前言:日常项目任务薅洞实战,完成项目的同时提升一下日站的个人综合技能水平,看同事的漏洞报告遇到好多回若依,这次恰巧自己遇上了就来试试,搜搜能找到公开的poc,找不到分析文章,这次就扒拉源码本地搭建分析一波后台SQL注入的原理学习学习…
搭建环境
Github找一下若依4.6.1版本下载到本地,丢到IDEA里面,数据库文件导入,druid连接池配置文件中修改username和password
在application.yml文件中可更改服务默认端口,80端口被占用修改成其他空闲端口
完成数据库导入和配置文件一些必要信息的修改之后就可以运行整个项目了
漏洞分析
若依cms这个后台SQL注入貌似还没有公开漏洞细节,相关的分析内容很难找,Google到了其中一篇文章,获取到了关键的污点传播路径,整理如下:
RuoYi/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java:56,`role`为污点源
->RuoYi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java:37,污点源从`role`传递至`dataScope`
->RuoYi/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java:19,污点传入selectRoleList方法
->RuoYi/ruoyi-system/src/main/resources/mapper/system/SysRoleMappper.xml:36,'SQLI'类型触发注入
初看比较疑惑,顺着污点传播路径跟进不太明白poc是怎么整出来的,看到最后的xml文件也就是漏洞触发点也就清楚是怎么一回事了,先从污点源开始看
RuoYi/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
查看代码可以确定利用的漏洞路径为/system/role/list
,以POST的方式进行传参,可以看到初始的污点源为传递给TableDataInfo
的参数role
,跟进方法中调用的startPage()
方法
Ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
函数体打断点处,调用了TableSupport
类的buildPAgeRequest()
,如果pageNum
和PageSize
两个参数值不为空的话就会进行分页处理,调用的是pagehelper这个第三方插件,跟进buildPAgeRequest()
方法分析是如何进行赋值处理的
Ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java
实例化一个PageDomain
类,并通过ServletUtils
类从post传递的数据中获取对应的参数值,所以这几个参数值对漏洞利用并没有太大的影响,让其获取到的都为空就可以,第一部分poc
pageSize=&pageNum=&orderByColumn=&isAsc=
顺着污点传播链,跟进RuoYi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
文件
对dataScope
参数的一个拼接,并且进行了类型的转换,继续跟传播链,RuoYi/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java
注释已经写明此处根据分页查询角色数据,暂时不知道污点为何会传入selectRoleList()
方法,继续跟传播链
RuoYi/ruoyi-system/src/main/resources/mapper/system/SysRoleMappper.xml
可以看到这里是SQL查询语句,具体为什么这么写可以去自行百度一下,可以看到这里直接将${params.dataScope}
拼接入了SQL语句中,因此构造SQL注入语句就能够查询我们想要获取的数据,到这里也就不难理解为什么污点源会变成dataScope
,现在根据公开的poc来捋一捋整个链
role为初始污点源->调用RuoYi/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java#selectRoleList
方法->selectRoleList
方法调用RuoYi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
中的SysRole
类,该类会对dataScope
参数进行处理->dataScope
传入了RuoYi/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java#selectRoleList
方法->调用SQL查询时拼接dataScope
参数值进行了注入
可能并不是很准确,但是自己是这么理解的,有师傅理解更到位的话请多多指教
第二部分poc
roleName=&roleKey=&status=¶ms[beginTime]=¶ms[endTime]=&arams[dataScope]=and extractvalue(1,concat(0x7e,substring((select database()),1,32),0x7e))
将两部分poc结合也就得到了公开的poc,其实从poc入手,再直接看到最后的漏洞注入点能够更好理解poc为什么是这么构造的,其他参数的值皆为空默认就会为null,只传入dataScope这个参数值也是可以的
url/system/role/list
POST:pageSize=&pageNum=&orderByColumn=&isAsc=&roleName=&roleKey=&status=¶ms[beginTime]=¶ms[endTime]=¶ms[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))
本地复现
可以看到通过报错注入获取到了数据库的名字,后面更改SQL语句就能够获取到详细的数据库信息了
项目测试
打开给定的地址,看到这个界面就觉得很熟悉,之前审报告的就是就看到很多回,若依没跑了,站点应该只是更改了一些静态资源。
登录还是常规手段尝试弱口令,admin/admin123,直接进去了后台
burp抓个包,poc打过去,获取到了数据库名
得到如下部分数据库中的信息,详细的就不公开了
exam_banner,exam_collect,exam_p 表名
id,title,banner_img,is_put,cont #exam_banner表中的列名,不完整,长度限制,可以分长度读出
总结
整个到这里就差不多结束了,漏洞分析的可能不是特别到位,师傅们轻喷,只是想知道poc的参数是怎么构造的才去扒拉源码分析的,跟着poc去分析会更好理解,也就有了这篇文章。
- 本文作者: joker
- 本文来源: 奇安信攻防社区
- 原文链接: https://forum.butian.net/share/485
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!