Jump to content
Nytro

Reverse Engineering the Australian Government’s Coronavirus iOS application

Recommended Posts

Reverse Engineering the Australian Government’s Coronavirus iOS application

Apr 6 · 5 min read
 
 

On the 29th of March, the Australian Government launch their Coronavirus app. It’s a pretty neat little app with lots of useful features, including data on the current status of the number of COVID-19 cases in Australia, broken down by state:

1*0HNWQMTssb6_WqBfMqg_Aw.jpeg?q=20
1*0HNWQMTssb6_WqBfMqg_Aw.jpeg

I’ve been wondering where this data is and how to access it programatically. With a native application fetching this data, the answer must be inside! I found the process of discovery interesting, so I’ve documented my efforts in the hope that it’s of interest to others.

The first thing I would try when presented with something like this is to simply proxy through an app like Burp Suite, Proxyman or mitmproxy. These are all capable of capturing https and secure websockets. I used mitmproxy in transparent proxy mode, and setting up my device to use my macbook as the router to force all traffic through it (not through the Proxy settings on the device). But when capturing, minimal traffic shows up (there’s a bit more on first app run and if refresh tokens or remote-config are required, but not a lot):

1*bUnrVk3rdnKl7NtyPBV5ZA.png?q=20
1*bUnrVk3rdnKl7NtyPBV5ZA.png

Worse, the following appears:

Warn: 192.168.86.25:51981: Client Handshake failed. The client may not trust the proxy’s certificate for firestore.googleapis.com.

However, this does give a couple of good pieces of information:

  • This app uses Firebase’s Firestore database. Maybe the data is there?
  • Firestore has pretty good SSL cert pinning, because traditional off-the-shelf cert pinning removal didn’t appear to work.

So the next step is to ssh to a jailbroken iPhone with the app installed and poke around a bit. The first thing I noticed was GoogleService-Info.plist in the root directory of the application. When integrating the Firebase SDK in an iOS application, it helpfully provides a plist file with all the configuration for your project, which gets embedded in the app for the SDK to read. This contains project ids, API keys, etc. Useful:

1*Z-n727rpZOJdMbR8B4m91Q.png?q=20
1*Z-n727rpZOJdMbR8B4m91Q.png

Good news: The Australian government doesn’t send application analytics off to Google willy-nilly. It also shows us the firestore database URL.

This is a good start, but we don’t know how the data is structured in Firestore (or even if it’s actually there). It could be in various collections and documents, so it requires more digging to find out what the names of those are before we can attempt to read the data for ourselves.

1*6Dt_4fhAVOnpr0W5t6iX9w.png?q=20
1*6Dt_4fhAVOnpr0W5t6iX9w.png
Filtered mangled symbols displayed from Ghidra

The next step was to extract the ipa from the device and have a look at any other configuration files, load it up in Ghidra and see if there’s anything glaring. This did present some useful info on how the app is structured — what View Controllers and View Models there are (and the name of the developer who’s build machine it ran on), but there was nothing obvious in the strings section around collection or document paths, and sifting through the status view controller and co. started to become time consuming. I also considered patching the binary to remove cert pinning, but there had to be an easier way first.

In steps Frida. Frida allows us to dynamically trace, hook, and inject code at runtime. My thinking here was to hook the Firestore methods for retrieving collections and documents and print out the arguments. The first step was to confirm that these methods are called, which will hint that it’s actually using it for the app data. Fortunately I’ve used Firestore in my own project so was slightly familiar with the APIs. Using frida-trace, we can get it to show when these functions are called:

% frida-trace -U -m "*[FIR* *collection*]" -m "*[FIR* *document*]" -f au.gov.health.covid19
Instrumenting functions...

Started tracing 16 functions. Press Ctrl+C to stop.
           /* TID 0x503 */
  1651 ms  -[FIRFirestore collectionWithPath:0xdb39cb061878d20a]
  1659 ms  -[FIRCollectionReference documentWithPath:0x2813caeb0]

This is great! We can see here that it pulls a collection and a document from Firestore, but we can’t yet see the arguments. The same output occurs when tapping into the “Current status” section. These two functions both take strings as their only argument; the collection path and document respectively. So I wrote a frida script to simply print them out:

Script to hook two Firebase methods

This results in the following:

% frida --no-pause -U -l coronavirus.js -f au.gov.health.covid19[iPhone::au.gov.health.covid19]->
[FIRFireStore collectionWithPath:@"<redacted>"][FIRCollectionReference documentWithPath:@"<redacted>"]**tap "Current status" section**[FIRFireStore collectionWithPath:@"<redacted collection>"][FIRCollectionReference documentWithPath:@"<redacted document>"]

Now we have enough information to get the data ourselves:

Javascript. Don’t ask.

The output of this is interesting:

Apart from the actual status data, there’s a whole lot of backend-for-frontend data for how the app should display sections from the second document. This is pretty neat, and how more and more applications are being developed.

Interestingly, I cannot find any reference to a string of the collection with the numbers in the application. This could either be because it’s hidden on purpose, or because I didn’t look hard enough. Either way, it doesn’t really matter.

Conclusion & Application

We can now use this to, for example, write a Slack bot that sends updates as soon as new data is in Firestore. Using Google’s Firestore is an interesting choice, and it’s nice to see it used well in what I presume is a heavily used application.

This app is well written, and doesn’t look like it was something very quickly thrown together and rushed to the App Store (perhaps it was, well done). Inspecting the network traffic was a problem, and I went down a few rabbit holes (e.g. trying to use my JWT token from my application to use Firestore REST apis) that aren’t documented here. I have almost no suggestions to the developers on how to improve things here. The API keys simply must be in the app in some fashion, so as long as permissions and scope on them are suitable then it’s really not an issue. 👍

I’ve shown how we can reverse engineer an application in order to replicate functionality, or fetch application data for ourselves. When an app doesn’t require user authentication to fetch data, it’s always going to be possible for someone determined enough to be able to inspect. My advice is to simply go with the assumption that the client is always an untrusted environment. Ensure your APIs are secure on the server side and able to deal with various types of abuse.

Sursa: https://medium.com/@wabz/reverse-engineering-the-australian-governments-coronavirus-ios-application-c08790e895e9

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...