Désérialisation de données non fiables : déballage d'une vulnérabilité d'exécution de code à distance

Introduction
Dans le paysage évolutif des menaces en cybersécurité, peu de vulnérabilités présentent un risque aussi important que la désérialisation non sécurisée. Cette faille de sécurité critique figure régulièrement parmi les vecteurs d’attaque les plus dangereux, ce qui lui a valu sa place dans la liste OWASP des 10 vulnérabilités principales. Les incidents récents en 2025, notamment la vulnérabilité zero-day de désérialisation ViewState dans les produits Sitecore (CVE-2025-53690) et celle de Microsoft SharePoint (CVE-2025-30382), montrent que les attaques par désérialisation restent une menace persistante et en constante évolution.
Les vulnérabilités de désérialisation peuvent entraîner une exécution de code à distance lorsqu’elles sont exploitées, permettant potentiellement aux attaquants de prendre le contrôle complet des systèmes affectés. Comprendre leur fonctionnement, leurs risques et les stratégies de prévention est essentiel pour les développeurs, les professionnels de la sécurité et les organisations souhaitant protéger leurs actifs numériques.
Qu’est-ce que la sérialisation et la désérialisation ?
Avant d’aborder la vulnérabilité elle-même, il est crucial de comprendre les concepts fondamentaux de la sérialisation et de la désérialisation.
Sérialisation est le processus de conversion d’un objet ou d’une structure de données en un format pouvant être stocké ou transmis. Cela peut impliquer la conversion d’objets en JSON, XML, formats binaires ou autres représentations structurées. La sérialisation permet aux applications de sauvegarder l’état des objets dans des fichiers, des bases de données ou de les envoyer à travers des réseaux.
Désérialisation est le processus inverse — reconstruire des objets à partir de leur forme sérialisée. Lors de la désérialisation, l’application lit les données sérialisées et recrée la structure d’objet originale en mémoire, avec ses propriétés, méthodes et son état.
Bien que ces processus soient fondamentaux au développement moderne d’applications, ils deviennent dangereux lorsque des données non fiables entrent en jeu.
L’anatomie de la désérialisation non sécurisée
La désérialisation peut être risquée car elle peut ouvrir les applications à des attaques telles que l’exécution de code à distance (RCE) si les données à désérialiser proviennent d’une source non fiable. La vulnérabilité survient lorsque les applications désérialisent des données provenant de sources qu’elles ne peuvent pas faire confiance, sans validation ou contrôles de sécurité appropriés.
Pourquoi la désérialisation est intrinsèquement risquée
Le risque fondamental réside dans le processus de désérialisation lui-même. Lorsqu’une application désérialise des données, elle ne se contente pas de recréer des structures de données passives — elle peut exécuter du code. De nombreux formats et bibliothèques de sérialisation supportent des graphes d’objets complexes, incluant du code exécutable, des constructeurs et des appels de méthodes qui s’exécutent lors de la désérialisation.
La désérialisation non sécurisée permet aux attaquants de manipuler des objets sérialisés pour injecter des données malveillantes dans le code de l’application, pouvant remplacer des objets sérialisés par des objets de types complètement différents.
Vecteurs d’attaque et impacts
Les vulnérabilités de désérialisation non sécurisée peuvent conduire à une exécution de code à distance si les attaquants contrôlent l’objet sérialisé, leur permettant d’exécuter du code arbitraire sur le serveur lors de la désérialisation. L’impact dépasse la RCE et inclut :
- Compromission complète du système : prise de contrôle totale des systèmes vulnérables
- Exfiltration de données : accès et vol d’informations sensibles
- Mouvement latéral : systèmes compromis servant de points de lancement pour d’autres attaques
- Déni de service : opérations de désérialisation intensives en ressources pouvant saturer les systèmes
- Contournement de l’authentification : manipulation d’objets de session pour bypasser la sécurité
Exemples concrets et incidents récents
Le paysage des menaces en 2025 continue de démontrer la gravité des vulnérabilités de désérialisation :
Vulnérabilité ViewState dans Sitecore (CVE-2025-53690)
La vulnérabilité de désérialisation ViewState a permis une exécution de code à distance sur des instances Sitecore exposées à Internet, avec déploiement de malware WEEPSTEEL pour la reconnaissance interne.
Désérialisation dans Microsoft SharePoint (CVE-2025-30382)
Cette vulnérabilité, évaluée à un score CVSS de 7.8, permet à des attaquants distants d’exécuter du code arbitraire, pouvant conduire à une compromission complète du système et à un mouvement latéral dans le réseau.
Ces incidents récents soulignent que les vulnérabilités de désérialisation restent exploitées activement et constituent un risque permanent pour les organisations mondiales.
Analyse technique approfondie : attaque de désérialisation Java
Pour illustrer le fonctionnement des attaques de désérialisation en pratique, examinons un scénario courant en Java — l’un des langages les plus ciblés pour ces attaques.
Exemple de code Java vulnérable
// Code de désérialisation vulnérable
public class VulnerableServer {
public void handleRequest(Socket socket) throws Exception {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Object obj = ois.readObject(); // DANGEREUX : accepte une entrée non fiable
// Traitement de l’objet désérialisé
if (obj instanceof UserData) {
UserData userData = (UserData) obj;
processUserData(userData);
}
}
}
Si un graphe d’objets malveillant, conçu avec une chaîne de gadgets provenant de Commons Collections, est envoyé via la socket, readObject() peut conduire à une exécution de code à distance.
La chaîne d’attaque
Construction de la chaîne de gadgets : Les attaquants identifient des “chaînes de gadgets” — séquences de classes existantes dans le classpath de l’application pouvant être enchaînées pour exécuter du code.
Création de la charge utile : Une objet sérialisé malveillant est construit pour exploiter ces chaînes de gadgets. Par exemple, avec Apache Commons Collections :
// Exemple simplifié d’une charge utile en chaîne de gadgets
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[] {String.class, Class[].class},
new Object[] {"getRuntime", new Class[0]}),
new InvokerTransformer("invoke",
new Class[] {Object.class, Object[].class},
new Object[] {null, new Object[0]}),
new InvokerTransformer("exec",
new Class[] {String.class},
new Object[] {"calc.exe"}) // Exécute la calculatrice
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map map = new HashMap();
map.put("value", "value");
Map transformedMap = TransformedMap.decorate(map, null, transformerChain);
Livraison de la charge utile : L’objet sérialisé malveillant est envoyé à l’application vulnérable via divers canaux (requêtes HTTP, sockets réseau, files de messages, etc.).
Exécution du code : Lors de la désérialisation, la chaîne de gadgets s’exécute, lançant le code de l’attaquant avec les privilèges de l’application.
Vulnérabilités Python Pickle
Le module pickle de Python présente des risques similaires. Considérez ce code vulnérable :
import pickle
import socket
def handle_request(conn):
data = conn.recv(4096)
obj = pickle.loads(data) # DANGEREUX : désérialise des données non fiables
return obj
Un attaquant pourrait créer une charge utile pickle malveillante :
import pickle
import subprocess
class MaliciousPayload:
def __reduce__(self):
return (subprocess.call, (['calc.exe'],))
# Sérialiser la charge utile malveillante
payload = pickle.dumps(MaliciousPayload())
# Envoyer la charge utile au serveur vulnérable...
Lors de la désérialisation, l’application vulnérable exécute la fonction subprocess.call, lançant la calculatrice (ou toute autre commande spécifiée par l’attaquant).
Techniques d’attaque avancées
Programmation orientée propriété (POP)
Les attaquants utilisent la Programmation orientée propriété pour construire des chaînes de gadgets exploitant les chemins de code existants dans les applications. En manipulant soigneusement les propriétés des objets, ils peuvent déclencher des appels de méthodes lors de la désérialisation menant à l’exécution de code.
Attaques de désérialisation aveugle
Même lorsque les applications n’utilisent pas directement les objets désérialisés, les attaquants peuvent toujours obtenir une exécution de code via des effets secondaires lors du processus de désérialisation, comme les appels de constructeurs ou les initialisateurs statiques.
Charges utiles polymorphes
Les attaquants avancés créent des charges utiles pouvant s’adapter à différents environnements et classpaths, augmentant leur taux de succès sur des systèmes cibles variés.
Détection et identification
Identifier les vulnérabilités de désérialisation nécessite à la fois une analyse du code et des tests en runtime :
Analyse statique du code
- Rechercher des méthodes de désérialisation acceptant des entrées non fiables
- Identifier l’utilisation de bibliothèques dangereuses (ObjectInputStream, pickle, etc.)
- Vérifier les procédures de validation et de nettoyage des entrées
Tests dynamiques
- Surveiller le trafic réseau pour des motifs de données sérialisées
- Tester les applications avec des charges utiles malveillantes
- Utiliser des outils de sécurité spécialisés pour détecter les failles de désérialisation
Surveillance en runtime
- Mettre en place des logs pour les opérations de désérialisation
- Surveiller les instanciations d’objets suspectes
- Suivre les appels système inhabituels lors de la désérialisation
Stratégies complètes de prévention
Les stratégies de prévention consistent à ne pas permettre au flux de données de définir le type d’objet qui sera désérialisé, en utilisant des alternatives plus sûres comme DataContractSerializer ou XmlSerializer lorsque cela est possible.
1. Éviter la désérialisation de données non fiables
La défense la plus efficace est simple : ne jamais désérialiser des données provenant de sources non fiables. Ce principe fondamental élimine complètement le vecteur d’attaque.
// Approche sûre : utiliser des formats de données structurés
public class SecureHandler {
public void handleRequest(HttpServletRequest request) {
// Utiliser JSON au lieu de la sérialisation Java
String jsonData = request.getParameter("data");
ObjectMapper mapper = new ObjectMapper();
UserData userData = mapper.readValue(jsonData, UserData.class);
}
}
2. Mettre en œuvre une validation stricte des entrées
Lorsque la désérialisation est inévitable, appliquer une validation complète :
public class ValidatingObjectInputStream extends ObjectInputStream {
private SetString allowedClasses;
public ValidatingObjectInputStream(InputStream in, SetString allowedClasses) {
super(in);
this.allowedClasses = allowedClasses;
}
@Override
protected Class? resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
String className = desc.getName();
if (!allowedClasses.contains(className)) {
throw new InvalidObjectException("Tentative de désérialisation non autorisée : " + className);
}
return super.resolveClass(desc);
}
}
3. Utiliser des approches de liste blanche
Restreindre la désérialisation uniquement aux classes ou objets explicitement fiables et nécessaires au fonctionnement de l’application en maintenant une liste blanche des classes autorisées.
4. Mettre en œuvre un sandboxing
Exécuter les opérations de désérialisation dans des environnements restreints avec des privilèges limités :
// Exemple : limiter les permissions lors de la désérialisation
AccessController.doPrivileged(new PrivilegedActionObject() {
public Object run() {
// Effectuer la désérialisation avec des permissions limitées
return deserializeWithLimitedPrivileges(data);
}
}, restrictedAccessControlContext);
5. Utiliser des alternatives plus sûres
Remplacer la sérialisation native par des formats plus sûrs :
- JSON : lisible par l’humain et ne pas exécuter de code lors de l’analyse
- Protocol Buffers : format binaire avec validation stricte du schéma
- MessagePack : format binaire efficace sans risque d’exécution de code
- XML avec validation de schéma : format structuré avec capacités de validation
6. Mettre en œuvre des protections en runtime
# Exemple Python : limiter les opérations pickle
import pickle
import builtins
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
# Autoriser uniquement les builtins sûrs
if module == "builtins" and name in ["list", "dict", "str", "int"]:
return getattr(builtins, name)
raise pickle.UnpicklingError(f"Classe interdite : {module}.{name}")
def safe_loads(data):
return RestrictedUnpickler(io.BytesIO(data)).load()
Bonnes pratiques et standards de l’industrie
Directives OWASP
Suivre les recommandations complètes d’OWASP pour prévenir la désérialisation non sécurisée, incluant recommandations architecturales, bonnes pratiques de codage et méthodologies de test.
Sécurité dès la conception
Intégrer la sécurité dès le cycle de développement logiciel, plutôt que de la considérer en dernier recours.
Évaluations de sécurité régulières
Réaliser des revues de sécurité périodiques et des tests de pénétration pour identifier les vulnérabilités potentielles avant que des attaquants ne le fassent.
Surveillance et réponse aux incidents
Journalisation et alerte
Mettre en place une journalisation complète des opérations de désérialisation :
logger.info("Tentative de désérialisation pour la classe : {} depuis la source : {}",
className, requestSource);
Procédures de réponse aux incidents
Élaborer des procédures spécifiques pour répondre aux attaques de désérialisation, incluant : - Stratégies de confinement immédiates - Procédures d’analyse forensique - Étapes de récupération et de remédiation - Protocoles de communication
Considérations futures et menaces émergentes
Comme le montrent les vulnérabilités récentes en 2025, les attaques par désérialisation continuent d’évoluer. Les organisations doivent rester vigilantes et adapter leurs stratégies de sécurité pour faire face à :
- Nouvelles techniques et vecteurs d’attaque
- Formats et bibliothèques de sérialisation émergents
- Architectures cloud-native et microservices
- Applications d’IA et d’apprentissage automatique traitant des données sérialisées
Conclusion
La désérialisation de données non fiables reste l’une des classes de vulnérabilités les plus critiques dans la sécurité des applications modernes. En injectant des données sérialisées malveillantes, les attaquants peuvent exécuter du code arbitraire sur les serveurs, prenant ainsi le contrôle total des systèmes. Les incidents récents en 2025 rappellent que cette menace est à la fois persistante et en constante évolution.
Le principe fondamental pour se protéger contre ces attaques est simple : ne désérialisez jamais des données que vous ne contrôlez pas. Lorsqu’il est nécessaire de désérialiser, mettre en œuvre plusieurs couches de défense, notamment une validation stricte des entrées, une liste blanche, un sandboxing et une surveillance approfondie.
Les organisations doivent prioriser la correction des vulnérabilités de désérialisation par une combinaison de bonnes pratiques de codage, de décisions architecturales minimisant les risques et d’évaluations de sécurité continues. En comprenant le fonctionnement de ces attaques et en appliquant des stratégies de prévention robustes, les développeurs et les équipes de sécurité peuvent réduire significativement leur exposition à cette classe de vulnérabilités critiques.
Le coût de la prévention est toujours inférieur à celui d’une compromission. Dans une ère où une seule attaque de désérialisation réussie peut conduire à une compromission complète du système et à un impact commercial important, investir dans des mesures de sécurité appropriées n’est pas seulement recommandé — c’est essentiel pour la survie des organisations dans le paysage numérique.
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.