What Is Exploit Chaining?
HuntRule Team · · 7 min read

On this page
One request, no credentials, and the appliance runs whatever sits inside the ${}.
GET /mifs/rs/api/v2/featureusage?format=${"".getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null).exec('touch /tmp/poc')} HTTP/1.1
Host: epmm.example.comThat is CVE-2025-4427 and CVE-2025-4428 fired together against Ivanti Endpoint Manager Mobile, reconstructed from watchTowr Labs' public analysis. Neither bug is rated critical alone. Ivanti scored the authentication bypass 5.3 and the code execution 7.2. Chained, they are unauthenticated remote code execution on an internet-facing MDM appliance. CISA added both to the KEV catalog on 2025-05-19 after in-the-wild use.
Each link buys one capability
Exploit chaining is not two bugs going off at once. It is a sequence where each link buys exactly one capability the next link needs. Initial access. Authentication bypass. A memory primitive. A sandbox escape. Privilege escalation. Persistence. The severity of the chain is a property of the sequence, not the sum of the scores.
The Ivanti chain has two links.
Link one is CVE-2025-4427, a logic flaw in how the /mifs REST API gates its routes (CWE-288). The route /rs/api/v2/** was reachable without a valid session. On its own it buys one thing: reach an endpoint that should be gated behind login. No code runs. Confidentiality impact only, and only "low," which is how it lands at 5.3.
Link two is CVE-2025-4428, a Java Expression Language injection in DeviceFeatureUsageReportQueryRequestValidator (CWE-94). The format parameter flows into AbstractMessageSource.getMessage, and the error-message template evaluates attacker-controlled EL. On its own this bug is authenticated. It needs an admin session, and that precondition is why it scored 7.2 rather than higher. The vector spells it out:
CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:HPR:H means high privileges required. Now compose the links. Link one deletes the precondition of link two. The PR:H that held CVE-2025-4428 to 7.2 is exactly what the bypass removes. What was reachable only by an authenticated admin is now reachable by anyone who can send a GET.
The scores, side by side
Link | Capability it buys | Vendor CVSS | NVD CVSS |
|---|---|---|---|
CVE-2025-4427 | Reach a gated API without auth | 5.3 Medium | 7.5 High |
CVE-2025-4428 | Run Java and OS commands (needs auth) | 7.2 High | 8.8 High |
Chain | Unauthenticated RCE | not scored | not scored |
Two sources could not even agree with each other in isolation. NVD scored the bypass 7.5 and the RCE 8.8, Ivanti scored them 5.3 and 7.2. Both are rating the same two bugs standing alone. That is the whole problem. A CVSS base score describes a vulnerability as a standalone fact, and a chain is not a standalone fact. There is no row in either scoring for "these two share a host and compose into pre-auth RCE."
Why the scanner shrugs
A scanner-driven backlog sorts by severity. A 7.2 and a 5.3 drop into the same heap as a hundred other Highs and Mediums, tagged for the same patch window. Nothing in either number encodes the relationship between them, because the relationship is the one thing a per-CVE score throws away by construction. Prioritisation that keys on standalone severity cannot see a chain, so it schedules the RCE link for next month and the bypass link for whenever.
There is a defender's edge hiding in the same structure. A chain fails if any single link fails. You do not have to fix every bug in it. Patching Ivanti to 11.12.0.5, 12.3.0.2, 12.4.0.2 or 12.5.0.1 closes both, but closing either one alone would already break the sequence. The catch is knowing which Medium is load-bearing, and the score will not tell you.
The sequence is the signature
The individual links are quiet. Link one is a GET to a valid endpoint. Link two, in web logs, is one odd query string. Correlation flips that around: the links are low-signal, but the ordered sequence is not. An unauthenticated request carrying ${ to the featureusage endpoint, followed within seconds by a shell process born from the EPMM Java process, is a shape that benign traffic does not make. That ordering is what a Sigma correlation rule keys on.
Two base rules first. The web request:
title: Ivanti EPMM featureusage EL injection attempt
name: epmm_el_injection
logsource:
category: webserver
detection:
selection:
cs-uri-stem|contains: '/rs/api/v2/featureusage'
cs-uri-query|contains: '${'
condition: selectionThe child process on the appliance, which runs a Linux stack with the app under Tomcat:
title: Shell spawned by Ivanti EPMM Tomcat process
name: epmm_java_shell_child
logsource:
product: linux
category: process_creation
detection:
selection:
ParentImage|endswith: '/java'
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
condition: selectionThen the correlation that joins them in order, on one host, inside a tight window:
title: Ivanti EPMM exploit chain, injection then shell
id: 8f2a5c1e-0d44-4b7a-9c3e-2a1f6b8d4e90
status: experimental
correlation:
type: temporal_ordered
rules:
- epmm_el_injection
- epmm_java_shell_child
group-by:
- host
timespan: 1m
level: criticaltemporal_ordered requires that both member rules match the same group-by value inside timespan, and in the listed order. The injection request has to come before the shell, not just near it. That ordering maps to T1190 (Exploit Public-Facing Application) for the entry and T1059.004 (Unix Shell) for the exec, and it is the join between the two that raises the level to critical when neither member rule would on its own.
What it catches: the documented path where the EL payload calls Runtime.exec and forks a process. What it misses is worth stating plainly. An attacker who stays inside the JVM never spawns a child, so rule two never fires and the correlation stays silent. Picus documented exactly this, EL payloads that register in-memory listeners rather than shelling out. Payload obfuscation in the query string (alternate encodings, no literal ${) also defeats rule one. False positives on rule two are the usual suspects: a legitimate management action or plugin that shells out from the Java process, which is why the correlation, not the lone process rule, is the alert you route.
What correlation costs
Correlation is not free, and pretending otherwise sets up a rule that never fires. It needs three things most environments have to be talked into.
Reliable timestamps. temporal_ordered decides "before" from event time. If the web proxy and the appliance disagree by more than the window, the order inverts and the rule goes quiet. Sync the clocks before you trust the sequence.
A shared identifier to join on. The group-by: host above assumes the web log and the process log tag the same appliance the same way. They rarely do out of the box. Web logs may carry a destination hostname while the EDR carries a sensor ID. Sigma's aliases exists for this, mapping each rule's real field to one logical key, and you have to fill it in for your fields. No join key, no correlation.
Telemetry from more than one layer. This rule spans a web tier and an endpoint tier. If you only ship one, the sequence is unobservable no matter how the rule is written.
Summary
Exploit chaining composes single-capability bugs into an outcome none of them scores alone, and CVSS rates each link in isolation, so a chain's real severity is invisible to score-driven triage. The Ivanti EPMM pair is the clean case: a 5.3 bypass removes the PR:H that capped a 7.2 RCE, and the product is unauthenticated code execution. The individual links are low-signal, but their ordered sequence is detectable, which is what correlation rules are for. Budget for the timestamps, join keys and cross-layer telemetry the correlation depends on, or the rule is theatre.
Collect:
- webserver access logs (cs-uri-stem, cs-uri-query) from the appliance and any fronting proxy
- linux process_creation (ParentImage, Image) from the EPMM host
Watch for:
- unauthenticated GET to /mifs/rs/api/v2/featureusage with ${ in the query string
- /java parent spawning /sh, /bash or /dash on the appliance within ~60s
CVEs: CVE-2025-4427 (auth bypass), CVE-2025-4428 (EL injection RCE)
Fixed in: EPMM 11.12.0.5, 12.3.0.2, 12.4.0.2, 12.5.0.1
ATT&CK: T1190, T1059.004Correlation rules that key on a sequence are their own catalog domain. Browse the web-facing and appliance detections at /rules?domain=web, or start from the highest-impact chains at /rules?severity=critical.
Related articles

What is vulnerability management?
About 6% of published CVEs are ever exploited in the wild. A scanner reports the other 94% with the same red badge. That gap is the entire job. Buying a scanner takes an afternoon. Running a…
2025-04-28 · 11 min read

What Is a Zero-Day Vulnerability?
An operator wrote human2.aspx into C:\MOVEitTransfer\wwwroot\ four days before Progress had a patch to give anyone. CISA's KEV entry for the bug behind it lists CWE-89. SQL injection, the same class…
2025-04-15 · 8 min read

What is CVSS and why severity is not risk
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H scores 10.0. That string is the Base vector Palo Alto Networks published for CVE-2024-3400. It says nothing about whether the…
2025-03-30 · 9 min read