For Red Team members who are already familiar with Linux, there may be some confusion about using a Mac. Many people believe that macOS and Linux are very similar operating systems, and in many ways, they are. Both are built on Unix-like principles and rely on the command line interface for much of their functionality.
However, once you move beyond the bash/zsh prompt, macOS becomes a very different beast. It has layers of security and proprietary frameworks that Linux doesn’t have. It is not just “Linux with a better UI.” It is Darwin, a BSD-derivative with a Mach microkernel, wrapped in proprietary Apple frameworks.
In this guide, we will bridge the gap. We will cover the “BSD Trap” that catches Linux users, the nightmare of TCC (Transparency, Consent, and Control), and how to persist and execute code using Apple’s unique “Living off the Land” binaries.
1. The Core: Darwin and the BSD Heritage
macOS is built on Darwin, an open-source Unix-like operating system that combines the XNU kernel with a BSD-based userland. This is the first trap for Linux users: macOS is BSD-based, not GNU-based.
Command Line Differences (GNU vs. BSD)
As a red teamer, your shell scripts will break if you assume GNU behavior.
sed: On Linux,sed -i 's/foo/bar/g' fileworks. On macOS, you must provide an empty string for the backup extension:sed -i '' 's/foo/bar/g' file.ps: Linux uses standardps aux. macOS prefers BSD flags likeps -ax -o pid,user,comm.netstat: Modern macOS has mostly deprecatednetstatfor process-to-port mapping. Uselsof -iTCP -sTCP:LISTEN -n -Pinstead.grep: The macOS version ofgrepdoes not support-P(Perl Compatible Regex) by default. Use-Efor extended regex.base64: macOS usesbase64 -i input -o output. Linux usesbase64 input > output.
2. The Security Boundaries: TCC and SIP
On Linux, root is god. On macOS, even root is restricted. This is the single most important thing for an offensive operator to understand.
SIP (System Integrity Protection)
SIP prevents even the root user from modifying certain system directories (like /System, /bin, /sbin). It also prevents “code injection” into system processes via task_for_pid unless the binary is signed by Apple with specific entitlements.
- Checking SIP:
csrutil status. - Implication: You cannot simply drop a rootkit into
/System/Library/Extensions. You are restricted to/Libraryor~/Libraryor/usr/local.
TCC (Transparency, Consent, and Control)
TCC is the “sandbox” that prompts you for permission to access the camera, microphone, or “Full Disk Access” (FDA).
- The Problem: Even if you have a root shell via SSH, if you try to
ls ~/Documents, the command might fail (Operation not permitted) or hang while a GUI prompt appears on the user’s desktop—tipping them off immediately. - The Database: TCC permissions are stored in SQLite databases protected by SIP.
- System:
/Library/Application Support/com.apple.TCC/TCC.db - User:
~/Library/Application Support/com.apple.TCC/TCC.db
- System:
- Red Team Strategy: Don’t attack TCC directly. Attack the apps that have TCC rights. If
Terminal.apphas Full Disk Access, running commands inside it inherits those rights.
3. Keychain Access: The Vault of Secrets
macOS stores passwords, certificates, and keys in the Keychain. For an offensive operator, this is the primary target for credential harvesting.
Dumping the Keychain via CLI
If you know the user’s login password (or have a keylogger), you can use the built-in security tool.
| |
[!WARNING] Accessing the Keychain often triggers a GUI prompt asking the user for permission to allow
securityto access the key. This is a OpSec risk.
The “Dump-All” Strategy
Tools like Chainbreaker can parse the .keychain-db files directly from ~/Library/Keychains/ if you can extract the master key. This usually requires root privileges to read the system keys.
4. Persistence: LaunchDaemons and LaunchAgents
While cron still exists on macOS (for now), the professional way to persist is via launchd.
- LaunchDaemons (
/Library/LaunchDaemons): Run as root at boot. Used for system-wide persistence. - LaunchAgents (
~/Library/LaunchAgents): Run as the user at login. Used for user-land persistence.
Creating a Persistent Agent
Create a plist file (e.g., com.apple.update.helper.plist):
| |
Load it:
| |
5. Living off the Land: JXA and AppleScript
macOS has a unique automation layer called OSA (Open Scripting Architecture). You can script almost any application using AppleScript or JavaScript for Automation (JXA).
JXA (JavaScript for Automation)
JXA allows you to use JavaScript syntax to bridge into native Objective-C (“Cocoa”) APIs. This allows for powerful in-memory execution without dropping binaries.
Example: Reading a file using ObjC bridge
| |
AppleScript Phishing
You can invoke native-looking dialog boxes to steal passwords.
| |
6. The “Quarantine” Flag: Gatekeeper
When you download a file via a browser, macOS adds the com.apple.quarantine extended attribute (xattr). This triggers Gatekeeper and Notarization checks.
If you curl or wget a binary, the flag is usually not added. However, unzipping a file via Finder might propagate the flag.
Removing the Mark of the Beast:
| |
Always perform this step on any binary you upload before trying to execute it.
7. macOS Post-Exploitation Tools
If you find yourself on a Mac and need to escalate or pivot:
- Mythic (Poseidon / Apfell): A robust C2 framework with macOS-specific agents written in Go and JXA.
- SwiftBelt: An enumeration tool inspired by Seatbelt, written in Swift to avoid command-line logging.
- Basic Recon:
system_profiler SPSoftwareDataType: OS Version.dscl . list /Users: List local users.scutil --proxy: Check proxy settings.
Conclusion
macOS requires a shift in mindset. You are not fighting just file permissions; you are fighting Entitlements, TCC transparency, and a hardened kernel. To succeed, you must stop thinking like a sysadmin and start thinking like a macOS developer who knows how to bend launchd, JXA, and Apple Events to their will.
Happy hunting!