前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【JAVA代码审计】从零开始的Mybatis框架SQL注入审计(下)

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

作者头像
一名白帽的成长史
发布2022-11-11 15:37:37
8840
发布2022-11-11 15:37:37
举报

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

结语

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-09-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一名白帽的成长史 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
代码审计
代码审计(Code Audit,CA)提供通过自动化分析工具和人工审查的组合审计方式,对程序源代码逐条进行检查、分析,发现其中的错误信息、安全隐患和规范性缺陷问题,以及由这些问题引发的安全漏洞,提供代码修订措施和建议。支持脚本类语言源码以及有内存控制类源码。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档