astr.al


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