Load & Execute Bundles with migrationTool

MacOS contains several hundred native and signed libraries within the /System/Library/PrivateFrameworks directory. Apple provides little documentation in regards to the APIs provided by these frameworks. This makes it difficult to explore any potential for abuse, but they should be investigated nonetheless. Abusing these private libraries for code execution can allow an attacker to blend in with noise and possibly evade detection. In particular, the SystemMigration framework contains a helper macho executable called migrationTool, that will execute an unsigned bundle in the context of the migrationTool process. This macho is essentially the command line equivalent of the migration assistant, the application responsible for transferring user data between devices.


Figure 1: MigrationTool Help Output for the executePlugin Flag

A bundle is a directory that contains a collection of executable code and their resources. Bundles can be loaded into an application to obtain additional functionality. For information on bundle files, please look here. Next we’ll demonstrate how to create a bundle/plugin for the migrationTool that opens the calculator app and another bundle to launch an Empire agent.

Creating a Migration Plugin

To create a migration plugin, open the Xcode application, start a new project, and select the bundle template. For this example our bundle will simply open the Calculator application. You’ll find the example code here.

Example Plugin

Figure 2: Example Plugin Code

You’ll notice that on line 11 we are importing a header file called SMConfMigratorPlugin.h. That file is from the SystemMigration private framework. We can obtain header files for any given macho using the class-dump tool. This is an excellent tool for gaining insight into the classes used in a private framework. Use the following command to dump all of the header files from the SystemMigrationframework:

class-dump -H -o <Destination Folder> </path/to/macho>. 

Next, copy the SMConfMigratorPlugin.h file into your project directory. Additionally, you will also need to add a reference to the SystemMigration framework because the header file contains the class definition but not its implementation. Navigate to the projects’ general settings, and add the SystemMigration framework by clicking the ‘+’ button under “Linked Frameworks and Libraries”. In the next window, select “Add Other” and navigate to the PrivateFrameworks directory. Select the SystemMigration framework and click open.


Figure 3: Adding a Framework Reference in XCode

Now the project should successfully build and the resulting file will be saved to the products folder. Copy the bundle to any other location and change its owner to root. This is one of the requirements for the bundle to work with migrationTool. If you plan to execute the bundle on a compromised host, unfortunately, you will need root privileges to change the file’s ownership. Now, we use the bundle as our plugin for the migrationTool.

Run the following command to execute the custom plugin:

/System/Library/PrivateFrameworks/SystemMigration.framework/Versions/A/Resources/migrationTool --disableIdleExit --executePlugin /Users/debug/Desktop/testExampleBundle.bundle

Offensive Application - Google Santa Bypass

So, why would this be useful for an attacker? If our goal is to blend in with the noise and leverage native binaries for code execution, the migrationTool offers just that. Ideally, operators avoid dropping binaries to disk during red team engagements. However, the benefits of loading a malicious payload into a signed and native binary may outweigh the risks of dropping a single bundle to disk.

Additionally, this can also be used to bypass application whitelisting solutions such as Santa. Santa is an open-source application whitelisting solution for macOS, developed by Google. Santa can be deployed in monitor or lockdown mode. In monitor mode, all unknown binaries (except blacklisted) are permitted to run. In lockdown mode, only binaries that match either the certificate-based or hash-based rules are permitted to run. Regardless of the mode, Santa will log all binary launch events. The one drawback for Santa is that it is unable to block or monitor load events via the dlopen function. To demonstrate migrationTool’s usefulness against an application whitelisting solution, please see the video below. In this example, Santa has been configured to only allow execution of binaries signed by Apple. Ideally, a migration plugin could be utilized to execute a post-exploitation capability, such as keylogging or taking a screenshot.


For detections, a simple rule based on execution of the migrationTool with the –executePlugin argument should serve as a good starting point. This binary has a specific use case and should not be used in day-to-day activities for the average user. We can use osquery for process auditing on macOS. This feature requires editing the audit_control file in /etc/security directory and adding the –disable_audit=false and –allow_audit_config=true flags to /var/osquery/osquery.flags. For additional information on configuring process auditing with osquery, please look here. For this example, we will use a simple query for viewing entries in the process_events table: SELECT * FROM process_events. Place this query in your osquery config file. Adjust your query to be as specific as necessary. Restart the osquery service and execute the custom bundle via the migrationTool. This will create an entry in the osquery results file once the interval for our query has elapsed.

OSquery Result

Figure 4: OSquery simple process query result

Once your query has been fine tuned, you should readily be able to detect usage of the migrationTool. Hopefully this post encourages other OSX security enthusiasts to explore the libraries within the PrivateFrameworks directory for post-exploitation opportunities.

Written by Chris Ross on 25 May 2018