首页 > 编程语言 >Java 8 中使用反射进行命令执行的 5 个方法

Java 8 中使用反射进行命令执行的 5 个方法

时间:2023-04-20 10:14:15浏览次数:75  
标签:反射 Java String 命令 int start new byte class

今天在逛先知的时候看到了一篇文章:《探究使用反射进行除Runtime的命令执行方法》https://xz.aliyun.com/t/12446 其中大概讲了下命令执行的其他构造方式,但最后没有给出实例,所以我这里就简单研究了一下。

概述

在RASP等安全产品防护严密的现在,普通的寻找Runtime.getRuntime().exec(cmds)的调用已经成为了一件不现实的事情
同样的,在Java中盛行的反序列化漏洞中,如果将RCE的功能简单的通过Runtime.getRuntime().exec(cmds)这种结构来进行实现可能大概率也不能达到我们的目的,所以探索一下Runtime的底层实现,使用更加底层且复杂的调用来进行RCE功能的实现相对来说更加的可行

命令执行

文章接下里要用到反射技术,这里就不细讲了,可以看看其他的文章学习一下:https://www.yuque.com/sanqiushu-dsz56/efe3vx/hchx1p

命令执行 1:Runtime.getRuntime().exec()

// 命令执行 1 Runtime.getRuntime().exec()
Runtime.getRuntime().exec("open -a Calculator");

这个是大家所熟知的 java 中执行外部命令的方法。
首先我们跟踪Runtime执行命令的过程
image
exec() 函数在这里接收一个String类型的参数,调用 exec() 的另一个重载方法对参数进行处理,将其通过分隔符(默认为空格),将其封装成了数组对象
image
然后继续调用 exec() 重载方法,执行字符串数组类型的命令。
image
然后通过 ProcessBuilder()....start() 去执行命令了。那么我们自己也是可以通过反射去手动调用这个方法的,构造一下。

命令执行 2:ProcessBuilder().start()

// 命令执行 2 ProcessBuilder().start()
String[] cmd_array = new String[] {"open","-a","Calculator"};
Process process = new ProcessBuilder(cmd_array).start();

// 或者
new ProcessBuilder("calc.exe").start();  // 不能有参数

//当然还可以有其他的变体(通过反射):
Class pro = Class.forName("java.lang.ProcessBuilder");
((ProcessBuilder) pro.getConstructor(List.class).newInstance(Arrays.asList("calc.exe"))).start();

Class pro = Class.forName("java.lang.ProcessBuilder");
pro.getMethod("start").invoke(pro.getConstructor(List.class).newInstance(Arrays.asList("calc.exe")));

Class pro = Class.forName("java.lang.ProcessBuilder");
((ProcessBuilder) pro.getConstructor(String[].class).newInstance(new String[][]{{"calc.exe"}})).start();

Class pro = Class.forName("java.lang.ProcessBuilder");
pro.getMethod("start").invoke(pro.getConstructor(String[].class).newInstance(new String[][]{{"calc.exe"}}));

environment() 是设置环境遍历的函数,directory() 是设置执行目录的函数,然而我们都没传值,所以直接可以忽略。继续看 start() 函数
image

继续跟进,系统先进行了一番检查,然后新建了一个 SecurityManager 进行检测命令是否允许,但默认情况下 SecurityManager 是 null ,不进行检查。

image

然后就发现了系统调用的是 ProcessImpl.start() 进行命令执行。
image

那么到这里我们又可以自己构造了

命令执行 3 ProcessImpl.start()

// 命令执行 3 ProcessImpl.start()
String[] cmd_array = new String[] {"open","-a","Calculator"};
Method method_start = Class.forName("java.lang.ProcessImpl").getDeclaredMethod("start",String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
method_start.setAccessible(true);
method_start.invoke(null, cmd_array, null, null, null, false);  // 静态方法不需要传入实例

继续跟踪 ProcessImpl.start() 方法,在经过一番准备之后,系统来到了 UNIXProcess() 构造方法(我是 linux 系统)(Windows 系统是调用 create() 方法)
image

那么是不是意味着我们又可以构造了

命令执行 4 UNIXProcess()

// 命令执行 4 UNIXProcess()
String[] cmd_array = new String[] {"open","-a","Calculator"};
Class<?> clazz = Class.forName("java.lang.UNIXProcess");
Method method_toCString = clazz.getDeclaredMethod("toCString", String.class);
method_toCString.setAccessible(true);
Constructor<?> constructor = clazz.getDeclaredConstructor(byte[].class, byte[].class, int.class, byte[].class, int.class, byte[].class, int[].class, boolean.class);
constructor.setAccessible(true);
constructor.newInstance((byte[])method_toCString.invoke(null, cmd_array[0]),
        new byte[] {45, 97, 0, 67, 97, 108, 99, 117, 108, 97, 116, 111, 114, 0}
        , 2, null, 0, null, new int[]{-1,-1,-1}, false);

image

那么继续往下看 UNIXProcess() 构造函数里面的代码
image

这里就一句话,调用 forkAndExec() 函数,那么我们可以手动调用这个函数,开始构造

命令执行 5: forkAndExec()

// 命令执行 5: forkAndExec()
String[] cmd_array = new String[] {"ls"};
Class<?> clazz = Class.forName("java.lang.UNIXProcess");
Method method_toCString = clazz.getDeclaredMethod("toCString", String.class);
method_toCString.setAccessible(true);
Constructor<?> constructor = clazz.getDeclaredConstructor(byte[].class, byte[].class, int.class, byte[].class, int.class, byte[].class, int[].class, boolean.class);
// Constructor<?> constructor = clazz.getDeclaredConstructor(byte[].class, byte[].class,byte[].class,byte[].class,int[].class,boolean.class);
constructor.setAccessible(true);
Method method_forkAndExec = clazz.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class, byte[].class, int.class, byte[].class, int[].class, boolean.class);
method_forkAndExec.setAccessible(true);
int pid = (int)method_forkAndExec.invoke(constructor.newInstance((byte[])method_toCString.invoke(null, cmd_array[0]), new byte[] {} , 0, null, 0, null, new int[]{-1,-1,-1}, false),
        2, new byte[]{47, 76, 105, 98, 114, 97, 114, 121, 47, 74, 97, 118, 97, 47, 74, 97, 118, 97, 86, 105, 114, 116, 117, 97, 108, 77, 97, 99, 104, 105, 110, 101, 115, 47, 106, 100, 107, 49, 46, 56, 46, 48, 95, 49, 48, 49, 46, 106, 100, 107, 47, 67, 111, 110, 116, 101, 110, 116, 115, 47, 72, 111, 109, 101, 47, 106, 114, 101, 47, 108, 105, 98, 47, 106, 115, 112, 97, 119, 110, 104, 101, 108, 112, 101, 114, 0}, new byte[]{111, 112, 101, 110, 0}, new byte[]{45, 97, 0, 67, 97, 108, 99, 117, 108, 97, 116, 111, 114, 0},2, null,0, null, ew int[]{-1, -1, -1}, false);

不过这个有点牵强,因为需要先构造一个 UNIXProcess 的实例才行。
当然,我这传入的都是 byte[] ,只能用于验证,后续需要对照源码,将每个参数的生成给自动化才行。

Windows 的最后面的代码执行途径不太一样,但是同理构造即可。

标签:反射,Java,String,命令,int,start,new,byte,class
From: https://www.cnblogs.com/Nestar/p/17335689.html

相关文章

  • Linux的tar命令
    tar命令可以用来创建和解压各种类型的压缩包,以下是常见的几种类型:1..tar文件.tar文件是最常见的压缩包类型,它将多个文件和目录打包成一个文件,但不进行压缩。使用tar命令创建.tar文件时,可以使用以下命令:```tar-cvfarchive.tarfile1file2dir1```使用tar命令解压.tar文件时......
  • 如何查看 java程序是否运行
    Linux系统:1、ps-ef|grepjava  2、查看日志输出的pid 3、关闭进程kill34338或kill-934338 4、启动java程序 ./start.sh  windows系统:(命令行)1、打开命令窗口(以管理员身份运行)cmd2、查找所有运行的端口netstat-ano3、查看被占用端口对应的PID......
  • pip命令更改镜像源
    在使用`pip`安装Python包时,由于网络问题,可能会出现下载速度慢、甚至无法下载的情况。这时可以考虑更改`pip`的镜像源,以加快下载速度。以下是几种更改`pip`镜像源的方法:1.使用`pip`命令更改可以使用`pip`命令更改`pip`的镜像源。以清华大学的镜像源为例,使用以下命令更改:```pip......
  • linux ln命令
    功能介绍ln用于建立文件的链接,用法:硬链接ln原始链接文件链接文件软链接ln-s原始链接文件链接文件区别类别概念区别磁盘限制删除的影响硬链接建立和原文件完全一样的文件载入点磁盘必须相同删除链接或者原文件之一,仍然能够访问文件内容;两个文件全部删除,文......
  • Java架构师面试题
    Java架构师面试题以下是一些Java架构师面试题的示例:请谈谈你对Java多线程的理解,并介绍一下Java线程池的使用场景。请谈谈你在项目中遇到的最困难的问题是什么,以及你是如何解决的?请谈谈你对Spring框架的理解,并介绍一下Spring的核心模块和作用。请简述一下你对RESTfulAPI的认......
  • Java架构师在项目中的经验
    好的,以下是一个更详细的Java架构师在项目中的经验描述:项目名称:XXX系统项目描述:该项目是一个基于微服务架构的电商平台,涵盖了商品管理、订单管理、支付管理、会员管理等多个模块。作为Java架构师,负责系统的整体设计和开发工作。项目职责:负责制定系统的整体架构和技术方案,根据业......
  • Java架构师在项目中的经验描述示例
    以下是一个Java架构师在项目中的经验描述示例:项目名称:XXX系统项目描述:该项目是一个基于微服务架构的电商平台,涵盖了商品管理、订单管理、支付管理、会员管理等多个模块。作为Java架构师,负责系统的整体设计和开发工作。项目职责:设计并实现了整个系统的微服务架构,包括服务拆分、......
  • 资深Java架构师简历
    资深Java架构师简历以下是一个资深Java架构师的简历示例:姓名:李四联系方式:12345678901|[email protected]职业目标:资深Java架构师教育背景:本科学位,计算机科学与技术专业,清华大学,2005年毕业技能与经验:15年以上Java开发经验,熟悉Spring、MyBatis等主流框架精通数据库设计和优......
  • Java架构师简历
    以下是一个Java架构师的简历示例:姓名:张三联系方式:12345678900|[email protected]职业目标:Java架构师教育背景:本科学位,计算机科学与技术专业,清华大学,2010年毕业技能与经验:10年以上Java开发经验,熟悉Spring和Hibernate框架精通数据库设计和优化,能够使用Oracle、MySQL等主......
  • Java架构师项目经验历史最详细版本
    Java架构师项目经验历史最详细版本好的,以下是一个Java架构师在项目中的历史最详细版本的经验描述:项目名称:XXX系统项目描述:该项目是一个基于微服务架构的电商平台,涵盖了商品管理、订单管理、支付管理、会员管理等多个模块。作为Java架构师,负责系统的整体设计和开发工作。项目职......