mcpField
W
webfuzzer-hotpatch

webfuzzer-hotpatch

github.com/yaklangセキュリティ10123 回インストール15 週間前に更新
リポジトリ

webfuzzer-hotpatch について

webfuzzer-hotpatch は、Yakit Web Fuzzer の単一タブのリクエスト処理に使う YAK ホットパッチスキルです。リクエストとレスポンスの書き換え、再試行、失敗判定、パラメーター抽出、モック応答に加え、並行処理と自己テストの方法も説明します。

主な機能

  1. 016 種類の Web Fuzzer フックを説明
  2. 02リクエストの書き換えとレスポンスの復号
  3. 03再試行制御と独自の失敗判定
  4. 04パラメーター抽出と fuzztag 対応
  5. 05暗号化レシピと自己テスト方法
  6. 06並行状態の扱い方を説明

活用シーン

  1. 01Fuzzer で平文リクエストを暗号化・署名
  2. 02レスポンスを復号して平文を確認
  3. 03業務応答に応じた再試行や失敗判定
  4. 04抽出パラメーターを使った複数ステップのテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yaklang/yak-skills --skill webfuzzer-hotpatch

インストール後、Claude Code で/webfuzzer-hotpatchを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

examples/
after-request.yak
before-request.yak
combo-aescbc-plaintext-roundtrip.yak
combo-rsa-aesgcm-hybrid.yak
combo-sign-and-encrypt.yak
custom-failure-checker.yak
fuzztag-handle.yak
mirror-http-flow.yak
mock-http-request.yak
retry-handler.yak

詳細

SKILL:Yakit Web Fuzzer ホットリロード(Hot Patch)

AI LOAD INSTRUCTION:これは3層ホットリロード体系の「モジュールレベル Web Fuzzer」特集です。Web Fuzzer のホットリロードは、単一の Fuzzer タブにおけるリクエスト送信フローに作用します。代表的な用途は「イントラネットの暗号化への対処」(リクエストの暗号化、レスポンスの復号、署名の注入)と「自動化された判断」(再試行、ビジネス上の失敗判定)です。まず Hook のシグネチャと戻り値の意味を確認し、次に examples/ の Hook 名に対応したサンプルを見てください。どれも yak <file> でテストできます。「フロントエンドの暗号化に対するさまざまな HACK/ユーザーに平文を表示する」場合は、第5節の組み合わせレシピ(examples/combo-*.yak)を参照してください。ホットリロードを書く前に、競合によるクラッシュを避けるため、必ず第6節「並行処理とグローバル変数」を読んでください。

0. 関連ルート

  • 入口と3層体系:yak
  • MITM ホットリロード(プロキシ側での横取り/ミラーリング/登録):mitm-hotpatch
  • グローバルホットリロード(モジュールの実行前に動作し、MITM/Fuzzer で共有):global-hotpatch

1. Hook のシグネチャと戻り値の意味

Web Fuzzer のホットリロードの Hook は、MITM と重要な違いがあります。横取り系の処理では、戻り値で変更を適用します(forward/drop ではありません)。

Hookシグネチャ役割適用方法
beforeRequest(https, originReq, req) -> reqリクエスト送信前の書き換え(暗号化/署名/ヘッダー追加)新しいリクエストをreturn
afterRequest(https, originReq, req, originRsp, rsp) -> rspレスポンス表示前の書き換え(復号/整形)新しいレスポンスをreturn
retryHandler(https, retryCount, req, rsp, retry)再試行時に次の処理を決定retry([newReq])
customFailureChecker(https, req, rsp, fail)カスタムの「失敗」判定fail("原因")
mirrorHTTPFlow(req, rsp, params) -> params{{params(name)}} 用のパラメーターを抽出map をreturn
mockHTTPRequest(https, url, req, mockResponse)オフライン時/サービスがない場合にローカルレスポンスを使用mockResponse(rspStr)

注意:Web Fuzzer の mirrorHTTPFlow(req, rsp, params) と MITM の mirrorHTTPFlow(isHttps, url, req, rsp, body) はシグネチャが異なります。混同しないでください。

2. コアシナリオ1:イントラネットの暗号化への対処

最新の Web アプリケーションでは、リクエスト/レスポンスを暗号化または署名することがよくあります。暗号化・復号/署名のロジックをホットリロードに組み込めば、Fuzzer で平文を直接ファジングでき、送信時には自動的に暗号化され、表示時には自動的に復号されます。

flowchart LR
    Plain["Fuzzer 里写明文请求"] -->|beforeRequest 加密/签名| Wire["真正出站的密文/带签名请求"]
    Wire --> Server["目标服务器"]
    Server -->|密文响应| After["afterRequest 解密"]
    After --> View["Fuzzer 里看到明文响应"]
シナリオHookサンプル
timestamp+nonce+HMAC 署名の注入beforeRequestexamples/before-request.yak
AES-CBC レスポンスの復号(Fuzzer に平文を表示)afterRequestexamples/after-request.yak

国産暗号(SM4-CBC/SM2/SM3)も同様です。codec.AESCBC* を codec.SM4*/codec.Sm3 に置き換えてください。

3. コアシナリオ2:自動化された判断(再試行/失敗判定)

記事043で導入された2つの関数により、「レスポンスを手動で分析し、その後の処理を決める」作業を自動化し、コード化できます。

シナリオHookサンプル
405→POST/429 でバックオフ/401 で中止/5xx で再試行retryHandlerexamples/retry-handler.yak
200 OK でも、本文に失敗キーワードが含まれていれば失敗と判定customFailureCheckerexamples/custom-failure-checker.yak
対象が未稼働の場合にローカルレスポンスで連携テストmockHTTPRequestexamples/mock-http-request.yak
  • retryHandler は、yakit Fuzzer の再試行設定(再試行の有効化と、失敗ステータスコードの指定)と併用する必要があります。
  • customFailureChecker は、「プロトコル層では200、ビジネス層では失敗」というブルートフォースの結果を絞り込む難題を解決します。
  • mockHTTPRequest を使えば、実際のサービスがなくても、ペイロードのレンダリング/再試行/失敗判定を含む連携テストを実行できます。

4. コアシナリオ3:fuzztag と関連テスト

シナリオ仕組みサンプル
ハッシュペイロードを動的に計算`{{yak(hashmd5,admin)}}`
複数ステップのリクエストから token/csrf を抽出mirrorHTTPFlow が map を返す → {{params(name)}}examples/mirror-http-flow.yak

ホットリロードで定義した通常の関数 f = func(param){ return [...] } は、{{yak(f|参数)}} タグとして呼び出せます。返された配列の各要素が1つのペイロードになります。

5. 前端加密对抗组合配方(让用户看到明文)

单个 hook 解决单点问题,真实"前端加密 HACK"往往要 多个 hook 组合:发包侧加密/签名,回包侧解密,让你在 Fuzzer 里始终面对 明文。这正是绕过前端加密做爆破/测试的核心套路。

flowchart LR
    P["你写的明文 payload"] -->|beforeRequest / fuzztag 加密+签名| W["出站密文(过验签)"]
    W --> S["目标服务器"]
    S -->|密文响应| D["afterRequest / mirrorHTTPFlow 解密"]
    D --> V["Fuzzer 里看到明文, 一眼判断成功"]
组合配方涉及 hook对抗的前端防护示例
AES-CBC 写明文/看明文往返beforeRequest + afterRequestCryptoJS AES-CBC 静态密钥examples/combo-aescbc-plaintext-roundtrip.yak
加密 + HMAC 验签 双重防护beforeRequest + afterRequestAES 加密叠加签名防篡改examples/combo-sign-and-encrypt.yak
RSA-OAEP + AES-GCM 混合加密{{yak(...)}} fuzztag + mirrorHTTPFlow动态公钥 + 非对称包裹对称密钥examples/combo-rsa-aesgcm-hybrid.yak

要点:

  • 请求侧用 beforeRequest(整包加密/签名)或 {{yak(fn|...)}} fuzztag(只加密某个字段)。
  • 响应侧用 afterRequest(直接把响应改成明文回显)或 mirrorHTTPFlow(把解密结果提取成变量,配合序列 {{params(name)}},并在结果表里一眼看出成功)。
  • 动态密钥/公钥用 Web Fuzzer 序列:Step0 取密钥 → 数据提取器存 publicKey/privateKey → Step1 {{params(publicKey)}} 引用(见混合加密示例头注释)。
  • 常用算法 API:codec.AESCBCEncryptWithPKCS7Padding / codec.AESGCMEncryptWithNonceSize12 / codec.RSAEncryptWithOAEP / codec.HmacSha256,国密换成 codec.Sm4* / codec.SM2*。

关于"明文密码传输"为什么值得测:参见文章 183——前端加密只是抬高门槛,密码本质仍在通信中可还原;把链路解密成明文后,常规注入/爆破/逻辑测试就全部恢复可用。

6. 并发与全局变量:尽量用"只读常量",否则会崩

这是热加载最容易踩的崩溃坑。 MITM / Web Fuzzer 会 并发 地对多个请求调用同一个 hook(同一份脚本实例)。如果你的 hook 去 读写同一个顶层可变全局变量(例如 append 到全局 slice、给全局 map 赋值、累加全局计数器),多个 goroutine 同时写就会触发 data race,轻则结果错乱,重则直接 panic 崩溃。

规则:

  • 配置/密钥/IV/规则表等放顶层,但当作"只读常量":加载时赋值一次,hook 内 绝不修改。这种用法天然并发安全(本节所有加密组合示例都是这么写的)。
  • 不要在 hook 里写共享可变全局。需要累加/收集时:
    • 优先把状态留在 函数局部 或通过返回值传出(mirrorHTTPFlow 返回 map、afterRequest 返回包)。
    • 确实要跨请求聚合,用并发安全容器/锁:sync.Map、sync.NewMutex() 加锁,或 yakit 的 db.* / risk.* 落库,而不是裸 append 全局 slice。
// 反例(并发会崩): 多个请求同时 append 同一个全局 slice
RESULTS = []
mirrorHTTPFlow = func(req, rsp, params) { RESULTS = append(RESULTS, req); return {} }  // 危险!

// 正例: 顶层只放只读常量, 结果通过返回值带出
AES_KEY = codec.DecodeHex("3132...")~   // 只读常量, 不再修改
afterRequest = func(https, oreq, req, orsp, rsp) {
    return poc.ReplaceHTTPPacketBody(rsp, decrypt(AES_KEY, poc.GetHTTPPacketBody(rsp)))
}

本库 mirror-* 单 hook 示例为了"自测可断言"用了全局 slice/map 累加——那是 单线程命令行自测 的演示写法;放进真实并发的 MITM/Fuzzer 时,请按上面的规则改成只读常量 + 返回值/加锁。

7. 标准写法:hook 函数 + YAK_MAIN 自测

beforeRequest = func(https, originReq, req) {
    // 改写 req
    return req
}

func runSelfTest() {
    // 构造 mock 请求, 调用 hook, assert 返回值
}

if YAK_MAIN {
    runSelfTest()
}

YAK_MAIN 区分运行环境:

  • yak xxx.yak 命令行:YAK_MAIN = true,跑自测。
  • yakit Fuzzer 热加载窗口:YAK_MAIN = false,仅注册 hook。
各 Hook 的自测 mock 方式
Hook自测验证方式
beforeRequest / afterRequest构造 mock 请求/响应,断言返回包内容(可对加密结果做反向解密验证 roundtrip)
retryHandler自定义 retry callback(func(args...)),断言调用次数与新请求内容
customFailureChecker自定义 fail callback,断言是否被标记失败
mirrorHTTPFlow直接调用,断言返回 map 的提取字段
mockHTTPRequest自定义 mockResponse callback,验证目标触发

8. 常用 codec / poc API 速查

用途API
AES-CBC 加/解密codec.AESCBCEncrypt(key, data, iv)~ / codec.AESCBCDecrypt(key, cipher, iv)~
Base64 编/解码codec.EncodeBase64(b) / codec.DecodeBase64(s)~
HMAC-SHA256(返回字节)codec.EncodeToHex(codec.HmacSha256(key, data))
哈希codec.Md5(s) / codec.Sha256(s) / codec.EncodeToHex(codec.Sm3(s))
状态码poc.GetStatusCodeFromResponse(rsp)
改方法poc.ReplaceHTTPPacketMethod(req, "POST")
改 body / headerpoc.ReplaceHTTPPacketBody / poc.ReplaceHTTPPacketHeader
取请求 method/pathpoc.GetHTTPRequestMethod(req) / poc.GetHTTPRequestPath(req)

9. 验证

cd /Users/v1ll4n/Projects/yaklang
go run common/yak/cmd/yak.go skills/webfuzzer-hotpatch/examples/before-request.yak

# 与 Yakit gRPC 同款执行路径 (MutateHookCaller); 验证 {{yak(...)}} fuzztag:
go build -o /tmp/yak ./common/yak/cmd/yak.go
printf 'GET / HTTP/1.1\r\nHost: t.example.com\r\n\r\n' > /tmp/req.txt
/tmp/yak hotpatch-webfuzzer --script skills/webfuzzer-hotpatch/examples/fuzztag-handle.yak \
    --request /tmp/req.txt --fuzztag '{{yak(hash|md5,hello)}}'

每个示例应:10 秒内完成、assert 全过、log 全英文、出现 ... self test passed。

参考来源

  • yak-project-public 043 (2025-07-25) Web Fuzzer 新的热加载函数——重试控制与错误处理
  • yak-project-public 183 (2023-09-14) 渗透测试高级技巧 分析验签与前端加密(一)(HMAC 验签 + AES-CBC,组合配方来源)
  • yak-project-public 177 (2023-10-11) 渗透测试高级技巧(二) 对抗前端动态密钥与非对称加密防护(RSA-OAEP + AES-GCM 混合,混合加密组合来源)
  • yak-project-public 084 (2024-12-05) 渗透测试高级技巧(三) 被前端加密后的漏洞测试
  • yak-project-public 270 (2022-07-28) 前端 AES-ECB 加密 Web 安全测试实战
  • yak-project-public 282/285 (2022-05) Yakit Web Fuzzer 终极能力强化 热加载 Fuzz
  • yak-project-public 167 (2023-11-17) Web Fuzzer 进阶
  • 引擎实现:common/yak/script_engine_for_fuzz.go

コメント