LC_LOAD_DYLIB Addition (MITRE ATT&CK T1546.006) is a macOS persistence and privilege escalation technique that tampers with a program rather than with a startup setting.
How attackers use it
Mach-O binaries carry headers that tell the loader what to do. The LC_LOAD_DYLIB header lists the dynamic libraries (dylibs) to load at run time. MITRE explains these can be added to an already compiled binary as long as the other fields and dependencies are adjusted, and that tools exist to do it.
An adversary modifies the headers so a malicious dylib is loaded and run every time the binary runs. The change breaks the binary's digital signature, but MITRE notes this can be worked around by removing the LC_CODE_SIGNATURE command so the signature is not checked at load time.
The persistence is tied to the host program, so it runs whenever that program does.
How to detect it
MITRE's detection is a chain of events:
- File metadata changes to a binary that has no matching authorized update.
- Removal of a code signature.
- Dylib loads at run time that are unrecognized or unsigned, visible in process memory mappings.
The key discriminator is whether an update explains the change. A binary that changed on a Tuesday with no software update behind it deserves an answer.
How to reduce the risk
- Baseline libraries. Record which dynamic libraries each important binary requires. If an app needs a new library that a legitimate update did not introduce, investigate.
- Allow by hash. Use execution prevention that allows applications by known hashes.
- Enforce code signing. Require that all binaries be signed by the correct Apple Developer IDs.
Check your own environment
Read-only commands on macOS, run on a binary you want to review (replace the path):
otool -L /Applications/Example.app/Contents/MacOS/Example
codesign --verify --verbose /Applications/Example.app
The first lists the dylibs the binary will load. The second reports whether the signature is valid. Compare the library list with a known good copy of the same version.
Quick check
Why is removing LC_CODE_SIGNATURE a detection opportunity?
Editing the binary breaks its signature, and removing the signature command is how an adversary avoids the check. A once signed binary that is now unsigned, with no update behind it, stands out.