I'm always interested in location data that is available on iOS and Android devices. Especially if that data is generated not by the core system and is instead generated by a third party application. Often times our third party apps are collecting location data but according to Apple's policy it's supposed to be passing through them. But what if the application is collecting it for their purpose too and transmitting it back to their servers? Maybe there are files left behind in the application that can point to when a user was in a specific area. Wouldn't it be nice if a user basically also carried around a GPS tracker with them? Oh wait, a lot of folks do!
Enter: the Chipolo. Well, enter a lot of Bluetooth based finders really. Chipolo just happens to be the first on my list to talk about for iOS. The upcoming blog posts will compare Chipolo, Tile, and TrackR finders and what they are leaving behind on our iOS devices. Last year I did a post on Tile for Android and ever since I've been interested in what the iOS operating system had as well.
Why am I starting with Chipolo versus the others? Well mostly because it caused me some issues and I wanted to talk about those issues. If you saw the Android post about DJI Fly, you saw that some of the preference data was encrypted now. Turns out, not only is Chipolo using a completely different data storage container than most apps, they're also encrypting said container.
As per my normal methodology, after finding the application storage folder for Chipolo it was time to start looking at its preference data.
It's a little lacking. I can find some timestamps to see when the user was last using the tracker/service but not any decent user account info. With that out of the way, let's go look for maybe a database that has all the good data instead.
There was some limited location data found within the caches folder under: net.ChipoloMKMapSnapshot.default and I can say that the creation dates/times do line up with when the device was within the area. In addition to a map image that is generated for the phone, geolocation points are also placed into the filename.
Don't forget to check for iOS Snapshots in the form of KTX Files! There were some good ones in here too that showed the device name as well as a location where the device had recently been found.
Continuing on the hunt for databases, I went looking into Application Support as it's usually a good place to look. That's when I found a dreaded folder name. Realm.
What is a Realm database? It's an alternative to SQLite database structures that are becoming more popular in applications. For more info about it and why developers are choosing to go to it, head over here.
I ended up using a depreciated tool, the Realm browser for macOS to view the information. Realm has more recently adopted more platform support in their Realm Studio tool available here. Once I exported the Realm folder, I attempted to open the "chipolo.realm" file found within using the Realm browser only to be greeted by this:
Oh great. Not only is it a realm database, it's an encrypted realm database. Joy of joys. At this point I did my fairly standard checks, going out and looking in the keychain or looking to see if the devs happened to be using a key stored somewhere in plaintext. Since the browser mentioned it was 128-characters of hexadecimal it made for some easy GREP searches. The bad news is that I didn't get anything back. So I turned to friend of colleague, Mike Williamson. Mike did a nice little writeup that I'm going to include verbatim below:
Reverse Engineering Chipolo – a lesson in making assumptions based on method names.
I had the opportunity to work with the legendary Chris Vance on this inquiry. I know I cringed a little bit inside when I heard this realm database was encrypted. Anyhow, here is a summary of the steps I took to determine what was going on:
Reviewed the Realm codebase (I chose to browse their .NET implementation because I understand it best) and found this source file with some helpful info about their encryption process.
Cool - so we know we are expecting a 64byte key and that it will be used with AES-256.
I downloaded a copy of the Chipolo app on iOS from the app store on my test device and then obtained a decrypted copy of the IPA using ios_dump.py from AloneMonkey.
Next I opened the decrypted binary in Hopper and did a search for ‘crypt’.
I searched for cross references to the setEncryptionKey: which sounded right in line with what I was hoping to find, and landed on the function [CPDataStore setupStore] which does this:
Here’s where I made the assumption: I concluded that [[CPDataStore someRandomData] retain]; was likely generating some pseudorandom data for use as a key. What I couldn’t figure out was where they were storing it, so that it could be found on the next run of the app. That should have been an alarm bell but I guess I did not expect anything that sloppy in this day and age.
I moved on from static analysis and into dynamic binary instrumentation with frida.
After setting traces on [CPDataStore encryptionKey*], I obtained a reference to the CPDataStore in memory using ObjC.Choose and arbitrarily invoked the encryptionKey getter.
Once I had my own realm database key sorted out, I set out to figure out how to compute this key for someone else. In the process, I shared my own key with Chris Vance. Chris thought to try this key on his own database, and it worked to decrypt. My mistaken assumption came to light – this app is not generating pseudorandom data to form a key. It is instead generating the SAME KEY FOR EVERY USER, also known as a hard-coded key.
How is it 2020 and folks are still using hard coded keys, you ask? Good question. But it certainly makes decoding easier.
Thanks Chris for the fun little early morning reversing project and good luck with the rest of your research!
And thank YOU Mike for figuring out the key. Bad for users to use a static key, but yay for us! Once that key is supplied the Realm database is now available to view.
Most of the timestamps in here that I can see are going to be Unix numeric timestamps. The chipolo_id column is going to reference a numeric identifier for the Chipolo tracker assigned to my account. Without giving away all my location information, I'm going to suggest that if you ever get this far, go check out the CPDeviceRLMObject model. It had some great information about my recent locations including geolocation points and timestamps.
One more point to mention is that the CPAuthProviderRLMObject model ended up having my login email. This could be valuable if you're trying to track what account the device information is coming back to. I've said it before and I'll say it again, these companies are obviously keeping some of this data. If you're working in law enforcement and you see a bluetooth tracker like Tile or Chipolo clipped to someone's keys, I would suggest sending them a search warrant based on this information. This Realm database will give you both the identifiers for the device(s) as well as the user.
Well that's it for this annoying app! Keep watching this blog space because I still have Tile and TrackR to talk about from an iOS perspective.