从Java源码来看Native命令执行方法

在JAVA中盛行的反序列化漏洞中 , 如果将RCE的功能简单的通过Runtime.getRuntime().exec(cmds)这种结构来进行实现可能大概率也不能达到我们的目的 , 所以探索一下Runtime的底层实现 , 使用更加底层且复杂的调用来进行RCE功能的实现相对来说更加的可行概述在RASP等安全产品防护严密的现在 , 普通的寻找Runtime.getRuntime().exec(cmds)的调用已经成为了一件不现实的事情 。
同样的 , 在Java中盛行的反序列化漏洞中 , 如果将RCE的功能简单的通过Runtime.getRuntime().exec(cmds)这种结构来进行实现可能大概率也不能达到我们的目的 , 所以探索一下Runtime的底层实现 , 使用更加底层且复杂的调用来进行RCE功能的实现相对来说更加的可行 。
这里主要是对Java中多种命令执行的方式跟踪源码进行原理分析、构造利用代码、集成自研工具 。
前置首先需要对Java中的反射机制有着基本的掌握
通过反射的方式 , 我们可以获取到任何类的构造方法 , 类方法 , 成员变量 , 且能够获取对应类对象进行对应方法的调用等等目的

  • 获取Class类对象对于类对象的获取 , 主要可以通过Class.forName / loadClass的方式来获取 , 值得注意的是 , 在调用Class.forName进行类的加载的时候 , 将会调用static方法
Class.forName("java.lang.Runtime")
  • 1.

从Java源码来看Native命令执行方法

文章插图
  • 获取对应类的构造方法对于获取类的构造方法 , 主要可以通过getConstructor或者getDeclaredConstructor这两种方法来进行实现

从Java源码来看Native命令执行方法

文章插图
两者的区别主要是前者不能够反射获取private修饰的构造方法 , 而后者能够获取 。
所以通常使用后者进行构造函数的获取 , 传入的参数就是对应构造方法的参数类 。
clazz.getDeclaredConstructor(type.class)clazz.getConstructor(type.class)
  • 1.
  • 2.
  • 反射获取成员变量和构造方法类似的 , 存在有getField和getDeclaredField两个不同的获取方法 , 区别和构造函数类似 。
clazz.getField(name)clazz.getDeclaredField(name)
  • 1.
  • 2.
  1. 反射获取类方法同样具有getMethod和getDeclaredMethod两种 。
  2. ...............
一个普通的命令执行是
Runtime.getRuntime().exec("calc");
  • 1.
如果使用反射机制可以是
Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(runtime, "calc");
  • 1.
或者是其他的一些使用反射机制的变形 。
command跟踪Runtime首先我们跟踪Runtime执行命令的过程 。
从Java源码来看Native命令执行方法

文章插图
在这里接收一个String类型的参数 , 调用exec的另一个重在方法对参数进行处理 , 将其通过分隔符 , 将其封装成了数组对象(这里就是一个字符串) 。
从Java源码来看Native命令执行方法

文章插图
之后通过参数是String[]类型的另一个重载方法 , 通过调用ProcessBuilder类的方法进行执行 。
从Java源码来看Native命令执行方法

文章插图
在ProcessBuilder#start方法中 , 将命令传递给了ProcessImpl#start方法进行处理
从Java源码来看Native命令执行方法

文章插图
windows在windows中主要是在ProcessImpl的构造方法中调用了create方法 。
从Java源码来看Native命令执行方法

文章插图
。这个create方法是通过win32的方式创建了一个进程 。
从Java源码来看Native命令执行方法


推荐阅读