{
	"id": "c8985bd4-3f3e-4309-a3fe-fb23ae83cb98",
	"created_at": "2026-04-06T03:37:31.961484Z",
	"updated_at": "2026-04-10T03:20:43.908375Z",
	"deleted_at": null,
	"sha1_hash": "3452782ad1f1625827e8bc414b386eac223313fb",
	"title": "Learn XPC exploitation - Part 3: Code injections",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 955150,
	"plain_text": "Learn XPC exploitation - Part 3: Code injections\r\nBy Wojciech Reguła\r\nArchived: 2026-04-06 03:25:38 UTC\r\nXPC Exploitation series\r\nLearn XPC exploitation - Part 1: Broken cryptography\r\nLearn XPC exploitation - Part 2: Say no to the PID!\r\nLearn XPC exploitation - Part 3: Code injections\r\nIntro\r\nThe last technique I showed in my presentation during Objective by the Sea v3 conference was abusing privileged\r\nXPC services using different code injections. In many apps I exploited, I observed that developers are aware that\r\nprivileged XPC services have to verify incoming connections. Devs usually perform the validation using Apple’s\r\ncryptographic APIs - what is good 👍🏻, but… The problem is that these APIs cannot easily detect if there was any\r\nmalicious code injected to the process. In this post, I’ll show you techniques that may help you exploit a bit more\r\nsecured XPC helpers. 😉\r\nMacOS != Linux\r\nBefore I start the exploitation, I have to mention one more thing. macOS is not Linux. The ptrace syscall is not as\r\npowerful as it is in Linux. You cannot write data to the victim’s process memory using the ptrace on macOS.\r\nFor such purpose you should: 1. get the task of the victim’s app (using for instance the task_for_pid()\r\nfunction); 2. use the mach_vm_write function. I used that technique when I was exploiting iExplorer. You can\r\nread more about that here.\r\nCan I inject to other processes on macOS?\r\nTypically if you want to use the above-mentioned task_for_pid() function to retrieve old/poorly secured apps’\r\ntasks, you need to have root permissions. However, there is an exception - if the application possesses a\r\ncom.apple.security.get-task-allow entitlement set to true , you do not need the root permissions. This\r\nproblematic entitlement is usually used for debugging purposes. For example, XCode signs apps with this\r\nentitlement because it attaches the lldb. Always look for that entitlement during audits. I exploited a few apps\r\nbecause of that left entitlement.\r\nBut why I wrote that you do need root to take over the old/poorly secured apps? Well, in the modern/well-secured\r\napps, the Hardened Runtime capability is turned on. If the application was signed with the hardened runtime\r\nhttps://wojciechregula.blog/post/learn-xpc-exploitation-part-3-code-injections/\r\nPage 1 of 6\n\nflag, even if you have root permissions, you are unable to retrieve the app’s task. If you want to debug a\r\nhardened app (without the get-task-allow entitlement), you should disable the System Integrity Protection. The\r\nhardened runtime feature gives macOS some cross-app isolation.\r\nIn all new projects, the hardened runtime flag is turned on by default. In the old projects, it was enforced by Apple\r\nin the macOS Catalina. All apps that are downloaded from the Internet (outside of the App Store) are quarantined\r\nand thus need to be notarized.\r\nThe notarization enforces not only the hardened runtime but also lack of the com.apple.security.get-task-allow entitlement:\r\nhttps://wojciechregula.blog/post/learn-xpc-exploitation-part-3-code-injections/\r\nPage 2 of 6\n\nHow can I verify if the app has the hardened runtime turned on?\r\nUse the following command:\r\n$ codesign -d -vv LuLu.app\r\nExecutable=./LuLu.app/Contents/MacOS/LuLu\r\nIdentifier=com.objective-see.lulu\r\nFormat=app bundle with Mach-O thin (x86_64)\r\nCodeDirectory v=20500 size=1538 flags=0x12300(hard,kill,library-validation,runtime) hashes=39+5 location=embedde\r\nSignature size=8974\r\nAuthority=Developer ID Application: Objective-See, LLC (VBG97UB4TA)\r\nAuthority=Developer ID Certification Authority\r\nAuthority=Apple Root CA\r\nTimestamp=11 Dec 2019 at 23:49:45\r\nInfo.plist entries=24\r\nTeamIdentifier=VBG97UB4TA\r\nRuntime Version=10.14.0\r\nSealed Resources version=2 rules=13 files=12\r\nInternal requirements count=1 size=216\r\nYou can see that there is a runtime flag set.\r\nhttps://wojciechregula.blog/post/learn-xpc-exploitation-part-3-code-injections/\r\nPage 3 of 6\n\nHow can I verify if the app has get-task-allow entitlement set?\nAlso with the codesign command:\n$ codesign -d --entitlements :- GetTaskAllowTest.app\nExecutable=./GetTaskAllowTest.app/Contents/MacOS/GetTaskAllowTest\n?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\ncom.apple.security.app-sandboxcom.apple.security.files.user-selected.read-onlycom.apple.security.get-task-allow Code injection with the DYLD_INSERT_LIBRARIES\nWhen the process doesn’t have the hardened runtime capability turned on and the com.apple.security.get-task-allow entitlements are not set, the easiest way to inject your code is to use the DYLD_INSERT_LIBRARIES\nenvironment variable. There is a great article explaining how it works in details.\nTo simply exploit such an application, create an exploit.m file with the following content:\n#import __attribute__((constructor)) static void pwn(int argc, const char **argv) {\n NSLog(@\"[+] Dylib injected\");\n}\nCompile it:\ngcc -dynamiclib exploit.m -o exploit.dylib -framework Foundation\nInject to a vulnerable app:\nDYLD_INSERT_LIBRARIES=exploit.dylib ./App.app/Contents/MacOS/App\nWhat if the hardened runtime is turned on? Well, there is an entitlement that can loose the restrictions and allow\nthe DYLD_INSERT_LIBRARIES - com.apple.security.cs.allow-dyld-environment-variables . But, the runtime\nhttps://wojciechregula.blog/post/learn-xpc-exploitation-part-3-code-injections/\nPage 4 of 6\n\nwill verify if the loaded dylib is signed with the same certificate. In order to be able to inject to a hardened\r\napplication, it has to possess also the com.apple.security.cs.disable-library-validation entitlement.\r\nSumming up the code injection techniques\r\nExploiting privileged XPC services, that cryptographically validate incoming connections without the code\r\ninjection checks, can be done with following tricks:\r\nIf the application doesn’t have the hardened runtime turned on -\u003e try DYLD_INSERT_LIBRARIES\r\nIf the application has the hardened runtime turned on:\r\nlook also for the com.apple.security.get-task-allow entitlement. If it’s set to inject via\r\ntask_for_pid\r\nlook also for the pair of com.apple.security.cs.allow-dyld-environment-variables \u0026\r\ncom.apple.security.cs.disable-library-validation entitlements. If they are both set to true use\r\nthe DYLD_INSERT_LIBRARIES\r\nfind an older version of the application without the hardened runtime and use the\r\nDYLD_INSERT_LIBRARIES\r\nfind another app signed by the same developer without the hardened runtime and use the\r\nDYLD_INSERT_LIBRARIES\r\nExploitation example\r\nAn example of an application I was able to exploit using the code injection technique is LuLu - an open-source\r\nfirewall. While it had the hardened runtime turned on and was verifying the incoming XPC connections\r\ncryptographically - it wasn’t detecting code injections. So, I took KextViewr (another Objective-See’s application)\r\nthat was signed with the same developer certificate but didn’t have the hardened runtime. LuLu’s validation was\r\nverifying if the incoming XPC connection was initiated by a process that was signed with a defined certificate. So,\r\nI injected a dylib using the DYLD_INSERT_LIBRARIES technique to the KextViewr and established a valid\r\nconnection with the privileged XPC helper. It allowed me to bypass the firewall by setting my own rule without\r\nroot permissions:\r\nThe fix\r\nLuLu mitigated the vulnerability by also verifying if the bundle identifier belongs to LuLu and if the minimum\r\nversion is 1.2.0 (in that version, the hardened runtime was turned on).\r\nhttps://wojciechregula.blog/post/learn-xpc-exploitation-part-3-code-injections/\r\nPage 5 of 6\n\nBTW I wrote an open-source privileged XPC helper that may help you with securing \u0026 abusing XPC apps. 😉\r\nYou can find it here.\r\nSource: https://wojciechregula.blog/post/learn-xpc-exploitation-part-3-code-injections/\r\nhttps://wojciechregula.blog/post/learn-xpc-exploitation-part-3-code-injections/\r\nPage 6 of 6",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://wojciechregula.blog/post/learn-xpc-exploitation-part-3-code-injections/"
	],
	"report_names": [
		"learn-xpc-exploitation-part-3-code-injections"
	],
	"threat_actors": [],
	"ts_created_at": 1775446651,
	"ts_updated_at": 1775791243,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/3452782ad1f1625827e8bc414b386eac223313fb.pdf",
		"text": "https://archive.orkl.eu/3452782ad1f1625827e8bc414b386eac223313fb.txt",
		"img": "https://archive.orkl.eu/3452782ad1f1625827e8bc414b386eac223313fb.jpg"
	}
}