Vulnerability Analysis: Ghost Bits WAF Bypass Principle and Codec/Fuzz Plugin Implementation
Ghost Bits is a WAF bypass technique that has drawn heavy attention in the security community lately; Black Hat-related talks and multiple CVEs (such as CVE-2025-41242) all touch on this technique. In real penetration testing, Ghost Bits encoding itself is not hard — a few lines of script will do. But every time the workflow is "open the editor → modify code → run the script → copy the result → paste it into the tool," the sheer number of steps easily breaks your train of thought. To address this we wrote a Yak Codec plugin: select a payload, right-click, and the encoding result is emitted directly, eliminating the hassle of switching back and forth between windows.
Beyond encoding, batch probing whether a target is affected by Ghost Bits is also a repetitive activity. For this scenario we additionally wrote a Yak Fuzz plugin, with built-in presets for common cases such as CVE-2025-41242, Jackson, and fastjson — one run quickly tells you whether the target carries truncation risk.
Building on a walkthrough of the core principles, this article introduces the design rationale and usage of these two plugins separately: Codec handles "one-click encoding" and Fuzz handles "batch probing." The goal is to cut repetitive labor and boost efficiency when detecting this class of vulnerabilities.
If you are also tired of manually copying and pasting Unicode characters, or you want to quickly validate in bulk whether a batch of targets is affected by Ghost Bits, this article is for you. These plugins are currently available in the Yakit plugin store.
These plugins can be downloaded from the online store:
1. The Ghost Bits Vulnerability Principle
Ghost Bits is a WAF bypass technique that exploits Java's character truncation behavior. Its core principle: when Java processes Unicode characters, certain methods silently discard the high 8 bits and keep only the low 8 bits.
For example, methods such as String.getBytes(), ByteArrayOutputStream.write(ch), and DataOutputStream.writeBytes() all essentially perform the following operation:
截断结果 = unicodeChar & 0xFF
This means that as long as you craft a Unicode character whose low 8 bits equal the target ASCII value, it will "impersonate" that ASCII character on the server side:
阮 = U+962E → 0x962E & 0xFF = 0x2E = .
严 = U+4E25 → 0x4E25 & 0xFF = 0x25 = %
灵 = U+7075 → 0x7075 & 0xFF = 0x75 = u
An attacker exploits this by encoding sensitive strings the WAF can recognize (such as ../, union select) into "harmless" Chinese Unicode, thereby bypassing detection.
Taking CVE-2025-41242 as an example
In Spring Framework CVE-2025-41242, the attack chain is as follows:
-
WAF lets it through: The WAF sees Unicode characters such as
阮严灵丰丰甲来; finding no sensitive keywords, it lets the request pass directly. -
Spring defense layer:
ResourceHttpRequestHandler#getResourcecallsisInvalidPath(path)to check for the literal../; since the path contains no../, it is deemed safe. -
Truncation occurs: Inside
StringUtils.uriDecode(),baos.write(ch)discards the high 8 bits:阮(U+962E) →.(0x2E). -
Path folding: The Jetty/Servlet container decodes
%u002eto., and ultimately.%u002e→.., forming a directory traversal.
2. Which Step in the Exploitation Flow Is Best Suited for Tooling
The complete exploitation flow of a Ghost Bits vulnerability includes:
The steps best suited for tooling
Across the entire flow, the parts genuinely worth turning into plugins are encoding and verification. Finding the truncation point can also be assisted by a Fuzzer for batch probing, but it depends far more on an understanding of the target's architecture; constructing the payload and sending the test itself is not complicated. What truly eats time is looking up and converting each ASCII character one by one into its Unicode replacement, and — after encoding is done — verifying that the truncation result actually restores the original ASCII. These two steps are highly repetitive and error-prone, making them the best candidates for tooling. Our Codec plugin solves the "one-click encoding" problem, the Fuzzer plugin solves the "batch probing of truncation points" problem, and the verification script ensures the encoding result is correct.
3. The Ghost Bits Encoding Plugin
Based on the pain points above, we wrote a Yak Codec plugin that fully automates the Ghost Bits encoding process.
Tool principle
The plugin ships with two Unicode candidate pools:
Candidate pool design:
By default it uses the Chinese-first pool; the encoded result is more readable, making it easier to identify and debug in WebFuzzer.
Core code
// 保留空白和斜杠,其余 ASCII 全部编码
shouldEncode = func(asciiCode) {
if asciiCode < 0 || asciiCode > 127 { return false }
if asciiCode in [9, 10, 13, 32] { return false } // 空白
if asciiCode == 47 { return false } // /
return true
}
// 从中文优先池随机选 highByte
pickGhostChar = func(asciiCode, fixedHighByte) {
selectedHighByte = fixedHighByte
if selectedHighByte <= 0 || selectedHighByte > 255 {
selectedHighByte = chinesePreferredHighBytes[randn(0, len(candidatePool))]
}
return chr(selectedHighByte*256 + asciiCode)
}
Lab in action: vulhub/CVE-2025-41242
Using the vulhub spring/CVE-2025-41242 vulnerability lab as an example, we demonstrate the actual usage of the Codec plugin.
Lab environment
docker-compose 启动后,目标地址:http://127.0.0.1:8080漏洞点:Spring 的 StringUtils.uriDecode() 在特定路径下会丢弃 Unicode 高 8 位
Constructing the payload
Exploiting this vulnerability requires replacing the ASCII characters in the path with Ghost Bits-encoded Unicode. For example, the target payload is .%u002e (after Spring's internal decoding it becomes .., achieving directory traversal). In WebFuzzer, select .%u002e, right-click and run GhostBits Payload Codec, and the plugin directly outputs the corresponding Unicode replacement result:
输入: .%u002e
输出: 蔮蔥蕵蔰锰進蕥
The payload here is not "阮严灵丰丰甲来," because Ghost Bits encoding is inherently non-unique. As long as the condition "the low 8 bits after truncation equal the target ASCII" is satisfied, any Unicode character can serve as the replacement.
Verifying the result
After sending, observe the response. If the truncation takes effect, the server discards the high 8 bits of the Unicode, and the path it actually processes becomes ../../etc/passwd, thereby reading system file contents. If /etc/passwd signatures such as root:x:0:0: appear in the response, the vulnerability is confirmed.
4. The Ghost Bits Cast Fuzz Plugin
The Codec plugin solves the problem of "how to quickly encode a payload," but in practice you also need to answer another question: does the target have a Ghost Bits vulnerability?
For this we wrote GhostBits Cast Fuzzer — an active scanner plugin with built-in preset payloads for multiple common scenarios; it sends them to the target in one click and automatically analyzes the responses.
Integrated scenarios
Quick verification flow
输入目标 URL → 选择场景 → 一键发送 → 自动分析响应
5. The Ghost Bits Encoded String Verification Script
An encoded payload must verify that every Unicode character correctly truncates back to the original ASCII. We wrote a standalone Yak verification script:
// verify_ghostbits.yak
// 验证 Ghost Bits 编码结果:每个 Unicode 字符截断后是否等于原始 ASCII
truncateVerify = func(encoded, original) {
ok = true
encRunes = []
for _, r = range encoded { encRunes = append(encRunes, r) }
origBytes = []byte(original)
for i = 0; i < len(origBytes) && i < len(encRunes); i++ {
truncated = ord(encRunes[i]) & 0xFF
if truncated != int(origBytes[i]) {
println("FAIL at", i, "orig=", origBytes[i], "truncated=", truncated)
ok = false
}
}
return ok
}
// 测试示例
encoded = "阮严灵丰丰甲来"
original = ".%u002e"
if truncateVerify(encoded, original) {
println("验证通过:所有字符截断后还原正确")
}
The core logic of this script simply simulates the server's truncation behavior: ord(unicodeChar) & 0xFF == ord(originalChar).
6. Summary. The essence of the Ghost Bits vulnerability is a semantic gap between the encoding layer and the parsing layer: the WAF sees harmless Unicode at the encoding layer, while the server truncates and restores it into malicious ASCII at the parsing layer.
The three tools shared in this article — Codec, Fuzzer, and the verification script — we hope will reduce repetitive labor and improve testing efficiency when detecting this class of vulnerabilities. The Codec plugin compresses Ghost Bits encoding into a three-step operation: "select → right-click → output"; the truncation verification script automatically confirms the correctness of the encoding result, avoiding errors from manual visual comparison.
It is worth noting that the scenarios built into the Fuzzer plugin (CVE-2025-41242, Jackson, fastjson, etc.) are not universally applicable — they draw on the analysis of Ghost Bits exploitation paths from AsiaCCS 2026-related talks and papers, but every target's business context, framework version, and WAF rules are different. Readers can reference the payload-construction ideas and scenario-classification methodology within, and modify the test scripts according to their actual targets, rather than copying and running them verbatim.
This article was first published on the Yak Project official account, read the original.

