扫码领资料
获黑客教程
免费&进群
在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")
获取对应类的构造方法
对于获取类的构造方法,主要可以通过getConstructor
或getDeclaredConstructor
这两种方法来进行实现。
两者的区别主要是前者不能够反射获取private
修饰的构造方法,而后者能够获取,
所以通常使用后者进行构造函数的获取,传入的参数就是对应构造方法的参数类:
clazz.getDeclaredConstructor(type.class)
clazz.getConstructor(type.class)
反射获取成员变量
和构造方法类似的,存在有getField
和getDeclaredField
两个不同的获取方法,区别和构造函数类似
clazz.getField(name)
clazz.getDeclaredField(name)
反射获取类方法
同样具有getMethod
和getDeclaredMethod
两种。
……………
一个普通的命令执行是:
Runtime.getRuntime().exec("calc");
如果使用反射机制,可以是:
Class.forName("java.lang.Runtime").getMethod("exec",String.class).invoke(runtime, "calc");
或者是其他的一些使用反射机制的变形
首先我们跟踪Runtime执行命令的过程
在这里接收一个String
类型的参数,调用exec的另一个重在方法对参数进行处理,将其通过分隔符,将其封装成了数组对象(这里就是一个字符串)
之后通过参数是String[]
类型的另一个重载方法,通过调用ProcessBuilder
类的方法进行执行
在ProcessBuilder#start
方法中,将命令传递给了ProcessImpl#start
方法进行处理
在windows中主要是在ProcessImpl
的构造方法中调用了create
方法
这个create
方法是通过win32
的方式创建了一个进程
在linux下,在ProcessImpl#start
的调用中将会创建一个UNIXProcess
对象并返回
在UNIXProcess
类的构造方法中,调用了forkAndExec
这个native方法
创建了一个一个进程,并返回了对应进程的pid。
在上面的流程分析中,知道了在Runtime.getRuntime().exec()方法调用的下一层就是使用ProcessBuilder#start
方法。
如果hook掉了我们可以通过使用ProcessBuilder
类来进行命令执行的构造:
new ProcessBuilder("calc").start();
或者使用反射的思路构造:
//method_1
Class pro = Class.forName("java.lang.ProcessBuilder");
((ProcessBuilder) pro.getConstructor(List.class).newInstance(Arrays.asList("calc.exe"))).start();
//method_2
Class pro = Class.forName("java.lang.ProcessBuilder");
pro.getMethod("start").invoke(pro.getConstructor(List.class).newInstance(Arrays.asList("calc.exe")));
//method_3
Class pro = Class.forName("java.lang.ProcessBuilder");
((ProcessBuilder) pro.getConstructor(String[].class).newInstance(new String[][]{{"calc.exe"}})).start();
//method_4
Class pro = Class.forName("java.lang.ProcessBuilder");
pro.getMethod("start").invoke(pro.getConstructor(String[].class).newInstance(new String[][]{{"calc.exe"}}));
从上面的分析可以知道,在windows环境下的JDK:
ProcessImpl
类的构造方法将会调用create
方法执行native方法进行命令执行
所以我们只需要反射获取ProcessImpl
类的构造方法并实例化就会执行我们的恶意逻辑。
上面是针对windows的方式,针对linux,在前面的分析中知道主要是在其start
方法中调用了UNIXProcess
类的构造方法
执行forkAndExec
这个native方法进行命令执行
甚至于,我们知道最后主要是在create
方法(windows)、forkAndExec
方法(linux)中执行命令,我们同样可以通过反射这两个方法进行命令执行
原文地址:https://xz.aliyun.com/t/1244
声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权!
(hack视频资料及工具)
(部分展示)
往期推荐
看到这里了,点个“赞”、“再看”吧
文章引用微信公众号"白帽子左一",如有侵权,请联系管理员删除!