Where in the World is Carmen Sandiego: Abusing Location Services on macOS

Justin Bui
8 min readDec 1, 2021

Introduction

This blogpost will describe the concept of Location Services on macOS and how an attacker can utilize the Core Location APIs to track the geographical location of their targets. This technique is mapped to MITRE ATT&CK under System Location Discovery (T1614).

Recently, I have been diving into understanding Transparency, Consent, and Control (TCC) on macOS. TCC is a control that limits an application’s ability to interact with various services on the operating system. It controls access to services such as camera, microphone, contacts, photos, folders on disc, location services, and more. If you want to know more about TCC, I highly recommend you read this blogpost by Keith Johnson.

While looking for bugs in TCC, I needed to write a proof-of-concept (POC) application that attempted to access the user’s location. This blogpost details what I learned about Location Services, how it works, the journey that took me there, and a tool release.

Transparency, Consent, and Control (TCC)

To lay down some baseline knowledge about TCC, here is a quote from Keith’s post:

TCC (Transparency, Consent, and Control) is a mechanism in macOS to limit and control application access to certain features, usually from a privacy perspective. This can include things such as location services, contacts, photos, microphone, camera, accessibility, full disk access, and a bunch more. TCC was introduced with OSX Mavericks and has gone through a number of changes since to expand what it has control over. TCC also appears to exist and provide the same functionality on iOS …
- Keith Johnson (source)

Security & Privacy UI

So how does a user manage TCC? This can be done from System Preferences -> Security & Privacy. From here, a user can unlock the Security & Privacy UI with administrator credentials and grant/deny applications access to various TCC-protected services.

Below, you’ll see the left column shows TCC-protected services and the right column shows the associated applications that are allowed to interact with that particular service.

Security & Privacy UI

TCC Prompts

The operating system can prompt the user to allow applications to access TCC-protected services. The user’s choice will be reflected in the Security & Privacy UI.

Zoom Application Requesting Camera Access

tccutil

Apple also provides a command line tool (tccutil) to reset TCC permissions for a TCC-protected service, a specific application (by bundle ID), or all TCC-protected services. Resetting TCC permissions requires root or sudo permissions.

### Reset all permissions for a single TCC-protected service.
### All applications previously granted Microphone access will be
### revoked
$ sudo tccutil reset Microphone### Reset all permissions for a single application identified by
### bundle ID. All permissions previously granted to Safari will be
### revoked
$ sudo tccutil reset com.apple.Safari ### Reset all permissions for all TCC-protected services. All
### applications granted access to any TCC-protected service will be
### revoked
$ sudo tccutil reset All

What’s Happening Under the Hood?

So far we learned that TCC will prompt the user when applications want to access TCC-protected services, these choices are reflected within the Security & Privacy UI, and that we can reset TCC permissions with tccutil. What’s really happening here?

Information about what applications can access what services is all stored within two SQLite databases:

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

The first path is a system-wide database and the second path is a per-user database. These databases are protected by System Integrity Protection (SIP), but they can be read if you grant Full Disk Access permissions to your application.

Introducing SwiftParseTCC

Note: Grant terminal “Full Disk Access” to use SwiftParseTCC from the terminal

To further my understanding of TCC, I wrote a TCC database parser based on Keith Johnson’s blogpost called SwiftParseTCC. My tool provides some additional context on the data returned from TCC.db that may not be as apparent when using only a SQLite client.

SwiftParseTCC Help Output
SwiftParseTCC Text Table Output

If you use SwiftParseTCC (or any SQLite database client) on TCC.db, you’ll see some familiar fields from the Security & Privacy UI.

  • service — The internal name used for various TCC-protected services
  • client — The application that requested access to a particular service
  • client_type — Whether the application is identified by bundle ID or absolute path
  • auth_value — Whether the application is allowed to access the TCC-protected service

Now we know when a user allows/denies a TCC prompt, their choice adds an entry to TCC.db. Additionally, we also now understand that tccutil simply removes entries from TCC.db.

Enough talk about TCC, I thought this blogpost was about Location Services?

Is Location Services TCC-Protected?

While looking into TCC bugs, I noticed an interesting TCC-protected service, kTCCServiceLiverpool, that appeared to be default for certain applications on macOS.

kTCCServiceLiverpool within SwiftParseTCC Output

Reading through Keith’s blogpost, the service appears to be related to Location Services, but may not apply to macOS.

kTCCServiceLiverpool Description From Keith’s Blogpost

So it seems that Safari, Notes, and TrustedPeersHelper should have access to Location Services. Let’s write a program that accesses Location Services to obtain GPS coordinates and see if our application shows up in TCC.db.

Introducing SwiftLiverpool

SwiftLiverpool Output

SwiftLiverpool is a Swift CLI tool that leverages the CoreLocation API to interact with Location Services and extract latitude, longitude, altitude, and more.

If our assumption about kTCCServiceLiverpool are correct, when SwiftLiverpool is run, a TCC prompt will ask if the user wants to allow access to Location Services and an entry will be added to TCC.db. Let’s start with a clean slate by resetting TCC permissions with sudo tccutil reset All.

Note: In the image below, SwiftLiverpool was previously given access to Location Services through a pop-up.

Location Services Not Reset

Interesting … even after resetting TCC permissions, applications previously granted Location Services permissions were not reset. Let’s try running our application and inspecting the TCC database.

SwiftLiverpool Does Not Appear Within TCC.db

It seems that our application is able to interact with Location Services while not having an entry within either the system or user-specific TCC database. Location Services does not appear to be protected by TCC, so what actually protects/controls it?

Location Services (locationd)

While searching for how to reset Location Services I came across this gist which scripted tccutil to reset all TCC-protected services. The comment below was particularly interesting and seemed like the answer to all my questions!

Gist Comment

Plist files are a form of configuration files and can be formatted as XML, JSON or binary. Let’s take a look at /var/db/locationd/clients.plist using plutil (you must be sudo or root):

slyd0g@Justins-MBP~$ plutil -p /var/db/locationd/clients.plist
/var/db/locationd/clients.plist: file does not exist or is not readable or is not a regular file (Error Domain=NSCocoaErrorDomain Code=257 "The file “clients.plist” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/var/db/locationd/clients.plist, NSUnderlyingError=0x7f8fb4506e90 {Error Domain=NSPOSIXErrorDomain Code=13 "Permission denied"}})
slyd0g@Justins-MBP~$ sudo plutil -p /var/db/locationd/clients.plist
{
"com.apple.locationd.executable-/Users/slyd0g/Projects/SwiftLiverpool/build/Debug/SwiftLiverpool" => {
"Authorized" => 1
"BundleId" => "com.apple.locationd.executable-/Users/slyd0g/Projects/SwiftLiverpool/build/Debug/SwiftLiverpool"
"Executable" => "/Users/slyd0g/Projects/SwiftLiverpool/build/Debug/SwiftLiverpool"
"LocationTimeStopped" => 660004429.982445
"ReceivingLocationInformationTimeStopped" => 660004431.985412
"Registered" => "/Users/slyd0g/Projects/SwiftLiverpool/build/Debug/SwiftLiverpool"
"Requirement" => "cdhash H"c670128640c6e2a8f7c33cda58d91d14c7062f2b""
"Whitelisted" => 0
}
"com.google.Chrome" => {
"Authorized" => 0
"BundleId" => "com.google.Chrome"
"BundlePath" => "/Applications/Google Chrome.app"
"Registered" => ""
"Requirement" => "(identifier "com.google.Chrome" or identifier "com.google.Chrome.beta" or identifier "com.google.Chrome.dev" or identifier "com.google.Chrome.canary") and certificate leaf = H"c9a99324ca3fcb23dbcc36bd5fd4f9753305130a""
"Whitelisted" => 0
}
"com.microsoft.VSCode" => {
"Authorized" => 1
"BundleId" => "com.microsoft.VSCode"
"BundlePath" => "/Applications/Visual Studio Code.app"
"Registered" => ""
"Requirement" => "identifier "com.microsoft.VSCode" 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] = UBF8T346G9"
"Whitelisted" => 0
}
}

Ah-ha! These applications match what is reflected within the Security & Privacy UI under Location Services. So locationd consumes /var/db/locationd/clients.plist, which is a binary plist that defines the “clients” that can access Location Services.

I wanted to see if I could remove the file, to reset Location Services, or write to the file and grant arbitrary applications access to location.

sh-3.2# rm /var/db/locationd/clients.plist
override rw-r--r-- _locationd/_locationd for /var/db/locationd/clients.plist? y
rm: /var/db/locationd/clients.plist: Operation not permitted

(Un)fortunately, I couldn’t delete clients.plist even from a privileged context. I then granted iTerm2 “Full Disk Access” permissions within TCC and tried again.

slyd0g@Justins-MBP~$ rm /var/db/locationd/clients.plist
rm: /var/db/locationd/clients.plist: Permission denied
slyd0g@Justins-MBP~$ sudo rm /var/db/locationd/clients.plist
Password:
slyd0g@Justins-MBP~$ sudo ls /var/db/locationd/
Library

With “Full Disk Access” and root permissions, I was able to delete clients.plist. You can also swap clients.plist with your own malicious.plist and grant any application access to Location Services. I’ll leave this as an exercise to the reader ;)

Copying a Malicious Plist File

Remember how we couldn’t reset Location Services earlier with tccutil?We can now reset Location Services within the Security & Privacy UI by deleting the clients.plist file and restarting locationd.

Resetting Location Services within Security & Privacy UI

Conclusion

In this post, I walked through my initial question, thought process, things learned along the way, and the tooling I built to challenge my assumptions. To recap, kTCCServiceLiverpool does not seem to be related to Location Services on macOS, which isn’t actually protected by TCC.

Location Services is configured using a binary plist file, /var/db/locationd/clients.plist, that is consumed by a daemon, locationd. With root permissions and “Full Disk Access”, a malicious user can overwrite the clients.plist file with a malicious copy to allow arbitrary applications access to Location Services.

Thanks for taking the time to read this post, I hope you learned a little about macOS, TCC, and Location Services!

References

https://gist.github.com/haircut/aeb22c853b0ae4b483a76320ccc8c8e9

--

--

Justin Bui

I break computers and skateboards and write about the former