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
结语
以上就是今天的全部内容了