SuperAPI AI Directory

webfuzzer-hotpatch

Security & auditing

View repository

Updated 10-16 01:27

About this skill

SKILL: Yakit Web Fuzzer Hot Patch (Hot Loading)

AI LOAD INSTRUCTION: This is the "module-level Web Fuzzer" topic in the three-tier hot loading system. Web Fuzzer hot loading acts on the packet-sending flow of a single Fuzzer Tab; the most typical uses are "intranet encryption countermeasures" (request encryption, response decryption, signature injection) and "automated decision-making" (retry, business failure determination). First read the Hook signatures and return value semantics, then look at examples/ examples named by Hook below, each of which can be yak <file> self-tested. When handling "various frontend encryption HACKs / letting users see plaintext", go directly to the combination recipe in Section 5 (examples/combo-*.yak); before writing any hot loading, be sure to read Section 6 "Concurrency and Global Variables" to avoid race crashes.

0. Related Routes

  • Main entry and three-tier system:yak
  • MITM hot loading (proxy-side hijacking/mirroring/storage):mitm-hotpatch
  • Global hot loading (executes before modules, shared by MITM/Fuzzer):global-hotpatch

1. Hook Signatures and Return Value Semantics

The hooks of Web Fuzzer hot loading differ critically from those of MITM: hijacking-type hooks submit modifications through the return value (not forward/drop).

Hook Signature Function Submission method
beforeRequest (https, originReq, req) -> req Rewrite before request goes out (encryption/signature/headers) return new request
afterRequest (https, originReq, req, originRsp, rsp) -> rsp Rewrite before response is displayed (decryption/formatting) return new response
retryHandler (https, retryCount, req, rsp, retry) Decide the next step when retry is triggered retry([newReq])
customFailureChecker (https, req, rsp, fail) Custom "failure" determination fail("原因")
mirrorHTTPFlow (req, rsp, params) -> params Extract parameters for {{params(name)}} return map
mockHTTPRequest (https, url, req, mockResponse) Use a local response when offline/no service mockResponse(rspStr)

Note: the Web Fuzzer's mirrorHTTPFlow(req, rsp, params) differs from MITM's mirrorHTTPFlow(isHttps, url, req, rsp, body) signature, do not mix them up.

2. Core Scenario One: Intranet Encryption Countermeasures

Modern Web applications often encrypt or sign requests/responses. By consolidating the encryption/decryption/signature logic into hot loading, you can directly fuzz the plaintext in the Fuzzer; packets are automatically encrypted when sent and automatically decrypted when displayed.

flowchart LR
    Plain["Fuzzer 里写明文请求"] -->|beforeRequest 加密/签名| Wire["真正出站的密文/带签名请求"]
    Wire --> Server["目标服务器"]
    Server -->|密文响应| After["afterRequest 解密"]
    After --> View["Fuzzer 里看到明文响应"]
Scenario Hook Example
timestamp+nonce+HMAC signature injection beforeRequest examples/before-request.yak
AES-CBC response decryption (Fuzzer sees plaintext) afterRequest examples/after-request.yak

The same applies to Chinese national cryptography (SM4-CBC / SM2 / SM3); just replace codec.AESCBC* with codec.SM4* / codec.Sm3 .

3. Core Scenario Two: Automated Decision-Making (Retry / Failure Determination)

The two functions introduced in article 043 automate and codify "manually analyzing the response and then deciding what to do":

Scenario Hook Example
405→POST / 429 backoff / 401 give up / 5xx retry retryHandler examples/retry-handler.yak
200 OK but body contains failure keywords → judged as failure customFailureChecker examples/custom-failure-checker.yak
Use a local response for integration testing when the target is not online mockHTTPRequest examples/mock-http-request.yak
  • retryHandler Must be used together with yakit Fuzzer's retry configuration (enable retry + specify failure status codes).
  • customFailureChecker Solves the brute-force filtering problem of "protocol-layer 200, business-layer failure".
  • mockHTTPRequest Lets payload rendering/retry/failure determination run through integration testing even without a real service.

4. Core scenario 3: fuzztag and correlated testing

Scenario Mechanism Example
Dynamically compute hash payload `{{yak(hash md5,admin)}}`
Multi-step request to extract token/csrf mirrorHTTPFlow returns a map → {{params(name)}} examples/mirror-http-flow.yak

An ordinary function defined in hot-loading f = func(param){ return [...] } can be used as the {{yak(f|参数)}} tag and called; each element of the returned array is a payload.

5. Frontend encryption countermeasure combination recipes (let users see plaintext)

A single hook solves a single-point problem; a real "frontend encryption HACK" often requires combining multiple hooks: encrypt/sign on the request side, decrypt on the response side, so that in the Fuzzer you always face plaintext. This is exactly the core approach for bypassing frontend encryption to perform brute-forcing/testing.

flowchart LR
    P["你写的明文 payload"] -->|beforeRequest / fuzztag 加密+签名| W["出站密文(过验签)"]
    W --> S["目标服务器"]
    S -->|密文响应| D["afterRequest / mirrorHTTPFlow 解密"]
    D --> V["Fuzzer 里看到明文, 一眼判断成功"]
Combination recipe Hooks involved Frontend protection being countered Example
AES-CBC write plaintext/see plaintext round trip beforeRequest + afterRequest CryptoJS AES-CBC static key examples/combo-aescbc-plaintext-roundtrip.yak
Encryption + HMAC signature verification dual protection beforeRequest + afterRequest AES encryption combined with signature to prevent tampering examples/combo-sign-and-encrypt.yak
RSA-OAEP + AES-GCM hybrid encryption {{yak(...)}} fuzztag + mirrorHTTPFlow Dynamic public key + asymmetric wrapping of symmetric key examples/combo-rsa-aesgcm-hybrid.yak

Key points:

  • Request sideUse beforeRequest(whole-packet encryption/signature) or {{yak(fn|...)}} fuzztag (encrypt only a certain field).
  • Response sideUse afterRequest(directly change the response to plaintext echo) or mirrorHTTPFlow(extract the decryption result as a variable, together with the sequence {{params(name)}}, and see success at a glance in the results table).
  • For dynamic keys/public keys use Web Fuzzer sequence: Step0 obtains the key → data extractor stores publicKey/privateKey → Step1 {{params(publicKey)}} reference (see the header comment of the hybrid encryption example).
  • Common algorithm APIs:codec.AESCBCEncryptWithPKCS7Padding / codec.AESGCMEncryptWithNonceSize12 / codec.RSAEncryptWithOAEP / codec.HmacSha256, for Chinese national cryptography replace with codec.Sm4* / codec.SM2*。

Why "plaintext password transmission" is worth testing: see article 183—frontend encryption only raises the threshold; the password is still essentially recoverable in communication; after decrypting the link into plaintext, conventional injection/brute-force/logic testing all become usable again.

6. Concurrency and global variables: use "read-only constants" as much as possible, otherwise it will crash

This is the crash pitfall most easily encountered in hot-loading. MITM / Web Fuzzer will concurrently call the same hook (the same script instance) for multiple requests. If your hook reads and writes the same top-level mutable global variable(for example, append to a global slice, assigning to a global map, accumulating a global counter), multiple goroutines writing at the same time will trigger data race, causing at best garbled results and at worst a direct panic crash.

Rules:

  • Put configuration/keys/IV/rule tables, etc. at the top level, but treat them as "read-only constants": assign once at load time, and inside the hook never modify. This usage is naturally concurrency-safe (all encryption combination examples in this section are written this way).
  • Do not write shared mutable globals inside hooks. When accumulation/collection is needed:
    • Prefer to keep state in function-local or pass it out via return values (mirrorHTTPFlow Return map,afterRequest return package).
    • If you really need to aggregate across requests, use a concurrency-safe container/lock:sync.Map、sync.NewMutex() lock, or yakit's db.* / risk.* persist to storage, rather than bare append global 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)))
}

This library's mirror-* single-hook examples use global slice/map accumulation for "self-test assertability"—that is the single-threaded command-line self-test demo style; when putting it into a real concurrent MITM/Fuzzer, please change it according to the rules above to read-only constants + return values/locking.

7. Standard style: hook function + YAK_MAIN self-test

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

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

if YAK_MAIN {
    runSelfTest()
}

YAK_MAIN Distinguish the runtime environment:

  • yak xxx.yak Command line:YAK_MAIN = true, run the self-test.
  • yakit Fuzzer hot-load window:YAK_MAIN = false, only register the hook.

Self-test mock method for each Hook

Hook Self-test verification method
beforeRequest / afterRequest Construct a mock request/response, assert the returned package content (you can perform reverse decryption on the encrypted result to verify the roundtrip)
retryHandler Custom retry callback(func(args...)), assert the call count and the new request content
customFailureChecker Custom fail callback, assert whether it is marked as failed
mirrorHTTPFlow Call directly, assert the extracted fields of the returned map
mockHTTPRequest Custom mockResponse callback, verify the target is triggered

8. Common codec / poc API quick reference

Purpose API
AES-CBC encrypt/decrypt codec.AESCBCEncrypt(key, data, iv)~ / codec.AESCBCDecrypt(key, cipher, iv)~
Base64 encode/decode codec.EncodeBase64(b) / codec.DecodeBase64(s)~
HMAC-SHA256 (returns bytes) codec.EncodeToHex(codec.HmacSha256(key, data))
Hash codec.Md5(s) / codec.Sha256(s) / codec.EncodeToHex(codec.Sm3(s))
Status code poc.GetStatusCodeFromResponse(rsp)
Change method poc.ReplaceHTTPPacketMethod(req, "POST")
Change body / header poc.ReplaceHTTPPacketBody / poc.ReplaceHTTPPacketHeader
Get request method/path poc.GetHTTPRequestMethod(req) / poc.GetHTTPRequestPath(req)

9. Verification

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)}}'

Each example should: complete within 10 seconds, all asserts pass, all logs in English, and show ... self test passed。

Reference sources

  • yak-project-public 043 (2025-07-25) Web Fuzzer new hot-load functions—retry control and error handling
  • yak-project-public 183 (2023-09-14) Advanced penetration testing techniques: analyzing signature verification and front-end encryption (part 1) (HMAC signature verification + AES-CBC, source of the combined recipe)
  • yak-project-public 177 (2023-10-11) Advanced penetration testing techniques (part 2): countering front-end dynamic keys and asymmetric encryption protection (RSA-OAEP + AES-GCM hybrid, source of the hybrid encryption combination)
  • yak-project-public 084 (2024-12-05) Advanced penetration testing techniques (part 3): vulnerability testing after front-end encryption
  • yak-project-public 270 (2022-07-28) Front-end AES-ECB encryption web security testing in practice
  • yak-project-public 282/285 (2022-05) Yakit Web Fuzzer ultimate capability enhancement: hot-load Fuzz
  • yak-project-public 167 (2023-11-17) Web Fuzzer advanced
  • Engine implementation:common/yak/script_engine_for_fuzz.go