Analysis of the ABTraceTogether app (iOS)
I decided to have a look at the ABTraceTogether contract tracing app released by the Alberta Government today (May 1 2020) and blog about my findings.
There’s potential for conspiracy theories and disinformation to run rampant for an app like this, so I wanted to have a look for myself and see how it actually works.
I was also curious to see if there might be any forensically valuable information found in the app’s databases and files.
I’ll start with my general observations and provide a more detailed explanation afterwards.
As I’ve added a couple of updates today (May 2) – any new info is marked in green.
Observations
The registration process does not prompt you for your name, email, or any other PII (personally identifiable information) except for one: you must register using valid phone number, which will be used to contact you in the event you come into contact with someone who contracted the virus.
The app is built on BlueTrace/OpenTrace, which is open source and has published a whitepaper that explains its methodology in great detail. It was first used in the TraceTogether app in Singapore beginning in March 2020.
Encounters between devices are only tracked locally and must be uploaded to AHS manually (and voluntarily) if they contact you and request you to do so. In my tests the app did not communicate with the server any more than necessary (such as to retrieve encrypted forward-dated Temp IDs).
Analysis of the tracing database did not net any information of significant forensic value. Encounters between devices are logged however the only information available is: 1) the other device’s make and model, 2) the host device’s make and model, 3) the time of the interaction, 4) indicators of how close the device came such as received signal strength indicator (RSSI). The remaining data is encrypted and not accessible without keys that AHS maintains.
In the BlueTrace design, the server (and its security) is of utmost importance. While out of scope for this article, I think it is worth noting that given all encryption keys, IDs, tempIDs, and registered phone numbers are stored on the server, any sort of poorly configured or insecure endpoints could pose the largest risk (such as in the event of a data breach).
Overall, the app appears to deliver on its privacy promises. I did not find much of potential forensic value in artifacts from the app’s sandbox. The app’s biggest failing, I think, is the requirement (iOS only) to keep the phone unlocked with the screen active at all times. I just can’t see people doing this – they will be on their phones, which will mean this app isn’t in the foreground and thus not working. I do acknowledge this limitation is not the fault of the developer, but rather the restrictiveness of iOS. Hopefully future development, such as with the recently released Apple/Google contact tracing API, the need for leaving the device unlocked can be eliminated.
UPDATE 2020-05-02: As pointed out by user Chris Thompson (@yegct), another curiosity is that the OpenTrace project seems to be using a GPL license, which would be potentially problematic as this license dictates anything it ships with be licensed under GPL as well. I found this github issue on the repo also questioning the same.
Static analysis
I obtained a copy of the app (version 1.0.0) on my test iPhone 6S running iOS 13.2.2. I used frida to obtain a copy of the IPA with a decrypted app binary and then used Hopper (macOS) to examine it.
It appears to be a small, straightforward app with not a lot of code to examine. It’s written in Swift which makes the static analysis a bit less intuitive.
The app uses a library called OpenTrace (which is an implementation of BlueTrace). BlueTrace has published a whitepaper explaining the technical methodology and, I feel gives very solid explanations for why things are the way they are.
UPDATE 2020-05-02: Just a minor clarification on the above paragraph – rather than consuming any pre-compiled library or framework, it appears that the OpenTrace code has been integrated directly with the ABTraceTogether codebase under the ABTraceTogether class. This does not mean there aren’t variations. However, I did test several strings from debug messages found in the OpenTrace code and located all of them unmodified in the ABTraceTogetherApp binary.
Info.plist
The app’s Info.plist contains some interesting info, such as developer specified descriptions for permissions potentially requested.
NSBluetoothAlwaysUsageDescription – ABTraceTogether exchanges Bluetooth signals with nearby phones running the same app. These signals contain an anonymised ID, which is encrypted and changes continually to ensure your privacy.
NSCameraUsageDescription – Grant ABTraceTogether permissions to access your camera if you would like to upload a photo as part of a support request
NSPhotoLibraryUsageDescription – Grant ABTraceTogether permissions to access your photo library if you would like to upload a photo as part of a support request
The plist also specifies that at a minimum, iOS 13 is required. This requirement was interesting to me because the app does not use the new Apple/Google API. It could limit the ability for people using older hardware that can’t run iOS 13 to access it.
Overall, nothing super surprising here. The camera/photo gallery permissions didn’t come up in any of my tests.
Nothing else of note resulting from static analysis. Future research -> to obtain a copy of the Android version and review it as well.
Forensic value of filesystem artifacts
The database tracer.sqlite, located in Library/Application Support/, and specifically the table ZENCOUNTER is where interactions between nearby devices are logged.
To generate a test encounter, I installed the app on my own iPhone (in addition to my research phone), and with the app open, brought the devices fairly close together.
This test showed up in table ZENCOUNTER as follows:
Column | Description |
---|---|
ZV | The version of BlueTrace protocol the other device is using (currently 2) |
ZRSSI | The received signal strength indicator (RSSI) – can be used to assess how close the devices actually got. |
ZTIMESTAMP | When the encounter took place. |
ZTXPOWER | Transmission power? Always 0.0, 7.0 or NULL in my database so far. |
ZMODELC | A device make and model. Can be the other device or our device. C is believed to refer to “Central”. See this link for more on the OpenTrace github for Encounter Record. |
ZMODELP | A device make and model. Can be the other device or our device. C is believed to refer to “Peripheral”. See this link for more on the OpenTrace github for Encounter Record . |
ZMSG | An encrypted payload, base 64 encoded including IV/Auth Tag. (84 bytes) |
ZORG | The organization code indicating the country / health authority with which the peripheral is enrolled. |
The ZMSG structure is described in the whitepaper as follows:
(Note the typo of AED which should read AES).
The forward-dated tempIDs were found in a file under Library\Caches\ca.ab.gov.ahs.contacttracing\fsCachedData\{GUID} . The contents of the file is shown here but redacted slightly to not show the full tokens:
Future work
One remaining bit of work on iOS is to examine the iOS keychain – there’s a bunch of entries in there and I’m curious what they could be used for given temp ID token generation takes place serverside.
As always super thorough and detailed. Thanks Mike 🙂
Plus I trust your assessments of these things so that is always helpful for when other third party or media folks have their own perspectives.
> The remaining data is encrypted and not accessible without keys that AHS maintains.
Correction: the remaining data is encrypted and is accessible with keys that both AHS and the app user have access to. The whitepaper explains that the data is encrypted symmetrically. This means that both parties possess the same key, and it is used for both encryption and decryption. It would be interesting to investigate how the app stores the key (probably not hard, since it is derived from an open source app) to make sure that it’s not exposed to other apps on the device. Also, finding that key would obviously allow you to further investigate exactly what the app is storing.
I suspect the conclusion will be the same, that it’s only doing what it advertises, I’m just pointing out there is more you can do to actually validate this and provide more meaningful reassurance. If all you did was run the binaries and the stored data through strings or something that’s a pretty shallow forensics dive tbh.
Thanks for the comments. I do have to reiterate my position here that the encryption keys for BlueTrace aren’t stored on the device. They are serverside only. This is based both on my own observations, as well as in numerous places throughout the BlueTrace spec. If you have evidence to the contrary I’d love to take a look! Consider:
On page 2 of the BlueTrace whitepaper, under “Generation of TempIDs” – “Only the health authority holds the secret key to encrypt and decrypt TempIDs“.
On page 6 of the BlueTrace whitepaper, the author speaks to a number of points:
As with many of my posts, and indeed forensics in general… there are many other angles that could (and perhaps should) still be explored. What I’ve learned is if you wait until you’ve explored every avenue, the topic may have already past its period of relevance, or the app will have a new version and you’ll have to start all over again :). For example, one thing that *is* resident on the device – and definitely deserves a deeper dive – is telemetry (IBM WLAnalytics). It is my present belief that WLAnalytics is responsible for most if not all of the keychain values in this app. But this might even be a separate post as it is unlikely to have any bearing on the core bluetooth tracing functionality.
Great job mike!
Have you been able to perform any traffic analysis?
I see that the app only interacts with one server but i haven’t been able to look at the traffic since they are implementing SSL pining.
This app is useless for iPhone users. Very few will leave their screen unlocked and the app running in the foreground all day long!
Why not use the Federal APP ??
I’m guessing the provincial govt just wants to avoid admitting they spent a lot of money on this for nothing 🙂