【JAVA代码审计】从零开始的Mybatis框架SQL注入审计(下)

2022-11-11 15:37:37 浏览数 (1)

Hello,各位小伙伴大家好~

这里是一名白帽的成长史~

上期讲完了SSM框架的搭建和路由分析:

【JAVA代码审计】从零开始的Mybatis框架SQL注入审计(上)

今天一起来看看Mybatis的注入挖掘吧~

Here we go ~

Part.1

SQL注入审计

审计思路

上期说到Mybatis的数据库执行操作都存在Mapper文件中,因此我们主要是在Mapper文件中进行漏洞挖掘。

Mapper文件基本格式如下:

以下图为例:

(1)id对应Dao接口中相应的方法名。

(2)parameterType为接收参数的类型。

(3)${}处则用于接收参数的值。

在Mybatis框架中,接收参数有两种方式:

(1)通过${param}方式 ,拼接的方式构造SQL。

(2)通过#{param}方式,会自动使用?作为占位符,通过预编译的方式构造SQL。

因此我们挖掘的重心就放在不会预编译的$符上了,需要满足2个基本条件:

(1)$符接收的参数需要为用户可控。

(2)$符接收的参数类型需要为字符型,如String型。

//假如为int等数字型,即使参数可控,但在尝试注入时,拼接上其他语句JAVA会语法报错。

当我们找到满足上述条件的注入点后,只需要一步一步往上追溯,看是否存在安全过滤,并最终确定访问URL即可。

下面一起来看几个案例吧。

sql注入点一:ArticleMapper.xml

全局搜索${value},我们可以找到以下Mapper文件:

//使用${}符,不会对参数进行预编译等处理。

先来看ArticleMapper.xml,删除文章和文章内容处均可能存在注入:

//更新文章内容使用#号,则不存在

deleteArticleByIds,deleteArticleContentByArticleIds方法可能存在问题。

根据ArticleMapper命名规则,这两个方法存在于接口ArticleDao中:

//找不到可以直接全局搜索deleteArticleByIds

接口对应的实现类ArticleDaoImpl:

往上追溯可发现ArticleServiceImpl类的deleteArticleByIds方法,调用了articleDao接口的这两个方法,且没做过滤:

ArticleServiceImpl类对应的接口为ArticleService:

//因此只要调用了ArticleService接口的deleteArticleByIds方法,就会触犯上面的sql语句。

全局搜索deleteArticleByIds,可以找到控制器AdminArticleController:

//delete方法会进行调用,对应的url为/delete

查看控制器AdminArticleController信息:

//确定该接口url为/admin/article/delete,注入点参数为articelId

全局搜/admin/article/delete,可以找到前端页面article-list.jsp:

//也可以不找前端了,因为已经知道url和参数名,直接发包就行了。

直接访问会跳到后台登陆界面,因该是做了会话校验:

通过admin/111111登陆:

再次访问:

http://localhost:8080/inxedu_war/admin/article/delete

会跳转至:

http://localhost:8080/inxedu_war/admin/article/showlist

//删除按钮就是我们要找的接口

点击删除,抓包,可以看到是我们想要的接口:

输入单引号报错:

原本的sql语句为:

构造延时注入语句进行验证,漏洞存在:

验证完毕~

SQL注入点二:CourseFavoritesMapper.xml

再来看一个漏洞点,思路和上面一致,首先打开CourseFavoritesMapper.xml,查找$符,可以发现deleteCourseFavoritesById方法可能存在注入:

该方法存在于CourseFavoritesDaoImpl类中:

CourseFavoritesDaoImpl类在CourseFavoritesServiceImpl类中进行注入,并未发现对参数ids做过滤处理:

继续追溯会发现deleteCourseFavoritesById方法被以下两个控制器调用:

查看AppUserController控制器,找到deleteCourseFavoritesById方法:

以上过程中未发现过滤,通过控制器确定路由为/webapp/deleteFaveorite,尝试访问:

传递参数id=1:

输入单引号,出现报错,因此可能存在注入:

原sql语句为:

通过时间盲注进行测试,漏洞存在:

验证完毕。

总结

综上所述:本次漏洞审计思路主要是先判断cms使用的框架,确定为mybatis后,检查Mapper.xml文件是否使用${}对sql语句引入变量即可。

如果使用${},再一步一步往上追溯,查看调用过程中是否存在过滤(当然还要判断一下是否存在filter全局过滤,这个cms没发现有全局过滤),直到追溯到控制器文件,即可确认该注入点的路由,最后构造报文进行测试即可。

全局搜索${,可以发现很多mapper中都存在:

大家可以尝试下自行挖掘。

Part.2

特殊场景分析

like模糊匹配

在SQL查询中,可以使用模糊匹配的方式进行查询:

但在这里使用#{ }会报错,因为#{ }不能直接放在单引号中:

改为使用${ },则可以正确执行:

但使用${}会存在SQL注入:

正确写法:

代码语言:javascript复制
select * from student where student_name like concat('%',#{name}, '%')

IN语句

首先来看看in语句的正确用法:

代码语言:javascript复制
select * from student where student_id in (1,2);
select * from student where student_id in ('1','2');

错误用法:

代码语言:javascript复制
select * from student where student_id in (‘1,2’);

而在定义id为String类型的情况下,传递参数id=1,2

#{}会为参数id添加单引号,查询语句会变成上面错误的情况!

使用${}即可正确查询,此时的查询语句为:

代码语言:javascript复制
select * from student where student_id in (1,2);

正确的写法,是使用?作为占位符:

代码语言:javascript复制
SELECT * FROM student_table WHERE id IN (?, ?, ?, ?);

或者借助foreach语句:

order by、group by语句

当使用#{ }时,会自动为排序字段加上单引号。

尝试传入参数student_tele:

排序失败,因此此时的查询语句为:

代码语言:javascript复制
select * from student order by 'student_tele';

//不能有单引号

使用${ }则可以正确排序:

代码语言:javascript复制
select * from student order by student_tele;

//但此时存在SQL注入漏洞,需要配合黑白名单等方式检查参数内容。

Part.3

结语

以上就是今天的全部内容了

0 人点赞