CVE-2025-26684 "pop-mdatp"
CVE-2025-26684: unprivileged local attackers can execute code as root by tricking
mdatp
into executing arbitrary binaries.
This affects
Microsoft Defender ATP (
mdatp
)
/ Defender for Endpoint / whatever they're calling it this week, on Linux (and possibly macOS, untested).
Versions between
101.52.57 (December 2021) through
101.25032.0008 (May 2025) are affected.
The vulnerability is rather similar to
CVE-2024-48991
in
needrestart
, disclosed by Qualys just a week prior. At least
needrestart
made an attempt to validate
what it was executing.
Background
On 2024-11-25 while investigating an unrelated exploit attempt, I noticed mdatp
executing java --version
on multiple JREs located in non-standard paths.
We tracked down this behavior to a python script
/opt/microsoft/mdatp/conf/scripts/open_files.py
.
It's part of mdatp’s detection logic for
CVE-2021-44228, aka Log4Shell.
open_files.py
is executed as root, as it relies on running
lsof -ac java,javaw
to check for
java
processes with open fds containing
log4j
or
spring-core
in the filename. If there are any positive matches, the script attempts to get the JRE's version number by running
/proc/$pid/exe --version
.
Since
open_files.py
executes any arbitrary binary that just happens to be named
java
, I whipped up a quick proof of concept:
- If with no arguments, it creates a file named
/tmp/log4j
and then sleeps, occasionally checking for root ownership and setuid bit of /tmp/elevate
.
When these conditions are true, it executes elevate
to spawn a root shell.
- When executed as root, with the argument
--version
it changes the ownership and setuid bit of the elevate
wrapper.
About 30 minutes later, after mdatp started its next process scan, I had a lovely root prompt:
snoclogost01:/tmp nobody$ gcc elevate.c -o elevate
snoclogost01:/tmp nobody$ gcc pop-mdatp.c -o java
snoclogost01:/tmp nobody$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
snoclogost01:/tmp nobody$ ./java
[.] creating fake fd to catch mdatp's attention
[.] waiting for next open_files.py scan (~ hourly)
[+] bingo
# id
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)
Mitigations
Modify open_files.py
and remove the unsafe _run_cmd()
call in grab_java_version
. This will break java version reporting in the MDE timeline.
A proper fix would be to identify the JRE version without executing the binary, but this method may vary depending on JRE vendor and version. The version number is only used for reporting
purposes and does not appear to have any bearing on actual log4shell vulnerability detection, so it may be entirely elided.
Exploit
The proof of concept and original writeup sent to MSRC is available
here.
Timeline
- 2024-11-25 — vuln identified, proof of concept tested
- 2024-12-04 — vuln reported to MSRC with reliable exploit included. requested 90 day disclosure window (2025-03-04). automated reply received
- 2024-12-16 — no reply from MSRC, follow-up requested
- 2024-12-17 — MSRC: "[...] we are attempting to reproduce the issue you have reported to us and evaluate its severity and impact."
- 2025-01-09 — follow-up requested
- 2025-01-09 — MSRC: "We are currently seeking to verify the behavior your reported within our own Microsoft Defender for Endpoint Linux test environment. That has proven more difficult than initially anticipated. [...] the earliest timeline we could deliver a fix would be April 8th, 2025."
- 2025-01-10 — MSRC: "We confirmed the behavior you reported."
- 2025-03-17 — MSRC: "[...] the fix [...] will be included in our April 2025 Security Update Release on April 8th, 2025."
- 2025-03-18 — MSRC: "We miscalculated the time required [...] the earliest fix release date for this case would be May 13th, 2025."
- 2025-04-10 — MSRC: "We're happy to report that the fix for MSRC case [...] will be included in our May 2025 Security Update Release on May 13th, 2025."
- 2025-05-16 — writeup released