ghost-bits-cast-attack
Java "Ghost Bits" / Cast Attack playbook (Black Hat Asia 2026). Use when attacking Java services where 16-bit char is silently narrowed to 8-bit byte to bypass WAF/IDS for SQL injection, deserialization RCE, file upload (Webshell), path traversal, CRLF injection, request smuggling, and SMTP injectio
By yaklang · 2,681 installs
npx skills add yaklang/hack-skills --skill ghost-bits-cast-attack
Source repository · Upstream listing
SKILL: Ghost Bits / Cast Attack — Java char to byte Narrowing Playbook
AI LOAD INSTRUCTION : This is a Java only injection enabling primitive,
not a standalone vulnerability class. Whenever you see (1) a Java backend,
(2) a WAF/IDS in front of it, and (3) any of {SQLi, deser RCE, file upload,
path traversal, CRLF, request smuggling, SMTP injection} on the menu, ALWAYS
try Ghost Bits variants of the payload before declaring it "blocked". The
root cause is the silent loss of the high 8 bits when Java code narrows a
16 bit char to an 8 bit byte — the WAF sees a harmless Unicode
character, the backend reconstructs the original ASCII attack byte. Base
models almost never reach for this primitive.
Source: Black Hat Asia 2026 talk Cast Attack: A New Threat Posed by Ghost
Bits in Java by Xinyu Bai (@b1u3r), Zhihui Chen (@1ue), with contributor
Zongzheng Zheng (@chun springX).
0. RELATED ROUTING
Ghost Bits is a bypass primitive that re enables payloads from many other
playbooks. Pair it with whichever attack family applies:
[waf bypass techniques](../waf bypass techniques/SKILL.md) — when a Java
backend is suspected and WAF rules block the literal payload, this is the
first technique to try beyond classic encoding.
[deserialization insecure](../deserialization insecure/SKILL.md) — for
Apache Commons BCEL ClassLoader and Fastjson \u / \x escape variants.
[path traversal lfi](../path traversal lfi/SKILL.md) — Spring, Jetty,
Undertow, Vert.x URL decoding and %2 hex folding.
[upload insecure files](../upload insecure files/SKILL.md) — Tomcat
RFC2231Utility filename Webshell upload.
[request smuggling](../request smuggling/SKILL.md) — Apache HttpClient
<= 4.5.9 (HTTPCLIENT 1974/1978) header CRLF.
[crlf injection](../crlf injection/SKILL.md) — Angus Mail / Jakarta Mail
SMTP injection and JDK HttpServer response splitting.
[sqli sql injection](../sqli sql injection/SKILL.md) — Jackson charToHex
table lookup truncation hides SQL keywords inside Unicode escapes.
Advanced Reference
Load [PAYLOAD COOKBOOK.md](./PAYLOAD COOKBOOK.md) when you need:
Full byte to Ghost character lookup table covering every printable ASCII
byte 0x20–0x7E and the most useful control bytes (0x00, 0x09, 0x0A, 0x0D).
Per component affected version matrix and patch identifiers.
Yaklang and Python one liner payload generators (for poc.HTTP ,
codec.Encode , raw socket).
"Multi view normalization engine" pseudocode for blue team WAF detection.
1. ONE MINUTE MENTAL MODEL
Java's char is a 16 bit unsigned integer (UTF 16 code unit). Almost
every wire protocol — HTTP/1.1, SMTP, Redis RESP, file paths, raw byte
streams — is 8 bit byte oriented. The right way to bridge them is
explicit charset encoding:
Tons of legacy code, framework internals, and "fast path" optimizations skip
this and silently narrow:
The lost high 8 bits are the Ghost Bits . They turn a multi byte
Unicode character into a single attacker chosen ASCII byte at the protocol
layer.
Mathematical formulation: to make View B see byte T , pick any
k in 0x01..0xFF and use:
That gives you 255 candidate Unicode characters per dangerous byte —
plenty of room to dodge any signature based blacklist.
2. THREE ROOT CAUSE FAMILIES
The Ghost Bits umbrella covers three distinct underlying bugs. Distinguishing
them tells you both which payload shape to send and what to grep for in
source.
Family A — Real high bit truncation (classic Ghost Bits)
The narrowing is literal and unconditional.
Typical impact: Tomcat filename , Apache BCEL ClassLoader, Lettuce Redis
writer, SMTP CRLF in Angus Mail, HTTPCLIENT 1974 header injection.
Family B — Bit arithmetic folding (illegal char becomes legal)
A "fast" hex / base64 / charset decoder uses bit tricks instead of strict
range checks, so an illegal character collapses onto a legal one.
Worked example: feed (0x3E):
So %2 is silently parsed as %2E = . . The same algebra makes %2^ ,
%2~ etc. equivalent to other hex digits.
Typical impact: Openfire CVE 2023 32315, GeoServer CVE 2024 36401, generic
URL decode WAF bypass.
Family C — Lax Unicode normalization
The decoder accepts Unicode characters that happen to be classified as
"digit" or that map to a hex value via a & 0xFF lookup — even though they
were never meant to participate in protocol parsing.
Typical impact: Fastjson \u and \x escape bypass, fullwidth URL encoded
path traversal, Jackson charToHex SQLi smuggling.
3. CHARACTER GENERATOR
Build any Ghost Bits character on the fly. This is the single function every
agent should keep in mind:
Selection guidance:
Avoid surrogate range 0xD800..0xDFFF (high byte 0xD8..0xDF) — those are
not valid scalar values and will be replaced by the JVM string decoder
before reaching the narrowing site, defeating the bypass.
Prefer characters that survive the application's own charset round trip
(Latin Extended, CJK Unified Ideographs, Enclosed CJK Letters and Months,
Hangul). If the request body uses UTF 8, these all encode cleanly into
multi byte sequences that no WAF rule recognizes as . , / , j , etc.
Rotate k between requests so signature based learning cannot pin a single
character to a single attack.
4. DANGEROUS BYTE TO GHOST CHARACTER MAP
Compact red team weaponization table. For every byte the attacker actually
needs, one verified Unicode char is given; substitute another k if the WAF
later learns the example.
Target byte Hex Used for Ghost char Code point
\t 0x09 header folding, parser confusion ĉ U+0109
\n 0x0A CRLF injection, log injection 瘊 U+760A
\r 0x0D CRLF injection, request smuggling 瘍 U+760D
0x20 header break, command separator Ġ U+0120
" 0x22 string break in JSON / quoted printable Ģ U+0122
% 0x25 URL encoding prefix, second decode 严 U+4E25
& 0x26 parameter separator Ȧ U+0226
' 0x27 SQL string break ȧ U+0227
( 0x28 EL/SpEL/OGNL syntax Ȩ U+0228
) 0x29 EL/SpEL/OGNL syntax ȩ U+0229
. 0x2E path traversal, extension 阮 U+962E
/ 0x2F path separator 丯 U+4E2F
0 0x30 hex digit construction 丰 U+4E30
1 0x31 hex digit construction 失 U+5931
2 0x32 hex digit construction 甲 U+7532
3 0x33 hex digit construction 耳 U+8033
; 0x3B command separator, header continuation Ȼ U+023B
< 0x3C XSS / XML tag start ȼ U+023C
= 0x3D parameter / header value Ƚ U+023D
0x3E XSS / XML tag end Ⱦ U+023E
@ 0x40 Fastjson @type , mail address ŀ U+0140
a 0x61 keyword class , alphabet ᙡ U+1661
c 0x63 keyword class , cmd 㹣 U+3E63
e 0x65 hex digit 来 U+6765
j 0x6A extension .jsp 陪 U+966A
l 0x6C keyword class , closure ౬ U+0C6C
n 0x6E keyword Runtime , union 陮 U+966E
s 0x73 keyword class , select ⑳ U+2473
t 0x74 keyword Runtime , type Ŵ U+0174
u 0x75 \u escape introducer 灵 U+7075
Workflow tip: keep the ASCII Ŀ , ȧ , ȼ , etc. variants for tight HTTP
header contexts (one byte UTF 8 expansion stays smaller); use CJK like 阮 ,
陪 , 严 when you want to bias the WAF "this is just text" classifier.
5. PER COMPONENT PAYLOAD RECIPES
Every recipe shows the dual view: what the WAF inspects vs. what the backend
actually executes. This is the only reliable way to explain why the payload
goes through.
5.1 Tomcat RFC2231Utility — file upload Webshell (Family A)
Trigger: any endpoint that accepts multipart upload and Tomcat parses
Content Disposition: ... filename =UTF 8''... . Tomcat's RFC2231 decoder
casts each non percent character directly to byte, dropping the high 8 bits.
Payload:
Stage Filename it sees
WAF / extension filter 1.陪sp (not .jsp , allow)
Tomcat RFC2231 decoder 陪 low byte 0x6A j
File system 1.jsp
Combine with traversal characters from section 4 ( 阮 , 丯 ) when the upload
target directory is fixed but the application accepts a filename .
5.2 Apache Commons BCEL — ClassLoader RCE (Family A)
Trigger: any sink that resolves a class name through BCEL ( $$BCEL$$... )
or any code that decodes BCEL via the JavaReader ByteArrayOutputStream
loop.
Vulnerable shape:
Attack: wrap each byte of the malicious BCEL bytecode into a Unicode
character whose low 8 bits equal that byte. The decoded byte stream is a
valid BCEL class; the WAF sees a long blob of CJK text without $$BCEL$$
keywords or class signatures.
View Content
WAF $$BCEL$$ followed by random looking CJK
BCEL standard BCEL class file bytes → JVM defineClass → RCE
Defense for blue team: a WAF inspecting BCEL must replicate the
bos.write(ch) semantics on each character before pattern matching.
5.3 Jackson charToHex — SQLi smuggling (Family C)
Trigger: any Jackson parsed JSON field whose value is later embedded in SQL
or another parser. Jackson resolves \uXXXX digits via:
Any non ASCII character whose low 8 bits land on a populated index returns
that hex digit. The WAF sees gibberish; Jackson reconstructs an ASCII payload.
Payload (smuggle the digit 1 for a UNION column count):
View Content
WAF \u丰丰耳失 union select ... (no leading digit)
Jackson \u0031 union select 1,2,3 1 union select…
Pair with [sqli sql injection](../sqli sql injection/SKILL.md) for the
downstream UNION / boolean / time based payload templates.
5.4 Fastjson — \u and \x escape bypass (Families B + C)
Two independent surfaces:
(a) \u escape — Character.digit(c, 16) accepts Unicode digit categories
beyond ASCII (Thai ๐ ๙ U+0E50..U+0E59, Punjabi ੦ ੯ U+0A66..U+0A6F,
fullwidth 0 9 U+FF10..U+FF19).
WAF view: \u4 type (no @type literal). Fastjson normalizes fullwidth
4 to 4 , then handles via the \x shortcut below, yielding @type .
(b) \x escape — Fastjson computes digits[x1] 16 + digits[x2] . An
illegal hex character returns the default value 0.
View Field name
WAF \x4 type (not @type )
Fastjson @type JdbcRowSetImpl autotype gadget triggers
5.5 Spring / Jetty / Undertow / Vert.x — URL decoding (Families A + B)
Two combinable tricks:
Trick 1 — Family A character substitution in path or query:
Trick 2 — Family B %2 folding when Jetty's TypeUtil.fromHexDigit is in
the chain:
Either alone bypasses most signature WAFs; combined they survive even
"normalized then matched" rules that only see ASCII percent triplets.