Working Around macOS Privacy Controls in Red Team Ops

Cedric Owens
5 min readJul 16, 2021

This blog post will take a look at some simple basics around what macOS privacy controls (Transparancy, Consent, and Control a.k.a. TCC) are and how red team operations on macOS hosts can still be effective despite these controls. This blog post will not cover any TCC bypasses but will instead look at working around TCC controls. If you are more interested in TCC bypasses, @theevilbit and @_r3ggi have done some great research in this area, have written several blog posts, and are also doing a talk at Black Hat 2021 on this subject.

I will (at a high level) talk about TCC controls, files that are not protected by TCC, and a simple way to check if you have full disk access without generating a TCC prompt.

High Level TCC Primer

Generally speaking, TCC was introduced in macOS Mojave with a goal of adding additional protections around personal data on macOS. These protections are in the form of a pop up window allowing the user to choose to to accept or deny a request to access a file in a TCC protected directory. Examples of places protected by TCC include:

  • ~/Documents
  • ~/Downloads
  • ~/Desktop
  • calendar
  • contacts
  • photos

A sample prompt looks like this:

The results of these “OK” or “Don’t Allow” decisions are stored in the user’s TCC database (which is how macOS “remembers” past TCC decisions on what an application bundle ID has been granted TCC permissions to):

  • ~/Library/Application Support/com.apple.TCC/TCC.db

There is also a system TCC database at /Library/Application Support/com.apple.TCC/TCC.db, but for this blog post we’ll focus on the user TCC.db above instead.

TCC.db is a sqlite3 database that you can query to view the entries by running the following command:

  • $ sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db “select * from access”

Terminal requires full disk access in order to read from the TCC.db sqlite3 file above. Later I will show how that can be used as an enumeration technique. If Terminal.app does not have full disk access, you will see the following response:

macOS also includes an on disk binary “tccutil” that can be used to reset TCC permissions. I often use this during TCC testing to see how Terminal without any TCC permissions at all would behave under certain test cases. I usually run “$sudo tccutil reset All com.apple.Terminal” but you could you use this for any application (just need the app’s bundle ID).

Now that I have covered the 10,000 ft overview of TCC, I also wanted to point out that not all macOS directories are protected by TCC. Examples of directories that are not protected include:

  • User’s base home directory (“~”)
  • Several other subdirectories outside of Desktop, Documents, and Downloads in the user’s home dir (ex: ~/.ssh, ~/.aws, ~/.azure, etc.)
  • /tmp directory
  • Several interesting files at ~/Library/Application Support/

— — — — →Interesting Chrome browser files at ~/Library/Application Support/Google/Chrome/Default (ex: Login Data database, Web Data database, History, etc.)

— — — — →Firefox cookies at ~/Library/Application Support/Firefox/Profiles/[random].default-release/cookies.sqlite

This means that Terminal would not require any TCC permissions to access the items above and would not generate any TCC pop-ups when accessing these items. Additionally any non-sandboxed macOS red team payload would be able to access the items above without needing TCC permissions. A common example of a macOS red team payload that is not sandboxed would be an installer package.

If you wanted to better understand this, I wrote a tool named “SwiftBelt” which pulls files from these directories (and others) and can be used to automate some initial access checks and data pulls. I have two implementations that you could use for testing — a Swift-based one that generates a macho-binary and a JXA (JavaScript for Automation) version:

Swift-based:

JXA-based:

SwiftBelt gathers several data sources including: zsh history, ~/.aws,~/.ssh,~/.azure content, running apps, Slack info search, Firefox cookies, etc.

For your testing:

  1. Clear the TCC database for the com.apple.Terminal bundle ID: $sudo tccutil reset All com.apple.Terminal
  2. Run either version of SwiftBelt
  3. You will see that SwiftBelt can collect the info it gathers without any TCC prompts, as the items it gathers are not protected by TCC

Enumerating Full Disk Access

So now that we’ve discussed the high level basics around TCC and how red team operations can still be effective despite TCC by accessing items not protected by TCC, now let’s talk about how after gaining initial access to macOS in a red team exercise you can determine if you have full disk access without generating a TCC pop up to the user.

Going back to the point earlier — the user’s TCC.db file requires full disk access. However it is interesting that attempts to access this file (~/Library/Application\ Support/com.apple.TCC/TCC.db) DO NOT generate a TCC prompt. So, here is a simple way to determine if Terminal has full disk access without generating any TCC pop ups:

$file ~/Library/Application\ Support/com.apple.TCC/TCC.db

IF FULL DISK ACCESS HAS NOT ALREADY BEEN GRANTED TO TERMINAL, YOU WILL RECEIVE THE FOLLOWING RESPONSE:

IF FULL DISK ACCESS HAS ALREADY BEEN GRANTED TO TERMINAL, YOU WILL RECEIVE THE FOLLOWING RESPONSE:

And there you have it! You can use this simple technique as part of your initial access checks to make a determination on how to proceed. In my case, unless I see that the command above shows that full disk access has already been granted, I will likely stay away from TCC protected directories and instead go for non TCC protected directories.

I am also looking for similar ways to check for TCC folder access to Documents and Downloads without generating a pop up, but have not yet found a way to do a similar check.

--

--

Cedric Owens

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