vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md (10082B)
1 --- 2 title: "VMware Tools service discovery LPE (CWE-426) via regex-based binary discovery (CVE-2025-41244)" 3 section: "Linux" 4 sectionSlug: "linux-hardening" 5 sourcePath: "src/linux-hardening/main-system-information/kernel-lpe-cves/vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/main-system-information/kernel-lpe-cves/vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # VMware Tools service discovery LPE (CWE-426) via regex-based binary discovery (CVE-2025-41244) 14 15 This technique abuses regex-driven service discovery pipelines that parse running process command lines to infer service versions and then execute a candidate binary with a "version" flag. When permissive patterns accept untrusted, attacker-controlled paths (e.g., /tmp/httpd), the privileged collector executes an arbitrary binary from an untrusted location, yielding local privilege escalation. NVISO documented this in VMware Tools/Aria Operations Service Discovery as CVE-2025-41244.<sup>[[1]](#references)[[2]](#references)</sup> 16 17 - Impact: Local privilege escalation to root (or to the privileged discovery account).<sup>[[1]](#references)[[2]](#references)</sup> 18 - Root cause: Untrusted Search Path (CWE-426) + permissive regex matching of process command lines.<sup>[[1]](#references)[[3]](#references)[[5]](#references)</sup> 19 - Affected: open-vm-tools/VMware Tools on Linux (credential-less discovery), VMware Aria Operations SDMP (credential-based discovery via Tools/proxy).<sup>[[1]](#references)[[2]](#references)</sup> 20 21 ## How VMware service discovery works (high level) 22 23 - Credential-based (legacy): Aria executes discovery scripts inside the guest via VMware Tools using configured privileged credentials.<sup>[[1]](#references)</sup> 24 - Credential-less (modern): Discovery logic runs within VMware Tools, already privileged in the guest.<sup>[[1]](#references)</sup> 25 26 Both modes ultimately run shell logic that scans processes with listening sockets, extracts a matching command path via a regex, and executes the first argv token with a version flag.<sup>[[1]](#references)[[3]](#references)</sup> 27 28 ## Root cause and vulnerable pattern (open-vm-tools) 29 30 In open-vm-tools, the serviceDiscovery plugin script get-versions.sh matches candidate binaries using broad regular expressions and executes the first token without any trusted-path validation.<sup>[[1]](#references)[[3]](#references)</sup> 31 32 ```bash 33 get_version() { 34 PATTERN=$1 35 VERSION_OPTION=$2 36 for p in $space_separated_pids 37 do 38 COMMAND=$(get_command_line $p | grep -Eo "$PATTERN") 39 [ ! -z "$COMMAND" ] && echo VERSIONSTART "$p" "$("${COMMAND%%[[:space:]]*}" $VERSION_OPTION 2>&1)" VERSIONEND 40 done 41 } 42 ``` 43 44 It is invoked with permissive patterns containing \S (non-whitespace) that will happily match non-system paths in user-writable locations.<sup>[[1]](#references)[[3]](#references)</sup> 45 46 ```bash 47 get_version "/\S+/(httpd-prefork|httpd|httpd2-prefork)($|\s)" -v 48 get_version "/usr/(bin|sbin)/apache\S*" -v 49 get_version "/\S+/mysqld($|\s)" -V 50 get_version "\.?/\S*nginx($|\s)" -v 51 get_version "/\S+/srm/bin/vmware-dr($|\s)" --version 52 get_version "/\S+/dataserver($|\s)" -v 53 ``` 54 55 - Extraction uses grep -Eo and takes the first token: ${COMMAND%%[[:space:]]*}.<sup>[[1]](#references)[[3]](#references)</sup> 56 - No whitelist/allowlist of trusted system paths; any discovered listener with a matching name is executed with -v/--version.<sup>[[1]](#references)[[3]](#references)</sup> 57 58 This creates an untrusted search path execution primitive: arbitrary binaries located in world-writable directories (e.g., /tmp/httpd) get executed by a privileged component.<sup>[[1]](#references)</sup> 59 60 ## Exploitation (both credential-less and credential-based modes) 61 62 Preconditions 63 - You can run an unprivileged process that opens a listening socket on the guest.<sup>[[1]](#references)</sup> 64 - The discovery job is enabled and runs periodically (historically ~5 minutes).<sup>[[1]](#references)</sup> 65 66 Steps 67 1) Stage a binary in a path matching one of the permissive regexes, e.g. /tmp/httpd or ./nginx.<sup>[[1]](#references)</sup> 68 2) Run it as a low-privileged user and ensure it opens any listening socket.<sup>[[1]](#references)</sup> 69 3) Wait for the discovery cycle; the privileged collector will automatically execute: /tmp/httpd -v (or similar), running your program as root.<sup>[[1]](#references)</sup> 70 71 Minimal demo (using NVISO’s approach).<sup>[[1]](#references)</sup> 72 ```bash 73 # Build any small helper that: 74 # - default mode: opens a dummy TCP listener 75 # - when called with -v/--version: performs the privileged action (e.g., connect to an abstract UNIX socket and spawn /bin/sh -i) 76 # Example staging and trigger 77 cp your_helper /tmp/httpd 78 chmod +x /tmp/httpd 79 /tmp/httpd # run as low-priv user and wait for the cycle 80 # After the next cycle, expect a root shell or your privileged action 81 ``` 82 83 Typical process lineage.<sup>[[1]](#references)</sup> 84 - Credential-based: /usr/bin/vmtoolsd -> /bin/sh /tmp/VMware-SDMP-Scripts-.../script_...sh -> /tmp/httpd -v -> /bin/sh -i 85 - Credential-less: /bin/sh .../get-versions.sh -> /tmp/httpd -v -> /bin/sh -i 86 87 Artifacts (credential-based) 88 Recovered SDMP wrapper scripts under /tmp/VMware-SDMP-Scripts-{UUID}/ may show direct execution of the rogue path.<sup>[[1]](#references)</sup> 89 ```bash 90 /tmp/httpd -v >"/tmp/VMware-SDMP-Scripts-{UUID}/script_-{ID}_0.stdout" 2>"/tmp/VMware-SDMP-Scripts-{UUID}/script_-{ID}_0.stderr" 91 ``` 92 93 ## Generalizing the technique: regex-driven discovery abuse (portable pattern) 94 95 Many agents and monitoring suites implement version/service discovery by: 96 - Enumerating processes with listening sockets 97 - Grepping argv/command lines with permissive regexes (e.g., patterns containing \S) 98 - Executing the matched path with a benign flag like -v, --version, -V, -h 99 100 If the regex accepts untrusted paths and the path is executed from a privileged context, you get CWE-426 Untrusted Search Path execution.<sup>[[5]](#references)</sup> 101 102 Abuse recipe for these patterns.<sup>[[1]](#references)</sup> 103 - Name your binary like common daemons that the regex is likely to match: httpd, nginx, mysqld, dataserver 104 - Place it in a writable directory: /tmp/httpd, ./nginx 105 - Ensure it matches the regex and opens any port to be enumerated 106 - Wait for the scheduled collector; you get an automatic privileged invocation of <path> -v 107 108 Masquerading note: This aligns with MITRE ATT&CK T1036.005 (Match Legitimate Name or Location) to increase match probability and stealth.<sup>[[4]](#references)</sup> 109 110 Reusable privileged I/O relay trick 111 - Build your helper so that on privileged invocation (-v/--version) it connects to a known rendezvous (e.g., a Linux abstract UNIX socket like @cve) and bridges stdio to /bin/sh -i. This avoids on-disk artifacts and works across many environments where the same binary is re-invoked with a flag.<sup>[[1]](#references)</sup> 112 113 ## Detection and DFIR guidance 114 115 Hunting queries 116 - Uncommon children of vmtoolsd or get-versions.sh such as /tmp/httpd, ./nginx, /tmp/mysqld.<sup>[[1]](#references)</sup> 117 - Any execution of non-system absolute paths by discovery scripts (look for spaces in ${COMMAND%%...} expansions).<sup>[[1]](#references)[[3]](#references)</sup> 118 - ps -ef --forest to visualize ancestry trees: vmtoolsd -> get-versions.sh -> <non-system path>.<sup>[[1]](#references)</sup> 119 120 On Aria SDMP (credential-based) 121 - Inspect /tmp/VMware-SDMP-Scripts-{UUID}/ for transient scripts and stdout/stderr artifacts showing execution of attacker paths.<sup>[[1]](#references)</sup> 122 123 Policy/telemetry 124 - Alert when privileged collectors execute from non-system prefixes: ^/(tmp|home|var/tmp|dev/shm)/ 125 - File integrity monitoring on get-versions.sh and VMware Tools plugins 126 127 ## Mitigations 128 129 - Patch: Apply Broadcom/VMware updates for CVE-2025-41244 (Tools and Aria Operations SDMP).<sup>[[2]](#references)</sup> 130 - Disable or restrict credential-less discovery where feasible.<sup>[[1]](#references)</sup> 131 - Validate trusted paths: restrict execution to allowlisted directories (/usr/sbin, /usr/bin, /sbin, /bin) and only exact known binaries 132 - Avoid permissive regexes with \S; prefer anchored, explicit absolute paths and exact command names.<sup>[[1]](#references)[[3]](#references)</sup> 133 - Drop privileges for discovery helpers where possible; sandbox (seccomp/AppArmor) to reduce impact 134 - Monitor for and alert on vmtoolsd/get-versions.sh executing non-system paths.<sup>[[1]](#references)[[3]](#references)</sup> 135 136 ## Notes for defenders and implementers 137 138 Safer matching and execution pattern 139 ```bash 140 # Bad: permissive regex and blind exec 141 COMMAND=$(get_command_line "$pid" | grep -Eo "/\\S+/nginx(\$|\\s)") 142 [ -n "$COMMAND" ] && "${COMMAND%%[[:space:]]*}" -v 143 144 # Good: strict allowlist + path checks 145 candidate=$(get_command_line "$pid" | awk '{print $1}') 146 case "$candidate" in 147 /usr/sbin/nginx|/usr/sbin/httpd|/usr/sbin/apache2) 148 "$candidate" -v 2>&1 ;; 149 *) 150 : # ignore non-allowlisted paths 151 ;; 152 esac 153 ``` 154 155 ## References 156 157 - [1] [NVISO – You name it, VMware elevates it (CVE-2025-41244)](https://blog.nviso.eu/2025/09/29/you-name-it-vmware-elevates-it-cve-2025-41244/) 158 - [2] [VMSA-2025-0015.1 – VMware Aria Operations and VMware Tools updates address multiple vulnerabilities (CVE-2025-41244, CVE-2025-41245, CVE-2025-41246) (Broadcom)](https://support.broadcom.com/web/ecx/support-content-notification/-/external/content/SecurityAdvisories/0/36149) 159 - [3] [open-vm-tools – serviceDiscovery/get-versions.sh (stable-13.0.0)](https://github.com/vmware/open-vm-tools/blob/stable-13.0.0/open-vm-tools/services/plugins/serviceDiscovery/get-versions.sh) 160 - [4] [MITRE ATT&CK T1036.005 – Match Legitimate Name or Location](https://attack.mitre.org/techniques/T1036/005/) 161 - [5] [CWE-426: Untrusted Search Path](https://cwe.mitre.org/data/definitions/426.html)