0x01 前言
这周看到了某公众号发的springboot+vue实现的一个后台管理系统。阅读量还挺高的,就下了一下源码翻一翻,发现里边漏洞还挺多的。尤其是SQL方面,作者虽然做了过滤但还是因为配置不当的导致SQL注入。
后边经过作者的同意,然后把本次代码审计的思路放出来和大家分享一下
0x02 SQL注入
mybatis-plus对绝大部分场景进行了预编译处理。但是类似动态表名、orderby这种需要拼接的场景配置不当还是会存在漏洞。本次就是记录一下在代码审计中遇到的一个奇怪的SQL注入,在对请求参数进行黑名单过滤十分严格的情况,代码逻辑不当导致SQL注入!
分页SQL注入分析
翻了一下pom.xml文件,发现该项目持久层使用的是Mybatis-puls框架!
我对mybatis-plus的理解就是封装了一些sql以减少代码量,其对绝大部分场景进行了预编译处理。但是类似动态表名、orderby这种需要拼接的场景配置不当还是会存在漏洞。
在翻工具类时发现该项目有对sql注入进行过滤
那就跟进去看看在哪里做了过滤,只在com.utils.Query#Query
中有4处调用
跟进com.utils.Query#Query
看看,发现该类具有两个重载的构造方法,接收的参数类型不同
- JQPageInfo:封装了分页参数的实体类
- Map<String, Object> params:集合类型的params参数
但其对sql注入的防御逻辑都相同,都是对sidx和order参数进行处理后,然后封装成Page对象
源码:
1 | package com.utils; |
很完美的防御、不过这里就有点奇怪了,翻了几个sql的xml文件,发现都没有使用到这个page
对象
那我们从页面中随便找一个带分页的查询请求分析一下,例如:
1 | /jixiaokaohe/page?page=1&limit=10&sort=id |
跟进到他的controller->com.controller.JixiaokaoheController#page
调用的是jixiaokaoheService.queryPage
来进行的查询,使用MPUtil.sort
来自定义了一个wrapper
继续跟进到com.service.impl.JixiaokaoheServiceImpl#queryPage
可以看到这块使用了sql过滤的com.utils.Query#Query(java.util.Map<java.lang.String,java.lang.Object>)
继续向下跟
可以看到最终sql的实现使用的是开头说的自定义的wrapper
来构建查询条件。
跟进去看看->com.utils.MPUtil#sort
发现在这块对sort
参数直接使用了拼接而且没有进行过滤
打个poc试一下吧!
1 | page=1&limit=10&sort=id+and+updatexml(1,concat(0x7e,database()),0)# |
其他SQL注入分析
从Mybatis-puls的简介中可以看到:Mybatis-Plus是一个Mybatis(opens new window)的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发。因此mybatis中实现sql的方式在Mybatis-puls同样适用。
#{}
预处理、${}
拼接就不用多说了。直接实现sql的xml搜索${
可以发现多出使用拼接,那直接选择一个分析一下
一路向上跟进
com.service.impl.CommonServiceImpl#remindCount
最终跟到com.controller.CommonController#remindCount
,发现全程也无过滤
根据接口,构造,打个poc
1 | users union select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA |
SQL注入总结
在对动态表名、orderby这种需要拼接的场景下,在代码实现时一定要仔细!总体来说mybatispuls框架中SQL注入漏洞挖掘相较于mybatis中更为困难,需要我们更加有耐心!
0x03 任意用户密码重置
这是在无意间发现的一个功能,感觉是作者设计的一个功能。但我没太看懂作者的意图,重置密码的接口可以不进行权限认证就使用!
@IgnoreAuth
这个注解的作用是不进行权限认证,之后就是通过用户名来查询用户,然后修改用户的密码为123456
1 | GET /springboot57n6g/users/resetPass?username=admin HTTP/1.1 |
0x04 任意文件上传
分析
在com.controller.FileController#upload
中实现的文件上传功能,通过最后一个点来获取上传文件后缀,在结合时间生成心的文件名,但未对文件进行过滤。导致任意文件上传
0x05 任意文件下载
分析
在com.controller.FileController#download
中实现的文件下载功能,但是在94行文件路径是由拼接而得:静态目录/upload/filename
由于filename我们可控。并且也无过滤,导致目录穿越下载任意文件
0x06 总结
开发注重功能的同时也应该考虑到一些安全问题。就像重置密码那个问题,作者就没有思考到安全问题。