{
  "hunt": {
    "meta": {
      "tlp": "clear",
      "hunt": {
        "handoff": "keep-as-periodic-hunt",
        "trigger": "intel-report",
        "methodology": "model-assisted",
        "applicability": "campaign-specific",
        "justification": "Disruption to DICOM servers impacts clinical care. This hunt provides assurance that critical healthcare infrastructure is not being actively exploited via this high-severity heap overflow."
      },
      "name": "Orthanc DICOM Server Vulnerability Exploitation",
      "type": "investigation",
      "labels": [
        "hunt",
        "attack.t1190",
        "attack.t1090.003",
        "attack.t1133",
        "attack.t1566",
        "attack.t1499"
      ],
      "related": [
        {
          "hunt": "lateral-movement-from-clinical-assets",
          "reason": "If an attacker crashes Orthanc, they may have already executed code and moved elsewhere.",
          "relation": "follows"
        }
      ],
      "targets": {
        "web": {
          "name": "Web server / proxy logs",
          "category": "siem",
          "telemetry": [
            "network"
          ]
        },
        "hunter": {
          "name": "Hunt agent",
          "agent": true
        },
        "analyst": {
          "name": "Tier-2 analyst",
          "role": "analyst"
        },
        "endpoint": {
          "name": "Endpoint telemetry (hb_ surfaces)",
          "category": "endpoint",
          "telemetry": [
            "endpoint"
          ]
        }
      },
      "analysis": "Static rules for process crashes are too noisy for medical environments. This hunt uses a phased approach, building confidence from software versions, exposure, and rare authenticated upload patterns before correlating with impact.",
      "coverage": [
        {
          "stage": "vulnerability-inventory",
          "steps": [
            "find-vulnerable-orthanc"
          ],
          "status": "covered"
        },
        {
          "stage": "initial-access-vectors",
          "steps": [
            "exposed-orthanc-services",
            "orthanc-authentication"
          ],
          "status": "covered"
        },
        {
          "stage": "exploit-delivery-upload",
          "steps": [
            "rare-uploader-prevalence"
          ],
          "status": "covered"
        },
        {
          "stage": "network-traffic-obfuscation",
          "reason": "Tor activity is covered by existing rule dns_query_tor_onion.",
          "status": "existing_rule"
        },
        {
          "stage": "impact-denial-of-service",
          "steps": [
            "orthanc-process-crashes"
          ],
          "status": "covered"
        }
      ],
      "scenario": {
        "stages": [
          {
            "name": "Initial Access & Credential Harvesting",
            "slug": "initial-access-vectors",
            "tactic": "initial-access",
            "techniques": [
              "T1566",
              "T1133"
            ],
            "observables": [
              "Unsolicited emails with malicious links or attachments",
              "Remote access attempts via VPNs or exposed control systems"
            ]
          },
          {
            "name": "Identification of Vulnerable Orthanc Server",
            "slug": "vulnerability-inventory",
            "tactic": "initial-access",
            "techniques": [
              "T1190"
            ],
            "observables": [
              "Orthanc DICOM Server versions < 1.13.0",
              "CVE-2026-87020"
            ]
          },
          {
            "name": "Authenticated Malicious Image Upload",
            "slug": "exploit-delivery-upload",
            "tactic": "initial-access",
            "techniques": [
              "T1190"
            ],
            "observables": [
              "Authenticated HTTP POST requests containing PNG or JPEG images",
              "Communication with Orthanc DICOM service endpoints"
            ]
          },
          {
            "name": "Multi-hop Proxying",
            "slug": "network-traffic-obfuscation",
            "tactic": "command-and-control",
            "techniques": [
              "T1090.003"
            ],
            "observables": [
              "Traffic routed through multiple proxies or Tor to hide origin"
            ]
          },
          {
            "name": "Process Crash and DoS",
            "slug": "impact-denial-of-service",
            "tactic": "impact",
            "techniques": [
              "T1499"
            ],
            "observables": [
              "Termination of Orthanc process",
              "Heap out-of-bounds write leading to Orthanc service instability"
            ]
          }
        ],
        "summary": "Authenticated remote attackers exploit an integer overflow in Orthanc DICOM Server's image decoding logic (CVE-2026-87020) by providing malicious PNG or JPEG files. Successful exploitation triggers a heap out-of-bounds write that crashes the Orthanc process, resulting in a denial-of-service (DoS) condition."
      },
      "severity": "high",
      "rationale": "Focus on medical imaging VLANs and servers running DICOM services. The scoping query uses LIKE patterns to capture vulnerable versions (e.g., 1.12.x) that string comparisons often miss.",
      "guardrails": {
        "claims": "no_unsupported",
        "evidence": "citation_required",
        "telemetry": "untrusted",
        "missing_data": "not_benign"
      },
      "hypothesis": "An intruder exploits CVE-2026-87020 by uploading a malformed image to an authenticated session on a vulnerable Orthanc server, causing a heap overflow and process crash.",
      "parameters": {
        "scope_hosts": {
          "from": {
            "ref": "analyst-defined",
            "kind": "manual",
            "observed": "2026-09-10"
          },
          "type": "list[host]",
          "default": [],
          "description": "List of hostnames to narrow the search; leave empty for all hosts."
        },
        "lookback_days": {
          "from": {
            "ref": "hunt-standard",
            "kind": "manual",
            "observed": "2026-09-10"
          },
          "type": "number",
          "default": "14",
          "description": "Days of history to examine."
        },
        "orthanc_keywords": {
          "from": {
            "ref": "cisa-advisory",
            "kind": "article",
            "observed": "2026-09-10"
          },
          "type": "list[string]",
          "default": [
            "orthanc",
            "dicom"
          ],
          "description": "Keywords to identify Orthanc processes and packages."
        },
        "upload_endpoints": {
          "from": {
            "ref": "orthanc-documentation",
            "kind": "article",
            "observed": "2026-09-10"
          },
          "type": "list[string]",
          "default": [
            "/instances/",
            " /tools/preview/",
            " /dicom-web/"
          ],
          "description": "Known Orthanc image upload paths."
        }
      },
      "provenance": {
        "authors": [
          {
            "org": "huntbase.io",
            "name": "Huntbase hunt generation"
          }
        ],
        "generated": {
          "by": "huntbase-hunt-generation",
          "from": "https://www.cisa.gov/news-events/ics-medical-advisories/icsma-26-253-02",
          "gates": [
            "dry-run",
            "lint"
          ],
          "model": "hb_google/gemini-3-flash-preview"
        }
      },
      "references": [
        {
          "url": "https://www.cisa.gov/news-events/ics-medical-advisories/icsma-26-253-02",
          "name": "CISA Advisory: Orthanc DICOM Server"
        }
      ],
      "blind_spots": [
        {
          "id": "http-body-inspection",
          "risk": "We see the upload event but cannot confirm it is malicious without seeing the image data.",
          "stage": "exploit-delivery-upload",
          "question": "Does the PNG/JPEG payload contain the specific malformed pitch header?",
          "requires": "Full HTTP body logging or DPI"
        },
        {
          "id": "no-crash-telemetry",
          "risk": "Legitimate maintenance could be flagged as a denial-of-service event.",
          "stage": "impact-denial-of-service",
          "question": "Was the process termination caused by the heap overflow or a manual service restart?",
          "requires": "activity_id 2 for all processes or kernel crash logs"
        }
      ]
    },
    "name": "Orthanc DICOM Server Vulnerability Exploitation",
    "description": "This hunt identifies vulnerable Orthanc DICOM Server instances and correlates authenticated image uploads with subsequent process terminations. The vulnerability is a heap out-of-bounds write triggered by integer overflows during image decoding. Because the exploit requires authentication, the hunt first establishes the risk surface through exposure and successful HTTP authentication events. It then stacks upload activity to find rare origins that precede service crashes."
  },
  "nodes": [
    {
      "id": "hypothesis",
      "type": "hypothesis",
      "label": "Hypothesis",
      "config": {
        "tags": [],
        "coverage": [
          {
            "stage": "vulnerability-inventory",
            "steps": [
              "find-vulnerable-orthanc"
            ],
            "status": "covered"
          },
          {
            "stage": "initial-access-vectors",
            "steps": [
              "exposed-orthanc-services",
              "orthanc-authentication"
            ],
            "status": "covered"
          },
          {
            "stage": "exploit-delivery-upload",
            "steps": [
              "rare-uploader-prevalence"
            ],
            "status": "covered"
          },
          {
            "stage": "network-traffic-obfuscation",
            "reason": "Tor activity is covered by existing rule dns_query_tor_onion.",
            "status": "existing_rule"
          },
          {
            "stage": "impact-denial-of-service",
            "steps": [
              "orthanc-process-crashes"
            ],
            "status": "covered"
          }
        ],
        "rationale": "An intruder exploits CVE-2026-87020 by uploading a malformed image to an authenticated session on a vulnerable Orthanc server, causing a heap overflow and process crash.",
        "blind_spots": [
          {
            "id": "http-body-inspection",
            "risk": "We see the upload event but cannot confirm it is malicious without seeing the image data.",
            "stage": "exploit-delivery-upload",
            "question": "Does the PNG/JPEG payload contain the specific malformed pitch header?",
            "requires": "Full HTTP body logging or DPI"
          },
          {
            "id": "no-crash-telemetry",
            "risk": "Legitimate maintenance could be flagged as a denial-of-service event.",
            "stage": "impact-denial-of-service",
            "question": "Was the process termination caused by the heap overflow or a manual service restart?",
            "requires": "activity_id 2 for all processes or kernel crash logs"
          }
        ],
        "scoping_notes": "Focus on medical imaging VLANs and servers running DICOM services. The scoping query uses LIKE patterns to capture vulnerable versions (e.g., 1.12.x) that string comparisons often miss.",
        "beyond_detection": "Static rules for process crashes are too noisy for medical environments. This hunt uses a phased approach, building confidence from software versions, exposure, and rare authenticated upload patterns before correlating with impact."
      }
    },
    {
      "id": "find-vulnerable-orthanc",
      "type": "query",
      "label": "Identify vulnerable Orthanc servers",
      "config": {
        "dsl": "sqlite",
        "role": "scoping",
        "source": "endpoint",
        "content": "SELECT device_hostname, package_name, package_version, install_path FROM hb_software_inventory WHERE (instr(',' || '{{orthanc_keywords}}' || ',', ',' || LOWER(package_name) || ',') > 0 OR LOWER(package_name) LIKE '%orthanc%') AND (package_version LIKE '1.12%' OR package_version LIKE '1.11%' OR package_version LIKE '1.10%' OR package_version LIKE '1.9%' OR package_version LIKE '0.%')",
        "surface": "hb_software_inventory",
        "description": "Filter software inventory for Orthanc versions earlier than 1.13.0 using explicit version patterns.",
        "expected_signal": "A list of servers running affected versions. Silence confirms no vulnerable packages are registered."
      },
      "parents": [
        {
          "id": "hypothesis"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "scoping",
        "label": "Identify vulnerable Orthanc servers",
        "reads": [
          "device_hostname",
          "install_path",
          "package_name",
          "package_version"
        ],
        "source": "hb_software_inventory",
        "target": "endpoint",
        "content": "SELECT device_hostname, package_name, package_version, install_path FROM hb_software_inventory WHERE (instr(',' || '{{orthanc_keywords}}' || ',', ',' || LOWER(package_name) || ',') > 0 OR LOWER(package_name) LIKE '%orthanc%') AND (package_version LIKE '1.12%' OR package_version LIKE '1.11%' OR package_version LIKE '1.10%' OR package_version LIKE '1.9%' OR package_version LIKE '0.%')",
        "silence": "not_evidence_of_absence",
        "expected": "A list of servers running affected versions. Silence confirms no vulnerable packages are registered.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "exposed-orthanc-services",
      "type": "query",
      "label": "Examine internet exposure",
      "config": {
        "dsl": "sqlite",
        "role": "enrichment",
        "source": "endpoint",
        "content": "SELECT domain_or_ip, port, product, version, discovered_at FROM hb_exposed_assets WHERE (LOWER(product) LIKE '%orthanc%' OR LOWER(source_product) LIKE '%orthanc%') AND discovered_at >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_exposed_assets",
        "description": "Check external scanner data for Orthanc instances visible from the public internet.",
        "expected_signal": "Asset records for exposed servers. Silence means no public footprint was detected."
      },
      "parents": [
        {
          "id": "find-vulnerable-orthanc"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "enrichment",
        "label": "Examine internet exposure",
        "reads": [
          "discovered_at",
          "domain_or_ip",
          "port",
          "product",
          "source_product",
          "version"
        ],
        "source": "hb_exposed_assets",
        "target": "endpoint",
        "content": "SELECT domain_or_ip, port, product, version, discovered_at FROM hb_exposed_assets WHERE (LOWER(product) LIKE '%orthanc%' OR LOWER(source_product) LIKE '%orthanc%') AND discovered_at >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Asset records for exposed servers. Silence means no public footprint was detected.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "orthanc-authentication",
      "type": "query",
      "label": "Detect successful HTTP authentication",
      "config": {
        "dsl": "sqlite",
        "role": "triage",
        "source": "web",
        "content": "SELECT device_hostname, src_endpoint_ip, url_full, status_code, time FROM hb_http_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND http_method = 'POST' AND status_code = 200 AND (LOWER(url_path) LIKE '%auth%' OR LOWER(url_path) LIKE '%login%' OR LOWER(url_path) LIKE '%instances%') AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_http_activity",
        "description": "Identify successful authenticated POST requests to the Orthanc server.",
        "expected_signal": "Successful authentication sessions. Authentication is a prerequisite for the CVE-2026-87020 exploit."
      },
      "parents": [
        {
          "id": "find-vulnerable-orthanc"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "triage",
        "label": "Detect successful HTTP authentication",
        "reads": [
          "device_hostname",
          "http_method",
          "src_endpoint_ip",
          "status_code",
          "time",
          "url_full",
          "url_path"
        ],
        "source": "hb_http_activity",
        "target": "web",
        "content": "SELECT device_hostname, src_endpoint_ip, url_full, status_code, time FROM hb_http_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND http_method = 'POST' AND status_code = 200 AND (LOWER(url_path) LIKE '%auth%' OR LOWER(url_path) LIKE '%login%' OR LOWER(url_path) LIKE '%instances%') AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Successful authentication sessions. Authentication is a prerequisite for the CVE-2026-87020 exploit.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "risk-assessment",
      "type": "analytic",
      "label": "Triage early evidence",
      "config": {
        "cite": "required",
        "tools": [
          "endpoint",
          "web"
        ],
        "context": [
          "find-vulnerable-orthanc",
          "exposed-orthanc-services",
          "orthanc-authentication"
        ],
        "objective": "Determine which vulnerable Orthanc servers are most at risk based on their version, exposure status, and the presence of authenticated traffic.",
        "description": "Evaluate the risk of exploitation per host based on version and exposure evidence.",
        "max_iterations": 3,
        "expected_signal": "A risk verdict per host prioritizing those with known vulnerabilities and active external authentication.",
        "success_criteria": "A summary per host citing vulnerable versions and evidence of external access."
      },
      "parents": [
        {
          "id": "exposed-orthanc-services",
          "kind": "merge"
        },
        {
          "id": "orthanc-authentication",
          "kind": "merge"
        }
      ]
    },
    {
      "id": "rare-uploader-prevalence",
      "type": "query",
      "label": "Baseline rare image uploaders",
      "config": {
        "dsl": "sqlite",
        "role": "baseline",
        "source": "web",
        "content": "SELECT device_hostname, src_endpoint_ip, url_path, COUNT(*) AS request_count, MIN(time) AS first_upload FROM hb_http_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND http_method = 'POST' AND instr(',' || '{{upload_endpoints}}' || ',', ',' || LOWER(url_path) || ',') > 0 AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY device_hostname, src_endpoint_ip, url_path HAVING request_count < 20",
        "surface": "hb_http_activity",
        "description": "Stack-count source IPs uploading images to find rare actors that might be delivering exploits.",
        "expected_signal": "One-off or rare source IPs performing uploads. Frequent uploaders are likely legitimate clinical tools."
      },
      "parents": [
        {
          "id": "risk-assessment"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "baseline",
        "label": "Baseline rare image uploaders",
        "reads": [
          "device_hostname",
          "http_method",
          "src_endpoint_ip",
          "time",
          "url_path"
        ],
        "source": "hb_http_activity",
        "target": "web",
        "content": "SELECT device_hostname, src_endpoint_ip, url_path, COUNT(*) AS request_count, MIN(time) AS first_upload FROM hb_http_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND http_method = 'POST' AND instr(',' || '{{upload_endpoints}}' || ',', ',' || LOWER(url_path) || ',') > 0 AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY device_hostname, src_endpoint_ip, url_path HAVING request_count < 20",
        "silence": "not_evidence_of_absence",
        "baseline": {
          "window": "{{lookback_days}}d",
          "compare": "first_seen"
        },
        "expected": "One-off or rare source IPs performing uploads. Frequent uploaders are likely legitimate clinical tools.",
        "verified": "dry-run",
        "prevalence": {
          "by": "device_hostname",
          "key": [
            "src_endpoint_ip",
            "url_path"
          ],
          "rare_below": 5
        },
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "orthanc-process-crashes",
      "type": "query",
      "label": "Detect Orthanc service terminations",
      "config": {
        "dsl": "sqlite",
        "role": "triage",
        "source": "endpoint",
        "content": "SELECT device_hostname, process_name, process_cmd_line, activity_id, time FROM hb_process_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND activity_id = 2 AND (instr(',' || '{{orthanc_keywords}}' || ',', ',' || LOWER(process_name) || ',') > 0 OR LOWER(process_name) LIKE '%orthanc%') AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_process_activity",
        "description": "Find process termination events for Orthanc to identify potential DoS impact from exploitation.",
        "expected_signal": "Orthanc process terminations. Silence means the service has remained stable during the window."
      },
      "parents": [
        {
          "id": "risk-assessment"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "triage",
        "label": "Detect Orthanc service terminations",
        "reads": [
          "activity_id",
          "device_hostname",
          "process_cmd_line",
          "process_name",
          "time"
        ],
        "source": "hb_process_activity",
        "target": "endpoint",
        "content": "SELECT device_hostname, process_name, process_cmd_line, activity_id, time FROM hb_process_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND activity_id = 2 AND (instr(',' || '{{orthanc_keywords}}' || ',', ',' || LOWER(process_name) || ',') > 0 OR LOWER(process_name) LIKE '%orthanc%') AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Orthanc process terminations. Silence means the service has remained stable during the window.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "exploitation-correlation",
      "type": "analytic",
      "label": "Final exploitation assessment",
      "config": {
        "cite": "required",
        "tools": [
          "endpoint",
          "web"
        ],
        "context": [
          "risk-assessment",
          "rare-uploader-prevalence",
          "orthanc-process-crashes"
        ],
        "objective": "Correlate the risk assessment with rare upload events and process terminations on the same host within a 10-minute window to confirm exploitation of CVE-2026-87020.",
        "description": "Link authenticated rare uploads to subsequent crashes within a short time window.",
        "max_iterations": 5,
        "expected_signal": "A confirmed exploitation verdict when a rare IP uploads an image and the service crashes immediately after.",
        "success_criteria": "A per-host verdict of malicious, suspicious, or benign with cited rows."
      },
      "parents": [
        {
          "id": "rare-uploader-prevalence",
          "kind": "merge"
        },
        {
          "id": "orthanc-process-crashes",
          "kind": "merge"
        }
      ]
    },
    {
      "id": "route-on-verdict",
      "type": "checkpoint",
      "label": "Route on verdict",
      "config": {
        "fuzzy": true,
        "judge": "hunter",
        "question": "the exploitation-correlation verdict is malicious for at least one host",
        "condition": "the exploitation-correlation verdict is malicious for at least one host",
        "blind_spot": "no-crash-telemetry",
        "confidence": "high",
        "description": "Determine the next action based on the exploitation correlation results.",
        "checkpoint_type": "mandatory"
      },
      "parents": [
        {
          "id": "exploitation-correlation"
        }
      ]
    },
    {
      "id": "isolate-affected-server",
      "type": "action",
      "label": "Isolate compromised server",
      "config": {
        "target": "endpoint",
        "description": "Contain the server to prevent further exploitation or pivot.",
        "instructions": "Isolate the host and block port 8042 at the network perimeter until the software is patched.",
        "action_approval": "required"
      },
      "parents": [
        {
          "id": "route-on-verdict",
          "branch": "on_supports"
        }
      ]
    },
    {
      "id": "analyst-manual-review",
      "type": "task",
      "label": "Forensic log review",
      "config": {
        "assignee": "analyst",
        "description": "Investigate the source of the malicious upload and the nature of the crash.",
        "instructions": "Review Orthanc application logs for memory allocation errors. Identify the authenticated user account linked to the suspicious POST request."
      },
      "parents": [
        {
          "id": "route-on-verdict",
          "branch": "default"
        },
        {
          "id": "route-on-verdict",
          "branch": "on_unavailable"
        },
        {
          "id": "isolate-affected-server"
        }
      ]
    },
    {
      "id": "patch-verification",
      "type": "task",
      "label": "Verify software upgrade",
      "config": {
        "assignee": "analyst",
        "description": "Ensure all systems are remediated to the patched version.",
        "instructions": "Confirm that all servers identified in the scoping phase have been updated to Orthanc v1.13.0."
      },
      "parents": [
        {
          "id": "route-on-verdict",
          "branch": "on_refutes"
        },
        {
          "id": "analyst-manual-review"
        }
      ]
    }
  ]
}