Skip to main content

DYLD_INSERT_LIBRARIES Injection

Many elements of access control depond on the app's signature, especially the embedded entitlements, therefore process injection is important. 

 

Injecting a dylib into an application could run in the app's context, which provides us rights that we do not have before. This technique will be used frequently in other exploitation. 

 

DYLD_INSERT_LIBRARIES injection is similar to LD_PRELOAD in Linux. DYLD_INSERT_LIBRARIES is an environment variable that instructs the dyld dynamic library loader to load any dylib before the main app starts. The variable should contain a list of dylibs to be loaded before the program starts. 

 

 

Example 

__attribute__((constructor)) is a GCC specific syntax that instructs the compiler to treat the next function as a constructor. When the dynamic loader loads the compiled binary, it will run the function specified under the constructor. 

In order to set the environment variable for the app to be executed, we have to specify DYLD_INSERT_LIBRARIES= and the path to the dylib in the cmdline. 

The constructor is called before the main app. 

 

And it works on real world app. 

 

 

We can also use syslog to observe log output: 

log stream --style syslog --predicate 'eventMessage CONTAINS[c] "constructor"' 

Log all event messages containing the constructor word in the message body. 

 

This technique only needs a dylib, and simply setting an environment variable, we can achieve code execution in the context of another app. However, it has some limitations. 

 

Apple added restrictions to the use of the environment variable, i.e. the loader will ignore the env var. 

Review old dyld source code, env vars are ignore through their removal during the load process. The following function is responsible for removing env vars. 

In summary, the following conditions ignore env vars 

  1. The main executable has SUID or GUID 

  2. The main executable has __RESTRICT section 

  3. Code signed with entitlements 

 

Function hasRestrictedSegment parses the Mach-O file for the LC_SEGMENT_COMMAND load command and looks for a __RESTRICT segment. 

 

SYS_csops is the SSN of csopscode signing operations. 

Code signing flag: 

 

In newer dylb source code 

 

issetguid() and hasRestrictedSegment are also called. Beside, SIP status is checked, which is done by csr_check. 

SIP is internally controlled through NVRAM variables, which will be mapped to a variable called csrActiveConfig. It can be treated as a bitmask. 

csrActiveConfig is a member of structure boot_args in platform export module in XNU, which is responsible for the hardware abstraction layer. 

boot_args can be located from structure PE_state in pexpert.h. 

 

In summary: 

  1. The main executable has a restricted segment 

  2. SUID/GUID is set 

  3. SIP is enabled and the program has the CS_RESTRICT flag 

 

Newer version of macOS offers developers with more options, such as hardened runtime code-signing flag. 

Meanwhile, they can disable some hardened runtime protections, such as adding com.apple.security.cs.allow-dyld-environment-variables entitlement to enable DYLD environment variables. Or com.apple.security.cs.disable-library-validation entitlement to disable library validation. They are managed by AppleMobileFileIntegrity(AMFI), not dyld. 

  

 

 

AMFI 

AMFI is a kernel extension that was originally introduced in IOS. It extends MACF(Mandatory Access Control Framework) and plays a key role in enforcing SIP and code signing. 

BUILD_FOR_TESTING checks if dyld was built with the build-for-testing compiler flag. In prod, it is not set. 

internalInstall function check whether the SIP-related CSR_ALLOW_APPLE_INTERNAL flag is set by calling the csr_check function. It always return FALSE on default installations. 

_amfi_check_dyld_policy_self is a wrapper around __sandbox_ms, while __sandbox_ms is a wrapper for the __mac_syscall system call. 

__mac_syscall allows us to create an ioctl type system call for one of the policy modules registered in the MACF. 

The policy selector is AMFI, the ioctl code is 0x5a. 

The flag value is 0x5f 

 

During MAC registration, the MAC policy module registers itself with the kernel by passing its name and the various functions it implements. 

 

mpc_ops is a pointer to a mac_policy_ops structure, it contains several additional pointers. 

 

 

 

…(Skip the following code review) 

 

 

Verification 

Adding a restrict section prevents the injection. 

 

Create a cert: