“Spotlighting” Your TCC Access Permissions

Cedric Owens
6 min readOct 30, 2021

Note: This is not a TCC Bypass. Instead this is a technique for checking TCC access permissions

As an offensive security engineer, one of the things I aim to avoid is quickly burning initial access on a host. On macOS hosts, one of the ways to do this is to try to access a TCC protected folder that your red team tool does not have access to and generate a TCC prompt to the user, immediately raising their suspicions. Example pop-up:

Not too long ago, I wrote a blog post on OPSEC safe checks that can be done to check for full disk access. Link to that blog post:

The technique/tools I posted in the blog above work great for checking for full disk access during a red team operation. However, what about instances where full disk access has NOT been granted but TCC access to specific folders has been granted? Prior to the techniques I will share in this blog post, if my full disk access check did not come back showing that I had full disk access, I would simply avoid any TCC protected folders (ex: ~/Documents, ~/Downloads, ~/Desktop, etc.) just to be safe. But what if there were useful files in those directories that would aid the red team operation? I would miss out on some potentially valuable files/data that could help us meet our red team operation objectives.

So, I began digging in and trying to figure out how I could go about enumerating what TCC permissions the Terminal app has (since some red team payloads run under Terminal’s permissions when interacting with the system) specifically for ~/Documents, ~/Desktop, and ~/Downloads (as these are often the TCC protected directories that have interesting/useful data). I used a very simple approach:

1. I opened Terminal and cleared all TCC permissions for Terminal:

% sudo tccutil reset All com.apple.Terminal

2. Then starting from the user’s home directory (~) I tried different ways of listing the directory names of ~/Documents, ~/Desktop, and ~/Downloads and noted what generated a TCC prompt and what did not. I also observed differences in output for each test when Terminal had TCC access to the specified folders versus when Terminal did not have TCC access to rule out programs that show the same result regardless of TCC permissions (which would not be helpful during a red team operation).

Examples of my tests from the user’s home directory are below:

% echo *

— → lists all 3 of the TCC protected directories above regardless of whether Terminal has any TCC folder access permissions (i.e., would not be useful for TCC folder enumeration)

% printf '%s\n' *

— → lists all 3 of the TCC protected directories above regardless of whether Terminal has any TCC folder access permissions (i.e., would not be useful for TCC folder enumeration)

% ls 

— → lists all 3 of the TCC protected directories above regardless of whether Terminal has any TCC folder access permissions (i.e., would not be useful for TCC folder enumeration)

% grep -l *

— → generates a TCC prompt when Terminal does not have any TCC permissions for protected folders (i.e., would not be useful for TCC folder enumeration)

% find .

— → Generates a TCC prompt when Terminal does not have any TCC permissions for protected folders (i.e., would not be useful for TCC folder enumeration)

In general, what I found was that any utilities that interact with the file system (ex: such as the sample I listed above) generated a TCC prompt or gave the same output regardless of TCC permissions, which wasn’t helpful for what I was hoping to achieve.

I continued running different tests and eventually found a solution: the mdfind binary! I noticed that mdfind conditionally listed ~/Documents, ~/Downloads, or ~/Desktop when run depending on the associated TCC permissions granted to Terminal. Additionally, no TCC prompts were generated! This fits the bill as the solution for my goal of remotely enumerate Terminal’s TCC permissions for ~/Desktop, ~/Downloads, and ~/Documents in an OPSEC safe manner. Yay!

Background info on why this works: mdfind queries the macOS Spotlight database as opposed to interacting directly with the file system (at least for some types of searches)…and the Spotlight database indexes various directories on the file system, including our 3 TCC protected directories of interest. The vast majority of macOS users are likely to have Spotlight indexing enabled since it is enabled by default and is a quick way to find files. But I also found that even if the user disables Spotlight indexing, this technique still works. However, in theory if the user disabled Spotlight indexing and cleared the Spotlight database prior to running this search, then this technique would not work.

Since just running mdfind with a string can be verbose, I ran mdls against a sample file to see some of the kMDItem values I could use to filter my mdfind results further. Since in my case I am really only interested in the 3 TCC protected directories I mentioned above (~/Documents, ~/Desktop, and ~/Downloads), I used the following search:

% mdfind 'kMDItemKind = Folder -onlyin /Users/[username]'

I noticed that ~/Documents, ~/Desktop, and ~/Downloads were only returned in the results if Terminal had the associated TCC access permissions for each.

I also noticed that since mdfind doesn’t generate any TCC popups I was able to pull some additional helpful info down using other kMDItem attributes:

% mdfind [keyword] -onlyin /Users/[username] 

— → Performs keyword searches to find files that match the keyword in the filename or file contents. This could be helpful for quickly finding secrets, tokens, passwords, API keys, etc.

% mdfind 'kMDItemFSName="*.*" && kMDItemFSContentChangeDate >= $time.this_week(-2)' 

— → Searches for files modified in the last 2 weeks. I filter the results returned for only files in the user’s home directory to limit the output.

% mdfind 'kMDItemFSName="*.*" && kMDItemFSCreationDate >= $time.this_week(-2)' 

— → Searches for files created in the last 2 weeks. I filter the results returned for only files in the user’s home directory to limit the output.

I wrote JXA and Swift versions of these techniques and posted them on my github at:

Sample output from the JXA TCC Checker:

  • All of the JXA scripts in this repo use the MDQuery API instead of the on disk mdfind binary and arecompatible with Mythic C2’s jsimport and jsimport_call functions to run in memory.
  • All of the Swift projects in this repo use the MDQuery API instead of the on disk mdfind binary
  • These TCC Folder checks work for any context (Terminal, app, installer package, etc.)

Detection/Hunting:

All of the Swift and JXA projects above use the MDQuery API to perform searches instead of the mdfind binary (i.e., no command line artifacts to key in on). Blue teams could leverage tools that hook into the Endpoint Security Framework and search for high volumes of reads to the Spotlight database (ex: ~/Library/Metadata/CoreSpotlight/index.spotlightV3/store.db or /System/Volumes/Data/.Spotlight-v100/STORE-v2/<UUID>/.store.db) over a very short period of time from a single source.

--

--

Cedric Owens

Red teamer with blue team roots🤓👨🏽‍💻 Twitter: @cedowens