id: CVE-2025-0994-insikt

info:
  name: CVE-2025-0994 Cityworks deserialization vulnerability
  author: ACHA, Insikt Group, Recorded Future
  severity: high
  description: |
    Trimble Cityworks before version 15.8.9 is vulnerable to a deserialization of untrusted data vulnerability. This template detects if the Cityworks instance is before version 15.8.9.
  impact: |
    Successfully exploiting the vulnerability can allow authenticated attackers to conduct remote code execution (RCE).
  remediation: |
    Upgrade to 15.8.9 or later, and Cityworks with Office Companion version 23.10 or later.
  reference:
    - https://www.cisa.gov/news-events/ics-advisories/icsa-25-037-04
    - https://nvd.nist.gov/vuln/detail/CVE-2025-0994
    - https://learn.assetlifecycle.trimble.com/i/1532182-cityworks-customer-communication-2025-02-06-docx
  classification:
    cvss-metrics: CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
    cvss-score: 8.6
    cve-id: CVE-2025-0994
    cwe-id: CWE-502 # Deserialization of Untrusted Data
  metadata:
    verified: true
    max-request: 1
    date: 2025-02-12
    last-updated: 2025-02-12
    unique-rule-id: d2381a79-5966-4ab4-9809-e6132058d431
    mitre-att&ck:
      - attack.t1190 # Exploit Public-Facing Application
      - attack.t1059.007 # Command and Scripting Interpreter: JavaScript
      - attack.t1055 # Process Injection
      - attack.t1036 # Masquerading: Match Legitimate Name or Location
      - attack.t1027 # Obfuscated Files or Information
      - attack.t1105 # Ingress Tool Transfer
      - attack.t1071.001 # Application Layer Protocol: Web Protocols
      - attack.t1219 # Remote Access Software
      - attack.t1573.002 # Encrypted Channel: Asymmetric Cryptography
    shodan-query: |
      html:"Cityworks"
    vendor: Trimble
    product: Cityworks
  tags: cve2025,cve,rce

http:
  - method: GET
    path:
      - "{{BaseURL}}"
      - "{{BaseURL}}/Cityworks/Login.aspx"

    extractors:
      - type: regex
        name: version
        part: body
        group: 1
        internal: true
        regex:
          - "Cityworks ([0-9.]+) - Revision [0-9.]+"

    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200

      - type: word
        words:
          - "Cityworks"
        part: body

      - type: dsl
        dsl:
          - compare_versions(version, '<15.8.9')
