VMware Tools ์„œ๋น„์Šค ๊ฒ€์ƒ‰ LPE (CWE-426) - regex ๊ธฐ๋ฐ˜ ๋ฐ”์ด๋„ˆ๋ฆฌ ๊ฒ€์ƒ‰ ์ทจ์•ฝ์  (CVE-2025-41244)

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

์ด ๊ธฐ๋ฒ•์€ ์‹คํ–‰ ์ค‘์ธ ํ”„๋กœ์„ธ์Šค์˜ ๋ช…๋ น์ค„์„ ํŒŒ์‹ฑํ•˜์—ฌ ์„œ๋น„์Šค ๋ฒ„์ „์„ ์ถ”๋ก ํ•œ ๋’ค ํ›„๋ณด ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ โ€œversionโ€ ํ”Œ๋ž˜๊ทธ๋กœ ์‹คํ–‰ํ•˜๋Š” regex ๊ธฐ๋ฐ˜์˜ service discovery ํŒŒ์ดํ”„๋ผ์ธ์„ ์•…์šฉํ•ฉ๋‹ˆ๋‹ค. ํ—ˆ์šฉ์ ์ธ ํŒจํ„ด์ด /tmp/httpd ๊ฐ™์€ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ ํ—ˆ์šฉํ•˜๋ฉด, ๊ถŒํ•œ ์žˆ๋Š” ์ˆ˜์ง‘ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹ ๋ขฐ๋˜์ง€ ์•Š์€ ์œ„์น˜์˜ ์ž„์˜ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ๋กœ์ปฌ ๊ถŒํ•œ ์ƒ์Šน์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. NVISO๋Š” ์ด๋ฅผ VMware Tools/Aria Operations Service Discovery์—์„œ CVE-2025-41244๋กœ ๋ฌธ์„œํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • Impact: Local privilege escalation to root (or to the privileged discovery account)
  • Root cause: Untrusted Search Path (CWE-426) + permissive regex matching of process command lines
  • Affected: open-vm-tools/VMware Tools on Linux (credential-less discovery), VMware Aria Operations SDMP (credential-based discovery via Tools/proxy)

How VMware service discovery works (high level)

  • Credential-based (legacy): Aria๊ฐ€ ๊ตฌ์„ฑ๋œ ๊ถŒํ•œ ์žˆ๋Š” ์ž๊ฒฉ์ฆ๋ช…์„ ์‚ฌ์šฉํ•ด VMware Tools๋ฅผ ํ†ตํ•ด ๊ฒŒ์ŠคํŠธ ๋‚ด๋ถ€์—์„œ discovery ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • Credential-less (modern): Discovery ๋กœ์ง์ด ์ด๋ฏธ ๊ฒŒ์ŠคํŠธ ๋‚ด์—์„œ ๊ถŒํ•œ์„ ๊ฐ€์ง„ VMware Tools ๋‚ด์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

๋‘ ๋ชจ๋“œ ๋ชจ๋‘ ๊ถ๊ทน์ ์œผ๋กœ ๋ฆฌ์Šค๋‹ ์†Œ์ผ“์ด ์žˆ๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ์Šค์บ”ํ•˜๊ณ , ์ •๊ทœ์‹์œผ๋กœ ์ผ์น˜ํ•˜๋Š” ๋ช…๋ น ๊ฒฝ๋กœ๋ฅผ ์ถ”์ถœํ•œ ๋’ค ์ฒซ ๋ฒˆ์งธ argv ํ† ํฐ์„ ๋ฒ„์ „ ํ”Œ๋ž˜๊ทธ์™€ ํ•จ๊ป˜ ์‹คํ–‰ํ•˜๋Š” ์…ธ ๋กœ์ง์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Root cause and vulnerable pattern (open-vm-tools)

open-vm-tools์—์„œ serviceDiscovery ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šคํฌ๋ฆฝํŠธ get-versions.sh๋Š” ๋„“์€ ์ •๊ทœ์‹์„ ์‚ฌ์šฉํ•ด ํ›„๋ณด ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ๋งค์นญํ•˜๊ณ , trusted-path ๊ฒ€์ฆ ์—†์ด ์ฒซ ๋ฒˆ์งธ ํ† ํฐ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

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
}

์ด๋Š” \S (๊ณต๋ฐฑ์ด ์•„๋‹Œ ๋ฌธ์ž)๋ฅผ ํฌํ•จํ•œ ๊ด€๋Œ€ํ•œ ํŒจํ„ด์œผ๋กœ ํ˜ธ์ถœ๋˜์–ด ์‚ฌ์šฉ์ž ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ์œ„์น˜์— ์žˆ๋Š” ๋น„์‹œ์Šคํ…œ ๊ฒฝ๋กœ์™€ ์‰ฝ๊ฒŒ ๋งค์น˜๋ฉ๋‹ˆ๋‹ค:

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 "\.?/\S*nginx($|\s)" -v
get_version "/\S+/srm/bin/vmware-dr($|\s)" --version
get_version "/\S+/dataserver($|\s)" -v
  • ์ถ”์ถœ์€ grep -Eo๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์ฒซ ํ† ํฐ์„ ์ทจํ•จ: ${COMMAND%%[[:space:]]*}
  • ์‹ ๋ขฐ๋œ ์‹œ์Šคํ…œ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ whitelist/allowlist๊ฐ€ ์—†์Œ; ์ผ์น˜ํ•˜๋Š” ์ด๋ฆ„์˜ ๋ฐœ๊ฒฌ๋œ listener๋Š” -v/โ€“version์œผ๋กœ ์‹คํ–‰๋จ

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.

Exploitation (both credential-less and credential-based modes)

Preconditions

  • ๊ฒŒ์ŠคํŠธ์—์„œ listening socket์„ ์—ฌ๋Š” unprivileged ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•จ.
  • discovery job์ด ํ™œ์„ฑํ™”๋˜์–ด ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜์–ด์•ผ ํ•จ (๊ณผ๊ฑฐ์—๋Š” ์•ฝ 5๋ถ„).

Steps

  1. ํ—ˆ์šฉ์ ์ธ regex ์ค‘ ํ•˜๋‚˜์™€ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ๋กœ์— ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์Šคํ…Œ์ด์ง•(๋ฐฐ์น˜), ์˜ˆ: /tmp/httpd ๋˜๋Š” ./nginx
  2. ์ €๊ถŒํ•œ ์‚ฌ์šฉ์ž๋กœ ์‹คํ–‰ํ•˜๊ณ  ์–ด๋–ค listening socket์ด๋ผ๋„ ์—ด๋„๋ก ํ™•์ธ
  3. discovery cycle์„ ๊ธฐ๋‹ค๋ ค๋ผ; privileged collector๊ฐ€ ์ž๋™์œผ๋กœ ์‹คํ–‰ํ•จ: /tmp/httpd -v (๋˜๋Š” ์œ ์‚ฌ), ๋‹น์‹ ์˜ ํ”„๋กœ๊ทธ๋žจ์„ root๋กœ ์‹คํ–‰

Minimal demo (using NVISOโ€™s approach)

# Build any small helper that:
#  - default mode: opens a dummy TCP listener
#  - when called with -v/--version: performs the privileged action (e.g., connect to an abstract UNIX socket and spawn /bin/sh -i)
# Example staging and trigger
cp your_helper /tmp/httpd
chmod +x /tmp/httpd
/tmp/httpd          # run as low-priv user and wait for the cycle
# After the next cycle, expect a root shell or your privileged action

์ผ๋ฐ˜์ ์ธ ํ”„๋กœ์„ธ์Šค ๊ณ„๋ณด

  • Credential-based: /usr/bin/vmtoolsd -> /bin/sh /tmp/VMware-SDMP-Scripts-โ€ฆ/script_โ€ฆsh -> /tmp/httpd -v -> /bin/sh -i
  • Credential-less: /bin/sh โ€ฆ/get-versions.sh -> /tmp/httpd -v -> /bin/sh -i

์•„ํ‹ฐํŒฉํŠธ (์ž๊ฒฉ ์ฆ๋ช… ๊ธฐ๋ฐ˜) /tmp/VMware-SDMP-Scripts-{UUID}/ ์•„๋ž˜์—์„œ ๋ณต๊ตฌ๋œ SDMP ๋ž˜ํผ ์Šคํฌ๋ฆฝํŠธ๋Š” ์•…์„ฑ ๊ฒฝ๋กœ๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

/tmp/httpd -v >"/tmp/VMware-SDMP-Scripts-{UUID}/script_-{ID}_0.stdout" 2>"/tmp/VMware-SDMP-Scripts-{UUID}/script_-{ID}_0.stderr"

๊ธฐ๋ฒ• ์ผ๋ฐ˜ํ™”: regex-driven discovery abuse (portable pattern)

๋งŽ์€ ์—์ด์ „ํŠธ์™€ ๋ชจ๋‹ˆํ„ฐ๋ง ์Šค์œ„ํŠธ๋Š” ๋ฒ„์ „/์„œ๋น„์Šค ๊ฒ€์ƒ‰์„ ๋‹ค์Œ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค:

  • ๋ฆฌ์Šค๋‹ ์†Œ์ผ“์„ ๊ฐ€์ง„ ํ”„๋กœ์„ธ์Šค ์—ด๊ฑฐ
  • argv/command lines๋ฅผ ํ—ˆ์šฉ์ ์ธ regex๋กœ Grepping(์˜ˆ: \S๋ฅผ ํฌํ•จํ•˜๋Š” ํŒจํ„ด)
  • ์ผ์น˜ํ•œ ๊ฒฝ๋กœ๋ฅผ -v, โ€“version, -V, -h ๊ฐ™์€ ๋ฌดํ•ดํ•œ ํ”Œ๋ž˜๊ทธ๋กœ ์‹คํ–‰

๋งŒ์•ฝ regex๊ฐ€ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ๋กœ๋ฅผ ํ—ˆ์šฉํ•˜๊ณ  ๊ทธ ๊ฒฝ๋กœ๊ฐ€ ๊ถŒํ•œ ์žˆ๋Š” ์ปจํ…์ŠคํŠธ์—์„œ ์‹คํ–‰๋˜๋ฉด, CWE-426 Untrusted Search Path execution์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์•…์šฉ ๋ฐฉ๋ฒ•

  • ๋ฐ”์ด๋„ˆ๋ฆฌ ์ด๋ฆ„์„ regex๊ฐ€ ๋งค์นญํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ์ผ๋ฐ˜์ ์ธ ๋ฐ๋ชฌ ์ด๋ฆ„์ฒ˜๋Ÿผ ์ง€์ •: httpd, nginx, mysqld, dataserver
  • ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ๋””๋ ‰ํ† ๋ฆฌ์— ๋ฐฐ์น˜: /tmp/httpd, ./nginx
  • regex์— ๋งค์นญ๋˜๊ณ  ์—ด๊ฑฐ๋˜๋„๋ก ์ž„์˜์˜ ํฌํŠธ๋ฅผ ์˜คํ”ˆํ•˜๋„๋ก ๋ณด์žฅ
  • ์Šค์ผ€์ค„๋œ ์ˆ˜์ง‘๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉด ์ž๋™์œผ๋กœ ๊ถŒํ•œ ์žˆ๋Š” -v ํ˜ธ์ถœ์„ ์–ป์Œ

Masquerading note: This aligns with MITRE ATT&CK T1036.005 (Match Legitimate Name or Location) to increase match probability and stealth.

์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ถŒํ•œ ์žˆ๋Š” I/O ๋ฆด๋ ˆ์ด ๊ธฐ๋ฒ•

  • ํ—ฌํผ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๊ถŒํ•œ ์žˆ๋Š” ํ˜ธ์ถœ(-v/โ€“version) ์‹œ ์•Œ๋ ค์ง„ rendezvous(์˜ˆ: @cve ๊ฐ™์€ Linux abstract UNIX socket)์— ์—ฐ๊ฒฐํ•˜๊ณ  stdio๋ฅผ /bin/sh -i๋กœ ๋ธŒ๋ฆฌ์ง€ํ•˜๋„๋ก ๋งŒ๋“œ์„ธ์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋””์Šคํฌ์— ๋‚จ๋Š” ์•„ํ‹ฐํŒฉํŠธ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๊ณ  ๋™์ผํ•œ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ํ”Œ๋ž˜๊ทธ์™€ ํ•จ๊ป˜ ๋‹ค์‹œ ํ˜ธ์ถœ๋˜๋Š” ๋งŽ์€ ํ™˜๊ฒฝ์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

Detection and DFIR guidance

ํ—ŒํŒ… ์ฟผ๋ฆฌ

  • vmtoolsd ๋˜๋Š” get-versions.sh์˜ ํ”์น˜ ์•Š์€ ์ž์‹ ํ”„๋กœ์„ธ์Šค ์˜ˆ: /tmp/httpd, ./nginx, /tmp/mysqld
  • discovery scripts์— ์˜ํ•ด ์‹คํ–‰๋œ ๋น„์‹œ์Šคํ…œ ์ ˆ๋Œ€ ๊ฒฝ๋กœ( ${COMMAND%%โ€ฆ} ํ™•์žฅ ๋‚ด์˜ ๊ณต๋ฐฑ์„ ์ฐพ์•„๋ณด์„ธ์š” )
  • ps -ef โ€“forest๋กœ ์กฐ์ƒ ํŠธ๋ฆฌ ์‹œ๊ฐํ™”: vmtoolsd -> get-versions.sh ->

Aria SDMP(credential-based)์—์„œ

  • /tmp/VMware-SDMP-Scripts-{UUID}/๋ฅผ ๊ฒ€์‚ฌํ•˜์—ฌ ์ผ์‹œ์  ์Šคํฌ๋ฆฝํŠธ์™€ stdout/stderr ์•„ํ‹ฐํŒฉํŠธ์—์„œ ๊ณต๊ฒฉ์ž ๊ฒฝ๋กœ ์‹คํ–‰ ํ”์ ์„ ํ™•์ธ

์ •์ฑ…/telemetry

  • ๊ถŒํ•œ ์žˆ๋Š” ์ˆ˜์ง‘๊ธฐ๊ฐ€ ๋น„์‹œ์Šคํ…œ ์ ‘๋‘์‚ฌ์—์„œ ์‹คํ–‰๋˜๋ฉด ๊ฒฝ๋ณด: ^/(tmp|home|var/tmp|dev/shm)/
  • get-versions.sh ๋ฐ VMware Tools plugins์— ๋Œ€ํ•œ ํŒŒ์ผ ๋ฌด๊ฒฐ์„ฑ ๋ชจ๋‹ˆํ„ฐ๋ง

Mitigations

  • Patch: CVE-2025-41244(Tools ๋ฐ Aria Operations SDMP)์— ๋Œ€ํ•œ Broadcom/VMware ์—…๋ฐ์ดํŠธ ์ ์šฉ
  • ์ž๊ฒฉ ์ฆ๋ช… ์—†์ด ์‹คํ–‰๋˜๋Š” discovery๋ฅผ ๊ฐ€๋Šฅํ•˜๋ฉด ๋น„ํ™œ์„ฑํ™”ํ•˜๊ฑฐ๋‚˜ ์ œํ•œ
  • ์‹ ๋ขฐ๋œ ๊ฒฝ๋กœ ๊ฒ€์ฆ: ์‹คํ–‰์„ ํ—ˆ์šฉ๋œ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ œํ•œ(/usr/sbin, /usr/bin, /sbin, /bin)ํ•˜๊ณ  ์ •ํ™•ํžˆ ์•Œ๋ ค์ง„ ๋ฐ”์ด๋„ˆ๋ฆฌ๋งŒ ํ—ˆ์šฉ
  • \S ๊ฐ™์€ ํ—ˆ์šฉ์ ์ธ regex ํšŒํ”ผ; ์•ต์ปค๋œ(explicit) ์ ˆ๋Œ€ ๊ฒฝ๋กœ์™€ ์ •ํ™•ํ•œ ๋ช…๋ น ์ด๋ฆ„์„ ์„ ํ˜ธ
  • discovery ํ—ฌํผ์˜ ๊ถŒํ•œ์„ ๊ฐ€๋Šฅํ•œ ํ•œ ๋‚ฎ์ถ”๊ณ , ์˜ํ–ฅ ๊ฐ์†Œ๋ฅผ ์œ„ํ•ด sandbox(seccomp/AppArmor) ์ ์šฉ
  • vmtoolsd/get-versions.sh๊ฐ€ ๋น„์‹œ์Šคํ…œ ๊ฒฝ๋กœ๋ฅผ ์‹คํ–‰ํ•˜๋Š”์ง€ ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ๊ฒฝ๋ณด

Notes for defenders and implementers

๋” ์•ˆ์ „ํ•œ ๋งค์นญ ๋ฐ ์‹คํ–‰ ํŒจํ„ด

# Bad: permissive regex and blind exec
COMMAND=$(get_command_line "$pid" | grep -Eo "/\\S+/nginx(\$|\\s)")
[ -n "$COMMAND" ] && "${COMMAND%%[[:space:]]*}" -v

# Good: strict allowlist + path checks
candidate=$(get_command_line "$pid" | awk '{print $1}')
case "$candidate" in
/usr/sbin/nginx|/usr/sbin/httpd|/usr/sbin/apache2)
"$candidate" -v 2>&1 ;;
*)
: # ignore non-allowlisted paths
;;
esac

์ฐธ๊ณ ์ž๋ฃŒ

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ