$npx -y skills add Prohao42/aimy-skill --skill ghost-bits-cast-attackJava "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 smugglin
| 1 | # SKILL: Ghost Bits / Cast Attack — Java char to byte Narrowing Playbook |
| 2 | |
| 3 | > **AI LOAD INSTRUCTION**: This is a Java-only injection-enabling primitive, |
| 4 | > not a standalone vulnerability class. Whenever you see (1) a Java backend, |
| 5 | > (2) a WAF/IDS in front of it, and (3) any of {SQLi, deser RCE, file upload, |
| 6 | > path traversal, CRLF, request smuggling, SMTP injection} on the menu, ALWAYS |
| 7 | > try Ghost Bits variants of the payload before declaring it "blocked". The |
| 8 | > root cause is the silent loss of the high 8 bits when Java code narrows a |
| 9 | > 16-bit `char` to an 8-bit `byte` — the WAF sees a harmless Unicode |
| 10 | > character, the backend reconstructs the original ASCII attack byte. Base |
| 11 | > models almost never reach for this primitive. |
| 12 | > |
| 13 | > Source: Black Hat Asia 2026 talk *Cast Attack: A New Threat Posed by Ghost |
| 14 | > Bits in Java* by Xinyu Bai (@b1u3r), Zhihui Chen (@1ue), with contributor |
| 15 | > Zongzheng Zheng (@chun_springX). |
| 16 | |
| 17 | ## 0. RELATED ROUTING |
| 18 | |
| 19 | Ghost Bits is a *bypass* primitive that re-enables payloads from many other |
| 20 | playbooks. Pair it with whichever attack family applies: |
| 21 | |
| 22 | - [waf-bypass-techniques](../waf-bypass-techniques/SKILL.md) — when a Java |
| 23 | backend is suspected and WAF rules block the literal payload, this is the |
| 24 | first technique to try beyond classic encoding. |
| 25 | - [deserialization-insecure](../deserialization-insecure/SKILL.md) — for |
| 26 | Apache Commons BCEL ClassLoader and Fastjson `\u`/`\x` escape variants. |
| 27 | - [path-traversal-lfi](../path-traversal-lfi/SKILL.md) — Spring, Jetty, |
| 28 | Undertow, Vert.x URL decoding and `%2>` hex folding. |
| 29 | - [upload-insecure-files](../upload-insecure-files/SKILL.md) — Tomcat |
| 30 | `RFC2231Utility` `filename*` Webshell upload. |
| 31 | - [request-smuggling](../request-smuggling/SKILL.md) — Apache HttpClient |
| 32 | `<= 4.5.9` (HTTPCLIENT-1974/1978) header CRLF. |
| 33 | - [crlf-injection](../crlf-injection/SKILL.md) — Angus Mail / Jakarta Mail |
| 34 | SMTP injection and JDK HttpServer response splitting. |
| 35 | - [sqli-sql-injection](../sqli-sql-injection/SKILL.md) — Jackson `charToHex` |
| 36 | table-lookup truncation hides SQL keywords inside Unicode escapes. |
| 37 | |
| 38 | ### Advanced Reference |
| 39 | |
| 40 | Load [PAYLOAD_COOKBOOK.md](./PAYLOAD_COOKBOOK.md) when you need: |
| 41 | |
| 42 | - Full byte-to-Ghost-character lookup table covering every printable ASCII |
| 43 | byte 0x20–0x7E and the most useful control bytes (0x00, 0x09, 0x0A, 0x0D). |
| 44 | - Per-component affected version matrix and patch identifiers. |
| 45 | - Yaklang and Python one-liner payload generators (for `poc.HTTP`, |
| 46 | `codec.Encode`, raw socket). |
| 47 | - "Multi-view normalization engine" pseudocode for blue-team WAF detection. |
| 48 | |
| 49 | --- |
| 50 | |
| 51 | ## 1. ONE-MINUTE MENTAL MODEL |
| 52 | |
| 53 | Java's `char` is a **16-bit** unsigned integer (UTF-16 code unit). Almost |
| 54 | every wire protocol — HTTP/1.1, SMTP, Redis RESP, file paths, raw byte |
| 55 | streams — is **8-bit** byte oriented. The right way to bridge them is |
| 56 | explicit charset encoding: |
| 57 | |
| 58 | ``` |
| 59 | // Correct: explicit UTF-8, multi-byte chars become multi-byte sequences |
| 60 | byte[] bytes = str.getBytes(StandardCharsets.UTF_8); |
| 61 | out.write(bytes); |
| 62 | ``` |
| 63 | |
| 64 | Tons of legacy code, framework internals, and "fast path" optimizations skip |
| 65 | this and silently narrow: |
| 66 | |
| 67 | ``` |
| 68 | // Dangerous: high 8 bits silently dropped |
| 69 | byte b = (byte) ch; // 0x966A -> 0x6A |
| 70 | out.write(ch); // ByteArrayOutputStream.write(int) keeps low 8 bits |
| 71 | dos.writeBytes(str); // DataOutputStream loops char->byte cast |
| 72 | int v = ch & 0xFF; // explicit low-byte mask |
| 73 | ``` |
| 74 | |
| 75 | The lost high 8 bits are the **Ghost Bits**. They turn a multi-byte |
| 76 | Unicode character into a single attacker-chosen ASCII byte at the protocol |
| 77 | layer. |
| 78 | |
| 79 | ``` |
| 80 | View A (string layer: WAF / business validation / logs) |
| 81 | sees: 陪 阮 严 灵 瘍 瘊 ... "harmless Unicode garbage, allow" |
| 82 | | |
| 83 | v silent narrowing somewhere in the call stack |
| 84 | View B (byte layer: protocol / file system / parser / class loader) |
| 85 | sees: j . % u \r \n ... "executes the dangerous semantics" |
| 86 | |
| 87 | The boundary is breached at the exact moment "view A" and "view B" disagree. |
| 88 | ``` |
| 89 | |
| 90 | Mathematical formulation: to make View B see byte `T`, pick any |
| 91 | `k in 0x01..0xFF` and use: |
| 92 | |
| 93 | ``` |
| 94 | c = chr((k << 8) | T) |
| 95 | ``` |
| 96 | |
| 97 | That gives you **255 candidate Unicode characters per dangerous byte** — |
| 98 | plenty of room to dodge any signature-based blacklist. |
| 99 | |
| 100 | --- |
| 101 | |
| 102 | ## 2. THREE ROOT-CAUSE FAMILIES |
| 103 | |
| 104 | The Ghost Bits umbrella covers three distinct underlying bugs. Distinguishing |
| 105 | them tells you both *which payload shape* to send and *what to grep for |