| name | macos-library-injection |
| description | macOS library injection and dylib hijacking analysis. Use this skill whenever the user needs to analyze macOS binaries for library injection vulnerabilities, check DYLD_INSERT_LIBRARIES restrictions, find weak linked libraries, examine rpath configurations, or test for privilege escalation via library loading. Trigger on any request about macOS dyld, library injection, dylib hijacking, dlopen hijacking, or binary security analysis. |
macOS Library Injection Analysis
A skill for analyzing macOS binaries for library injection vulnerabilities and understanding dyld behavior.
When to Use This Skill
Use this skill when:
- Analyzing macOS binaries for library injection vulnerabilities
- Checking if
DYLD_INSERT_LIBRARIES will work on a binary
- Finding weak linked libraries that could be hijacked
- Examining rpath configurations in Mach-O binaries
- Testing for privilege escalation via library loading
- Understanding macOS dyld restrictions and protections
- Auditing binaries for hardened runtime and library validation
Core Concepts
DYLD_INSERT_LIBRARIES
Similar to LD_PRELOAD on Linux, this environment variable allows loading a custom library into a process. However, Apple has significantly restricted this since 2012.
Restrictions that block DYLD_INSERT_LIBRARIES:
- Binary is setuid/setgid
- Binary has
__RESTRICT/__restrict section
- Binary has hardened runtime without
com.apple.security.cs.allow-dyld-environment-variables entitlement
Library Validation
Even if DYLD_INSERT_LIBRARIES is allowed, the binary may check library signatures. To load a custom library, the binary needs:
com.apple.security.cs.disable-library-validation entitlement
com.apple.private.security.clear-library-validation entitlement
- OR no hardened runtime flag
- OR the library is signed with the same certificate as the binary
Quick Checks
Check Binary Restrictions
codesign --display --verbose <binary>
codesign -dv --entitlements :- <binary>
ls -l <binary>
csops -status <pid>
Find Weak Linked Libraries
otool -l <binary> | grep LC_LOAD_WEAK_DYLIB -A 5
Find RPATH Configurations
otool -l <binary> | grep -E "LC_RPATH|LC_LOAD_DYLIB" -A 5
Attack Vectors
1. DYLD_INSERT_LIBRARIES Injection
Works when:
- Binary is NOT setuid/setgid
- Binary has NO
__RESTRICT section
- Binary has
com.apple.security.cs.allow-dyld-environment-variables entitlement OR no hardened runtime
- Library validation is disabled OR library is properly signed
Test:
DYLD_INSERT_LIBRARIES=/path/to/inject.dylib ./binary
2. Weak Linked Library Hijacking
Works when:
- Binary has
LC_LOAD_WEAK_DYLIB for a missing library
- Attacker can write to the expected library path
- Library validation restrictions are satisfied
Find targets:
otool -l <binary> | grep LC_LOAD_WEAK_DYLIB -A 5
3. RPATH Hijacking
Works when:
- Binary uses
@rpath in LC_LOAD_DYLIB
- One of the rpath directories is writable by attacker
- Library validation restrictions are satisfied
Note: macOS searches rpath directories in order. If a library exists in multiple paths, the first match wins.
4. Dlopen Hijacking
Search order for dlopen (no slash in name):
$DYLD_LIBRARY_PATH
LC_RPATH directories
- Current working directory (if unrestricted)
$DYLD_FALLBACK_LIBRARY_PATH
/usr/local/lib/ (if unrestricted)
/usr/lib/
Works when:
- Binary is unrestricted (no setuid, no CS_RESTRICT)
- Attacker can write to one of the search paths
- Library validation restrictions are satisfied
5. Relative Path Hijacking
Works when:
- Privileged binary loads library via relative path (
@executable_path, @loader_path)
- Library validation is disabled
- Attacker can move the binary or write to the relative path
Testing Scripts
Use the bundled scripts for automated analysis:
scripts/check_binary_restrictions.sh - Check all restriction flags
scripts/find_weak_libraries.sh - Find weak linked libraries
scripts/find_rpath_configs.sh - Find rpath configurations
scripts/test_dyld_injection.sh - Test DYLD_INSERT_LIBRARIES
Common Patterns
SUID Binary Testing
sudo chown root <binary>
sudo chmod +s <binary>
DYLD_INSERT_LIBRARIES=inject.dylib ./binary
sudo chmod -s <binary>
Hardened Runtime Testing
codesign -s <cert-name> --option=runtime ./binary
codesign -f -s <cert-name> --option=library ./binary
codesign -f -s <cert-name> inject.dylib
codesign -f -s <cert-name> --option=restrict ./binary
Creating Test Binary with __RESTRICT Section
gcc -sectcreate __RESTRICT __restrict /dev/null hello.c -o hello-restrict
Important Notes
-
Environment Variable Pruning: DYLD_* and LD_LIBRARY_PATH are removed for restricted binaries by pruneEnvironmentVariables() in dyld
-
Library Validation: Even if injection is allowed, library signatures may be checked. The library must be signed with the same certificate as the binary, or the binary must have library validation disabled
-
Universal Binaries: macOS uses universal files combining 32-bit and 64-bit libraries. There are no separate search paths for different architectures
-
Dyld Cache: Most OS dylibs are combined into the dyld cache and don't exist on disk. Use dlopen_preflight() instead of stat() to check if a dylib exists
-
Setuid/SGID: These binaries always have environment variables pruned and are highly restricted
-
CS_RESTRICT Flag: Can be applied dynamically at execution time even if not present in the binary's signature
References