核心差异:沙箱造船 vs 高速公路修车
Yakit 中的 Fuzzer 热加载 和 MITM 热补丁功能强大,但应用场景截然不同。为方便区分,我们以一张对比表开启认知:
对照表:Fuzzer 热加载 vs MITM 热补丁
维度 | Fuzzer 热加载 | MITM 热补丁 |
运行位置 | Fuzzer 发包前生成 payload | MITM 代理拦截实时流量 |
目标范围 | 手动指定的单一请求 | 未知,所有经过代理的浏览器流量 |
数据来源 | 手写字典或 Fuzztag | 任意请求体(如 JSON) |
Key 来源 | 硬编码或预设值 | 从请求体动态读取并解码 |
字段名 | 手写指定(如 username/password) | 未知,动态识别请求体中的字段 |
字段顺序 | 手写固定模板 | 遵循原始 JSON 键序 |
输出形式 | 返回字符串列表给 Fuzzer | 直接修改 HTTP 原始字节包并放行 |
一句话总结:Fuzzer 在沙箱里造船,MITM 在高速公路上修车。
- Fuzzer 热加载
:在已知的“可疑功能点”上,对指定的参数进行加密/签名等修改后发包测试。 - MITM 热补丁
:在代理层面,对所有经过的流量进行实时的加密/解密操作,让加密流量在 Yakit 的历史记录中“裸奔”。
效率提示:若你希望快速上手,让 AI 直接生成代码,可跳至文末的【收官之战】部分,获取统一的提示词模板。
第一部分:Fuzzer 热加载实战
靶场入门:HMAC-SHA256 签名
靶场地址:http://127.0.0.1:8787/crypto/sign/hmac/sha256
第一步:抓取正常流量输入 admin/admin 登录并抓包,观察正常的请求格式。
正常请求体示例:
POST /crypto/sign/hmac/sha256/verify HTTP/1.1Host: shan:8787...Content-Type: application/json...{"signature": "2cac409a88d14ac7ac3c34d8afa3dab473161ee3919681af781623c57e53cfa4","key": "31323334313233343132333431323334","username": "admin","password": "admin"}方法一:照葫芦画瓢(抄作业)
参考现有案例(如 CSDN博客),复制并理解热加载代码。
sign = func(p) { key = `1234123412341234` usernameDict = ["admin"] // 使用 Fuzztag 动态获取字典值 passwordDict = x"{{payload(pass_top25)}}" resultList = [] for username in usernameDict { for password in passwordDict { data=f`username=${username}&password=${password}` signature = codec.EncodeToHex(codec.HmacSha256(key, data)) m={ "signature": signature, "key": "31323334313233343132333431323334", "username": username, "password": password } res=json.dumps(m) resultList.Append(res) } } return resultList}代码解读:
固定用户名 admin,遍历密码字典。按照 username=${username}&password=${password}格式拼接待签名字符串。使用 HmacSha256计算签名并转为十六进制。组装完整 JSON 请求体。
使用方法:
由于该函数直接生成完整的 JSON 响应体,在 Fuzzer 中直接插入标签 {{yak(sign)}} 即可。
效果:成功爆破 admin/admin,且所有签名计算正确。
方法二:自学成才(让 AI 写)
当你需要处理更复杂的加密(如 JS 逆向出的算法)时,可以让 AI 代劳。
核心提示词模板:
/yakit-hotpatch-skill-master 给我生成一个Fuzzer热加载补丁自动替换"signature":"{{yak(sign)}}",flowid=3106,加密方式你调用浏览器去js逆向出来。操作流程:
- 定位目标
:分析数据包,找到像 "signature": "..."这类会动态变化的加密字段。 - AI 逆向
:让 AI 分析前端 JS,逆向出加密逻辑(如 HMAC、AES 等)。 - 生成补丁
:AI 基于逆向结果,生成能在 Fuzzer 中自动重算签名的热加载代码。
辅助工具:Skill 仓库与 MCP
开源 Skill 仓库:<https://github.com/XiangXtreme/yakit-hotpatch-skill>(源自公众号“湘安无事”)
关键步骤:启动 Yakit MCP(模型上下文协议)服务,确保热加载代码能通过环境检验。
成果示例:Fuzzer 热加载代码
以下是一个 beforeRequest 钩子示例,它在 Fuzzer 渲染完所有标签后,自动计算并替换签名字段。
/*Web Fuzzer Hotload: HMAC-SHA256 signature via beforeRequestFuzzer body:{"signature": "","key": "31323334313233343132333431323334","username": "admin","password": "{{x(pass_top25)}}"}beforeRequest runs AFTER all fuzztags (like {{x(...)}}) are rendered,so json.loads sees the fully expanded password.*/beforeRequest = func(req) { body = string(poc.GetHTTPPacketBody(req)) bodyObj = json.loads(body) key = `1234123412341234` data = f`username=${bodyObj["username"]}&password=${bodyObj["password"]}` bodyObj["signature"] = codec.EncodeToHex(codec.HmacSha256(key, data)) return []byte(poc.ReplaceHTTPPacketBody(req, []byte(json.dumps(bodyObj))))}第二部分:MITM 热补丁实战
靶场进阶:AES-ECB 加密参数
靶场地址:http://127.0.0.1:8787/crypto/js/lib/aes/ecb/sqli
这一关的参数被整体加密,需要 MITM 热补丁在流量经过时实时解密/加密。
用 AI 生成实时解密补丁
核心需求:让 AI 生成一个 MITM 热补丁,实现“自动放行看明文 + 历史记录存明文”。
提示词要点:向 AI 清晰说明目标 URL、加密算法(从 JS 逆向)、以及期望的 hijackSaveHTTPFlow 钩子行为。
关键步骤:
- 保存与生效
:生成的补丁代码必须先保存再启用,否则可能不生效。 - 调试与修复
:如果补丁无效,查看引擎 Console 的错误信息,并直接抛给 AI 进行修复。
成果示例:MITM 热补丁代码(AES-ECB)
以下是成功生成的 MITM 热补丁,实现了请求/响应的实时加解密及历史明文存储。
// AES-ECB MITM 热补丁 — 自动放行时 History 显示明文// 目标: http://shan:8787/crypto/js/lib/aes/ecb/handler/*// 算法: CryptoJS.AES.ECB + PKCS7Padding, key="1234123412341234"// 请求: {"data":"<base64>","key":"<hex>"}targetPath = "/crypto/js/lib/aes/ecb/handler/*"rawKey = "1234123412341234"aesKey = []byte(rawKey)isTarget = func(packet) { path = poc.GetHTTPRequestPathWithoutQuery(packet) if str.HasSuffix(targetPath, "/*") { prefix = targetPath[:len(targetPath)-1] return str.HasPrefix(path, prefix) } return path == targetPath}// AES-ECB 解密:入参 Base64 → 返回明文字符串decryptPayload = func(dataB64) { cipher, err = codec.DecodeBase64(dataB64) if err != nil || len(cipher) == 0 { return "", false } plain, err = codec.AESECBDecrypt(aesKey, cipher, nil) if err != nil || len(plain) == 0 { return "", false } return string(plain), true}// AES-ECB 加密:入参明文字符串 → 返回 Base64encryptPayload = func(plainText) { cipher, err = codec.AESECBEncrypt(aesKey, []byte(plainText), nil) if err != nil { return "" } return codec.EncodeBase64(cipher)}// 从 HTTP 包体提取 data 字段并解密,成功返回 (新包体, true)tryDecryptBody = func(bodyBytes) { if bodyBytes == nil || len(bodyBytes) == 0 { return "", false } bodyStr = str.TrimSpace(string(bodyBytes)) // 用 try/catch 保护,防止 json.loads 或字段取值 panic try { obj = json.loads(bodyStr) ... // 详细解密逻辑 return s, true } catch err { return "", false }}// ========== Hook 实现 ==========// hijackHTTPRequest: 编辑器显示明文hijackHTTPRequest = func(isHttps, url, req, forward, drop) { if !isTarget(req) { forward(req) return } body = poc.GetHTTPPacketBody(req) plain, ok = tryDecryptBody(body) if ok { req = poc.ReplaceHTTPPacketBody(req, plain) req = poc.FixHTTPRequest(req) } forward(req)}hijackRequest = hijackHTTPRequest// beforeRequest: 放行前回封加密beforeRequest = func(isHttps, oreq, req) { if !isTarget(req) { return []byte(req) } body = poc.GetHTTPPacketBody(req) bodyStr = str.TrimSpace(string(body)) // 如果 body 已含 data+key 字段,说明已经是包装体,不需要再加密 try { tmp = json.loads(bodyStr) if tmp != nil && str.Contains(sprintf("%v", typeof(tmp)), "map") { _, hasData = tmp["data"] _, hasKey = tmp["key"] if hasData && hasKey { return []byte(req) } } } catch e {} wrapped, ok = encryptBody(bodyStr) if ok { req = poc.ReplaceHTTPPacketBody(req, wrapped) req = poc.FixHTTPRequest(req) } return []byte(req)}// hijackSaveHTTPFlow: 入库前解密 → History 明文hijackSaveHTTPFlow = func(flow, modify, drop) { req, reqErr = str.Unquote(flow.Request) if reqErr != nil { req = flow.Request } if !isTarget(req) { modify(flow) return } body = poc.GetHTTPPacketBody(req) plain, ok = tryDecryptBody(body) if ok { req = poc.ReplaceHTTPPacketBody(req, plain) req = poc.FixHTTPRequest(req) flow.Request = str.Quote(req) } modify(flow)}// ... 其他 hook (hijackHTTPResponseEx, afterRequest)效果验证:
- 实时解密
:浏览器提交加密数据,Yakit 历史记录中看到的是明文。 - 明文操作
:可以在 History 中直接修改明文参数,MITM 会自动加密后转发。
组合拳:MITM 解密 + Fuzzer 加密
实战中,我们常需要:
- MITM 热补丁
:实时解密流量,看清明文,定位参数。 - Fuzzer 热加载
:对定位到的参数进行爆破或测试,自动加密后发包。
操作流程:
用上述方法生成并启用 MITM 解密补丁。 让 AI 生成配套的 Fuzzer 热加载代码,实现“明文编辑,自动加密”。
Fuzzer 热加载代码示例(AES-ECB加密):
/*AES-ECB Web Fuzzer 热加载用法: Fuzzer 请求里写明文 JSON,beforeRequest 自动加密输入: {"username":"admin","password":"123456"}发出: {"data":"<base64>","key":"3132..."}*/targetPath = "/crypto/js/lib/aes/ecb/handler/*"aesKey = []byte("1234123412341234")keyHex = "31323334313233343132333431323334"isTarget = func(packet) { path = poc.GetHTTPRequestPathWithoutQuery(packet) if str.HasSuffix(targetPath, "/*") { return str.HasPrefix(path, targetPath[:len(targetPath)-1]) } return path == targetPath}beforeRequest = func(isHttps, originReq, req) { if !isTarget(req) || isWrapped(req) { return []byte(req) } plain = str.TrimSpace(string(poc.GetHTTPPacketBody(req))) cipher, err = codec.AESECBEncrypt(aesKey, []byte(plain), nil) if err != nil { return []byte(req) } wrapped = json.dumps({"data": codec.EncodeBase64(cipher), "key": keyHex}) req = poc.ReplaceHTTPPacketBody(req, wrapped) req = poc.FixHTTPRequest(req) return []byte(req)}效果对比:
关闭热加载:发送明文,返回 500 错误。 开启热加载:自动加密,请求成功。
注意:Yakit 内置的 AI 测试功能(如 AI Fuzzer)目前可能不经过热加载模块,其发包是独立处理的。但 AI 有时能自行逆向并发现漏洞。
第三部分:收官之战——统一工作流
最终靶场:http://shan:8787/crypto/js/basic
为提升日常渗透效率,我们可以固化一套“让 AI 打工”的标准流程。
标准化提示词模板
第一步:安装并调用 /yakit-hotpatch-skill-master 技能。
第二步:在提示词中明确指定 flowid=XXX(你的流量包编号)。
第三步:使用以下万能提示词:
帮我写 Yakit MITM + Fuzzer 双热加载,流量加密了。加密算法你从浏览器 JS 逆向出来。我要自动放行看明文 + Fuzzer 改包爆破。成果验收
按照上述流程,一个新开的 AI 会话能在约 22 分钟内,产出可直接使用的 MITM 热补丁和 Fuzzer 热加载两个文件。
- MITM 实时解密测试成功
:历史记录中流量明文可见。 - Fuzzer 加密测试成功
:修改明文参数后,能自动加密并成功发包。
总结
通过本文的“靶场实操 → 案例分析 → AI 生成 → 标准流程”四步走,你应能掌握:
- 概念区分
:Fuzzer 热加载(针对单点) vs MITM 热补丁(针对全局流量)。 - 基础应用
:手工编写或复制修改简单的热加载代码。 - 高阶技巧
:利用 AI 逆向 JS 加密逻辑,自动生成复杂的热加载/热补丁代码。 - 效率法门
:固化提示词模板,让 AI 成为你的自动化代码生成器。
从此,面对前端加密不再是障碍,而是你渗透测试流程中一个可被标准化、自动化解决的环节。
夜雨聆风