Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-33701-Unsafe-Deserialization-in-OpenTelemetry-Java-Agent-RMI-Instrumentation — Análisis técnico de CVE-2026-33701, una vulnerabilidad de deserialización insegura en la instrumentación RMI del agente Java de OpenTelemetry, incluyendo condiciones de explotación, detalles del parche y estrategias de mitigación. | Kitploit
Herramientas/GitHubGitHub/pl4tyz/cve-2026-33701-unsafe-deserialization-in-opentelemetry-java-agent-rmi-instrumentation
Análisis de VulnerabilidadesExplotaciónSeguridad WebAprendizaje y Educación
GitHubpl4tyz/cve-2026-33701-unsafe-deserialization-in-opentelemetry-java-agent-rmi-instrumentation

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

Análisis técnico de CVE-2026-33701, una vulnerabilidad de deserialización insegura en la instrumentación RMI del agente Java de OpenTelemetry, incluyendo condiciones de explotación, detalles del parche y estrategias de mitigación.

Ver Repositorio
11hace 6 mesesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2026-33701 — Deserialización insegura en la instrumentación RMI del agente Java de OpenTelemetry

Gravedad: Crítica (CVSS v4.0: 9.3)
Versiones afectadas: opentelemetry-javaagent < 2.26.1
Corregido en: 2.26.1 (publicado el 23 de marzo de 2026)


Resumen

OpenTelemetry es probablemente el framework de observabilidad más adoptado en el ecosistema Java en la actualidad. El agente Java en particular es utilizado por miles de servicios de producción para instrumentar automáticamente aplicaciones para trazado, métricas y registro de eventos sin requerir ningún cambio de código por parte del desarrollador. Solo lo adjuntas como un flag de javaagent y hace todo detrás de escena.

Lo que hace interesante a CVE-2026-33701 no es solo la vulnerabilidad en sí, sino la naturaleza de cómo se introdujo. El agente registra silenciosamente un endpoint RMI personalizado como efecto secundario de su instrumentación RMI. Los desarrolladores no saben que está ahí. No está en ningún código de aplicación. No es algo que hayan configurado. El agente lo colocó automáticamente, y para versiones anteriores a 2.26.1 ese endpoint estaba deserializando datos entrantes sin absolutamente ningún filtro aplicado.

Si la aplicación ya tenía un puerto RMI o JMX expuesto, un atacante con acceso de red a ese puerto podría enviar una carga útil serializada manipulada al endpoint personalizado del agente y potencialmente lograr ejecución remota de código con los privilegios del proceso JVM. El detalle es que la RCE requiere que una cadena de gadgets compatible esté presente en el classpath de la aplicación. Más sobre eso más adelante.


Cómo el Agente Instrumenta RMI

Cuando el agente Java de OTel se adjunta a una JVM, instrumenta llamadas RMI para la propagación de contexto. La idea es que cuando un cliente RMI llama a un método remoto, el agente necesita propagar el contexto de trazado actual al lado del servidor para que los spans se conecten correctamente a través de los límites del servicio.

Para hacer esto, el agente registra su propio objeto RMI personalizado usando un ObjID codificado. En ContextPropagator.java:

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

Este ObjID es cómo el agente identifica su propio endpoint dentro del runtime RMI. Cuando un cliente RMI instrumentado se conecta a un servidor, primero verifica si el servidor tiene este ObjID registrado. Si lo tiene, envía una carga útil de propagación de contexto. Si no, omite la propagación de contexto y simplemente realiza la llamada regular.

El problema es que este endpoint está registrado dentro del runtime RMI de la JVM, lo que significa que comparte el mismo transporte que cualquier puerto RMI o JMX que la aplicación tenga abierto. Si la aplicación tiene -Dcom.sun.management.jmxremote.port configurado, o si exporta sus propios servicios RMI, el endpoint del agente es alcanzable en ese mismo puerto por cualquiera que pueda conectarse a él.


El Código Vulnerable

La deserialización ocurre en ContextPayload.java. En versiones anteriores a 2.26.1, el método read() se veía así:

@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;
}

La anotación @SuppressWarnings("BanSerializableRead") con el comentario // fine es en realidad bastante reveladora. Alguien del equipo marcó esto como una preocupación en algún momento, se agregó la supresión, y el comentario pretendía justificarla. Claramente no estaba bien.

oi.readObject() sin filtros de serialización es el patrón clásico de deserialización insegura. La serialización de Java instanciará felizmente cualquier clase en el classpath durante la deserialización, y si el atacante puede controlar el flujo serializado, puede elegir qué clases se instancian y en qué orden. Esa es la base de los ataques de cadenas de gadgets.

El código sí verifica instanceof Map después de la deserialización, pero para ese punto el daño ya está hecho. La cadena de gadgets se ejecuta durante la llamada a readObject() en sí, antes de que ocurra cualquier verificación de tipos. La verificación instanceof es completamente irrelevante desde un punto de vista de seguridad.


El Parche

La corrección en 2.26.1 reemplaza por completo el enfoque de deserialización. En lugar de serializar un objeto Map y llamar a readObject(), la nueva implementación lee manualmente las entradas de contexto como tipos primitivos:

@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);
}

Y el lado de escritura se actualizó para coincidir:

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());
    }
}

Este enfoque solo lee tipos primitivos (ints y cadenas UTF) del flujo. No hay instanciación de objetos. Ninguna cadena de gadgets puede ejecutarse a través de readInt() o readUTF(). La corrección es correcta y completa.

También hay un segundo cambio que vale la pena señalar. El ObjID utilizado para identificar el endpoint personalizado del agente fue versionado:

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

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

Esto significa que un agente parcheado no responderá al ObjID antiguo en absoluto. Un atacante que apunte al endpoint antiguo no obtendría respuesta de un servidor parcheado. Esta es una medida adicional de endurecimiento agradable además de la corrección de deserialización; efectivamente rompe cualquier exploit que se haya construido contra el endpoint v1 incluso si de alguna manera la deserialización aún fuera alcanzable.


Condiciones de Explotación

Las tres siguientes condiciones deben ser verdaderas simultáneamente para que esto sea explotable:

1. Agente Java de OpenTelemetry adjunto en JDK 16 o inferior

Esta es la restricción más importante. JDK 17 introdujo cambios significativos en los internals de RMI y aplica una encapsulación de módulos mucho más estricta a través del Java Platform Module System. La mayoría de las cadenas de gadgets que funcionan contra la deserialización de Java dependen de la reflexión para acceder a clases internas del JDK o para invocar métodos que normalmente no serían accesibles. JDK 17 rompe esas rutas de reflexión por defecto debido a la encapsulación fuerte, lo que significa que la mayoría de las cadenas de gadgets conocidas simplemente no funcionan en JDK 17 y superiores.

Descargar herramienta