Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-33701-Unsafe-Deserialization-in-OpenTelemetry-Java-Agent-RMI-Instrumentation — Analyse technique de CVE-2026-33701, une vulnérabilité de désérialisation non sécurisée dans l'instrumentation RMI de l'agent Java OpenTelemetry, incluant les conditions d'exploitation, les détails du correctif et les stratégies d'atténuation. | Kitploit
Outils/GitHubGitHub/pl4tyz/cve-2026-33701-unsafe-deserialization-in-opentelemetry-java-agent-rmi-instrumentation
Analyse des VulnérabilitésExploitationSécurité WebApprentissage et Éducation
GitHubpl4tyz/cve-2026-33701-unsafe-deserialization-in-opentelemetry-java-agent-rmi-instrumentation

CVE-2026-33701-Unsafe-Deserialization-in-OpenTelemetry-Java-Agent-RMI-Instrumentation

Analyse technique de CVE-2026-33701, une vulnérabilité de désérialisation non sécurisée dans l'instrumentation RMI de l'agent Java OpenTelemetry, incluant les conditions d'exploitation, les détails du correctif et les stratégies d'atténuation.

Voir le dépôt
10il y a 6 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2026-33701 — Désérialisation non sécurisée dans l'instrumentation RMI de l'agent Java OpenTelemetry

Sévérité : Critique (CVSS v4.0 : 9.3)
Versions concernées : opentelemetry-javaagent < 2.26.1
Corrigé dans : 2.26.1 (publié le 23 mars 2026)


Vue d'ensemble

OpenTelemetry est probablement le framework d'observabilité le plus largement adopté dans l'écosystème Java actuellement. L'agent Java en particulier est utilisé par des milliers de services de production pour instrumenter automatiquement les applications pour le tracing, les métriques et la journalisation, sans nécessiter aucune modification de code de la part du développeur. Il suffit de l'attacher comme flag javaagent et il fait tout en arrière-plan.

Ce qui rend CVE-2026-33701 intéressant, ce n'est pas seulement la vulnérabilité elle-même, c'est la nature de la façon dont elle a été introduite. L'agent enregistre silencieusement un endpoint RMI personnalisé comme effet secondaire de son instrumentation RMI. Les développeurs ne savent pas qu'il est là. Il n'est dans aucun code applicatif. Ce n'est pas quelque chose qu'ils ont configuré. L'agent l'a mis là automatiquement, et pour les versions antérieures à 2.26.1, cet endpoint désérialisait les données entrantes sans aucun filtre appliqué.

Si l'application avait déjà un port RMI ou JMX exposé, un attaquant ayant un accès réseau à ce port pouvait envoyer une charge utile sérialisée spécialement conçue à l'endpoint personnalisé de l'agent et potentiellement obtenir une exécution de code à distance avec les privilèges du processus JVM. Le hic, c'est que l'exécution de code à distance nécessite qu'une chaîne de gadgets compatible soit présente sur le classpath de l'application. Plus de détails à ce sujet plus tard.


Comment l'agent instrumente RMI

Lorsque l'agent Java OTel s'attache à une JVM, il instrumente les appels RMI pour la propagation de contexte. L'idée est que lorsqu'un client RMI appelle une méthode distante, l'agent doit propager le contexte de trace actuel au côté serveur afin que les spans se connectent correctement à travers les frontières de service.

Pour ce faire, l'agent enregistre son propre objet RMI personnalisé en utilisant un ObjID codé en dur. Dans ContextPropagator.java :

public static final ObjID CONTEXT_CALL_ID =
    new ObjID("io.opentelemetry.javaagent.context-call".hashCode());

Cet ObjID est la façon dont l'agent identifie son propre endpoint dans le runtime RMI. Lorsqu'un client RMI instrumenté se connecte à un serveur, il vérifie d'abord si le serveur a cet ObjID enregistré. Si c'est le cas, il envoie une charge utile de propagation de contexte. Sinon, il ignore la propagation de contexte et effectue simplement l'appel normal.

Le problème est que cet endpoint est enregistré dans le runtime RMI de la JVM, ce qui signifie qu'il partage le même transport que le port RMI ou JMX que l'application a ouvert. Si l'application a -Dcom.sun.management.jmxremote.port défini, ou si elle exporte ses propres services RMI, l'endpoint de l'agent est accessible sur ce même port par quiconque peut s'y connecter.


Le code vulnérable

La désérialisation se produit dans ContextPayload.java. Dans les versions antérieures à 2.26.1, la méthode read() ressemblait à ceci :

@SuppressWarnings("BanSerializableRead") // fine
public static ContextPayload read(ObjectInput oi) throws IOException {
    try {
        Object object = oi.readObject();
        if (object instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, String> map = (Map<String, String>) object;
            return new ContextPayload(map);
        }
    } catch (ClassCastException | ClassNotFoundException ex) {
        logger.log(FINE, "Error reading object", ex);
    }
    return null;
}

L'annotation @SuppressWarnings("BanSerializableRead") avec le commentaire // fine est en fait assez révélatrice. Quelqu'un dans l'équipe a signalé cela comme une préoccupation à un moment donné, la suppression a été ajoutée, et le commentaire était destiné à la justifier. Clairement, ce n'était pas correct.

oi.readObject() sans filtres de sérialisation est le schéma classique de désérialisation non sécurisée. La sérialisation Java instanciera volontiers n'importe quelle classe sur le classpath pendant la désérialisation, et si l'attaquant peut contrôler le flux sérialisé, il peut choisir quelles classes sont instanciées et dans quel ordre. C'est la base des attaques par chaîne de gadgets.

Le code vérifie bien instanceof Map après la désérialisation, mais à ce stade, les dégâts sont déjà faits. La chaîne de gadgets s'exécute pendant l'appel readObject() lui-même, avant que toute vérification de type ne se produise. La vérification instanceof est complètement hors de propos d'un point de vue sécurité.


Le correctif

Le correctif dans 2.26.1 remplace complètement l'approche de désérialisation. Au lieu de sérialiser un objet Map et d'appeler readObject(), la nouvelle implémentation lit manuellement les entrées de contexte comme des types primitifs :

@Nullable
public static ContextPayload read(ObjectInput oi) throws IOException {
    int size = oi.readInt();
    if (size > MAX_CONTEXT_ENTRIES) {
        logger.log(
            FINE,
            "RMI context propagation payload size {0} exceeds maximum allowed of {1}, skipping context propagation.",
            new Object[] {size, MAX_CONTEXT_ENTRIES});
        return null;
    }
    Map<String, String> map = new HashMap<>();
    for (int i = 0; i < size; i++) {
        String key = oi.readUTF();
        String value = oi.readUTF();
        map.put(key, value);
    }
    return new ContextPayload(map);
}

Et le côté écriture a été mis à jour pour correspondre :

public void write(ObjectOutput out) throws IOException {
    int size = context.size();
    if (size > MAX_CONTEXT_ENTRIES) {
        out.writeInt(0);
        return;
    }
    out.writeInt(size);
    for (Map.Entry<String, String> entry : context.entrySet()) {
        out.writeUTF(entry.getKey());
        out.writeUTF(entry.getValue());
    }
}

Cette approche ne lit que des types primitifs (entiers et chaînes UTF) depuis le flux. Aucune instanciation d'objet ne se produit. Aucune chaîne de gadgets ne peut s'exécuter via readInt() ou readUTF(). Le correctif est correct et complet.

Il y a aussi un deuxième changement qui mérite d'être noté. L'ObjID utilisé pour identifier l'endpoint personnalisé de l'agent a été versionné :

// Avant (2.26.0)
new ObjID("io.opentelemetry.javaagent.context-call".hashCode());

// Après (2.26.1)
new ObjID("io.opentelemetry.javaagent.context-call-v2".hashCode());

Cela signifie qu'un agent corrigé ne répondra pas du tout à l'ancien ObjID. Un attaquant ciblant l'ancien endpoint n'obtiendrait aucune réponse d'un serveur corrigé. C'est une mesure de durcissement supplémentaire intéressante en plus du correctif de désérialisation, elle casse effectivement toute exploitation construite contre l'endpoint v1 même si, d'une manière ou d'une autre, la désérialisation était toujours accessible.


Conditions d'exploitation

Les trois conditions suivantes doivent être vraies simultanément pour que cela soit exploitable :

1. Agent Java OpenTelemetry attaché sur JDK 16 ou inférieur

Télécharger l’outil