找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

431

积分

0

好友

55

主题
发表于 6 小时前 | 查看: 5| 回复: 0

我来帮你优化一下这篇文章的排版,让它更清晰易读:

小程序国密加密渗透测试:固定SM4密钥与自动化加解密实战

0x01 背景

在针对一个小程序进行安全测试时,发现其请求数据采用 SM2+SM4 国密算法进行加密,且 SM4 密钥为动态生成,这给常规的渗透测试带来了阻碍。

为实现对请求的自动化测试与分析,需要解决动态密钥的问题。本文将详细记录通过修改内存固定密钥,并实现自动化加解密的完整过程。


0x02 工具准备

主要工具

  • Cheat Engine (CE)

  • BurpSuite + Galaxy 插件

  • Reqable 等抓包工具

    • 用途:辅助验证加密结果

0x03 使用 CE 固定 SM4 密钥

核心思路

使用 CE 修改小程序进程内存,将动态生成 SM4 密钥的代码逻辑修改为返回固定值。

操作步骤

1. 附加进程

在 CE 中点击左上角电脑图标,选择并附加目标小程序的进程。

附加进程 选择进程


2. 定位密钥生成代码

通过搜索字符串 randomstr 来定位动态生成密钥的代码区域。

如何定位?

  • 方法一:强制开启开发者工具(F12)跟踪加密函数调用栈
  • 方法二:反编译小程序源码进行分析

搜索字符串 查看内存区域 定位代码


3. 分析并修改代码

复制出相关代码片段进行分析,发现关键行:

this.sm4Key = this.randomStr(32);

进一步查看 randomStr 函数的实现,发现其核心逻辑为:

t += "0123456789qwertyuiopasdfghjklzxcvbnm"[Math.floor(33*Math.random()+0)];

修改策略:

该行代码通过 Math.random() 生成随机索引。为了固定输出,只需将 33*Math.random()+0 中的 + 号修改为 * 号:

  • 修改前:33*Math.random()+0
  • 修改后:33*Math.random()*0

结果恒为 0,从而每次都取字符串的第一个字符 '0'


4. 执行内存修改
  1. 在 CE 中右键该代码行,选择 "Browse this memory region"
  2. 在内存查看窗口中,找到对应字节
  3. 将加法操作码修改为乘法操作码(通常将 2B (+) 修改为 2A (*)
  4. 应用修改

浏览内存 查找字节 修改字节 应用修改


5. 验证修改效果

重新进入小程序触发加密(或刷新页面)。此时,每次调用 randomStr(32) 都将返回由 32 个 '0' 字符组成的固定字符串。

通过抓包可以发现,相同请求的加密密文不再变化

重新进入 抓包验证

⚠️ 重要提示:这里的密钥是字符 '0',其十六进制表示为 \x30,而非 \x00。实际密钥为 \x30\x30\x30...(共 32 字节)。


0x04 实现 BurpSuite 自动化加解密

固定密钥后,即可利用 BurpSuite 插件实现测试流量的自动加解密,提升渗透测试效率。

使用 Galaxy 插件

1. 环境准备

在 Burp 的 Extender 中安装 Galaxy 插件。

安装插件


2. 编写加解密脚本

在 Galaxy 中创建新的 Script Module,编写 Python 脚本。

脚本核心:四个 Hook 函数

函数名 作用
hook_request_to_burp 将客户端发来的加密请求解密为明文,便于在 Burp 中查看和修改
hook_request_to_server 将 Burp 中修改后的明文重新加密,再发送给服务器
hook_response_to_burp 处理服务器响应(本例中服务器返回明文,故无需处理)
hook_response_to_client 处理返回给客户端的响应(本例中无需处理)

3. 脚本核心逻辑

脚本需包含 SM4 的 ECB 模式加解密实现,并与前面固定的密钥(32 个 '0')保持一致。

关键点: 正确处理 Java 与 Python 之间的字节数组转换(有符号/无符号问题)。

自动化效果


4. 示例脚本概要
from org.m2sec.core.utils import CryptoUtil, JsonUtil
from java.lang import String
from jarray import array

# 算法配置
ALGORITHM = "SM4/ECB/PKCS5Padding"
secret = [0x30] * 32  # 32个'0'字符的ASCII码
requestJsonKey = "encryptJson"

def hook_request_to_burp(request):
    """解密请求:从加密数据还原为明文"""
    # 从请求JSON中提取加密的十六进制数据
    encrypted_hex = extract_data(request.getContent())
    if encrypted_hex:
        # 解密
        decrypted_bytes = sm4_decrypt(encrypted_hex)
        # 将解密后的明文替换原请求体
        request.setContent(decrypted_bytes)
    return request

def hook_request_to_server(request):
    """加密请求:将明文加密后发送给服务器"""
    # 获取Burp中编辑后的明文
    plain_data = request.getContent()
    # 加密
    encrypted_bytes = sm4_encrypt(plain_data)
    # 包装成JSON格式并替换请求体
    new_body = package_to_json(encrypted_bytes)
    request.setContent(new_body)
    return request

def sm4_decrypt(encrypted_bytes_list):
    """SM4解密函数"""
    # 将Python字节列表转换为Java有符号字节数组
    java_bytes = array(to_signed_java_bytes(encrypted_bytes_list), 'b')
    java_secret = array(to_signed_java_bytes(secret), 'b')
    # 调用Galaxy的CryptoUtil解密
    decrypted_java_bytes = CryptoUtil.sm4Decrypt(ALGORITHM, java_bytes, java_secret, {})
    # 将Java字节数组转回Python字节
    return to_python_bytes(decrypted_java_bytes)

def sm4_encrypt(plain_bytes):
    """SM4加密函数(与解密对称)"""
    # 实现逻辑与解密类似
    pass

# ... 其他辅助函数(数据提取、包装、字节转换等)

📝 注意事项:脚本需根据实际小程序的请求/响应格式(JSON 字段名、加密数据编码方式等)进行调整。核心是确保加解密算法、模式、填充方式以及密钥与小程序客户端一致。


0x05 总结

通过以上步骤,我们成功实现了:

✅ 使用 Cheat Engine 固定动态生成的 SM4 密钥 ✅ 通过 BurpSuite + Galaxy 插件实现自动化加解密 ✅ 建立完整的渗透测试通道

现在可以高效地对小程序后端接口进行安全测试与漏洞挖掘了。


相关资源


关键技术点回顾:

  • 内存修改技术(CE)
  • 国密算法(SM2/SM4)
  • BurpSuite 插件开发
  • Java-Python 互操作



上一篇:RL训练框架选型实战指南:智能体多轮与异步强化学习考量
下一篇:Let's Encrypt 通配符SSL证书实战:从生成到部署与自动续期指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-6 23:56 , Processed in 0.113187 second(s), 37 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 CloudStack.

快速回复 返回顶部 返回列表