Aarogya Setu: The story of a failure
In order to fight Covid19, the Indian government released a mobile contact tracing application called Aarogya Setu. This application is available on the PlayStore and 90 million Indians already installed it.
Aarogya Setu - Apps on Google Play
This application is currently getting a lot of attention in India. In Noida, if people doesn’t have the app installed on their phone, a person can be imprisoned up to 6 months or fined up to Rs 1000.
No Aarogya Setu app? Pay Rs 1,000 fine or face 6 months jail in Noida
Access to app internal files
On April 3, 2 days after the launch of the app, I decided to give a look to the version 1.0.1 of the application. It was 11:54 pm and I spent less than 2 hours looking at it.
https://twitter.com/fs0c131y/status/1246194289144737793?s=20
At 1:27 am, I found that an activity called WebViewActivity, was behaving weirdly. This activity is a webview and is, in theory, responsible of showing web page like the privacy policy for example.
AndroidManifest.xml in Aarogya Setu v1.0.1
The issue is that WebViewActivity was capable of doing a little bit more than that.
WebViewActivity in Aarogya Setu v1.0.1
As you can see, the onPageStarted method checked the value of the str parameter. If str:
- is tel://[phone number]: it will ask Android to open the dialer and pre-dial the number
- doesn’t contain http or https, it does nothing
- else it is opening a webview with the specified URI.
As you can see there is no host validation at all. So, I tried to open an internal file of the application called FightCorona_prefs.xml by sending the following command
As you can see in the following video, it worked fine!
https://twitter.com/fs0c131y/status/1246222367661187073
Why it’s a problem? With only 1-click an attacker can open any app internal file, included the local database used by the app called fight-covid-db
Ability to know who is sick anywhere in India
On May 4, I decided to push my analyse a little bit further and I analysed the version v1.1.1 of the app which is the current version.
The first thing I noticed is the issue described previously had been fixed silently by the developpers. Indeed, the WebViewActivity is no more accessible from the outside, they removed the intent filters in the AndroidManifest.xml.
AndroidManifest.xml in Aarogya Setu v1.1.1
To continue my analysis, I decided to use the app on a rooted device. When I tried, I directly received this message.
I decompiled the app and found where this root detection was implemented. In order to bypass it, I wrote a small function in my Frida script.
The next challenge was to be able to bypass the certificate pinning implemented in order to be able to monitor the network requests made by the app. Once I done that, I used the app and found an interesting feature
In the app, you have the ability to know how many people did a self assessment in your area. You can choose the radius of the area. It can be 500m, 1km, 2kms, 5kms or 10kms.
When the user is clicking on one of the distance:
- his location is sent: see the lat and lon parameters in the header
- the radius choosen is sent: see the dist parameter in the url and the distance parameter in the header
The first thing I noticed is that this endpoint returns a lot of info:
- Number of infected people
- Number of unwell people
- Number of people declared as bluetooth positive
- Number of self assesment made around you
- Number of people using the app around you
Because I’m stupid, the 1st thing I tried was to modify the location to see if I was able to get information anywhere in India. The 2nd thing was to modify the radius to 100kms to see if I was able to get info with a radius which is not available in the app. As you can see in the previous screenshot, I set my location to Mumbai and set the radius to 100kms and it worked!
What are the consequences?
Thanks to this endpoint an attacker can know who is infected anywhere in India, in the area of his choice. I can know if my neighboor is sick for example. Sounds like a privacy issue for me…
So I decided to play with it a little bit and checked who was infected in some specific places with a radius of 500 meters:
- PMO office: {“infected”:0,”unwell”:5,”bluetoothPositive”:4,”success”:true,”selfAsses”:215,”usersNearBy”:1936}
- Ministry of Defense: {“infected”:0,”unwell”:5,”bluetoothPositive”:11,”success”:true,”selfAsses”:123,”usersNearBy”:1375}
- Indian Parliament: {“infected”:1,”unwell”:2,”bluetoothPositive”:17,”success”:true,”selfAsses”:225,”usersNearBy”:2338}
- Indian Army Headquarters: {“infected”:0,”unwell”:2,”bluetoothPositive”:4,”success”:true,”selfAsses”:91,”usersNearBy”:1302}
Disclosure
https://twitter.com/fs0c131y/status/1257689150729392135?s=20
49 minutes after my initial tweet, NIC and the Indian Cert contacted me. I sent them a small technical report.
Few hours after that they released an official statement.
https://twitter.com/SetuAarogya/status/1257755315614801921?s=20
To sum up they said “Nothing to see here, move on”.
My answer to them is:
- As you saw in the article, it was totally possible to use a different radius than the 5 hardcoded values, so clearly they are lying on this point and they know that. They even admit that the default value is now 1km, so they did a change in production after my report
- The funny thing is they also admit an user can get the data for multiple locations. Thanks to triangulation, an attacker can get with a meter precision the health status of someone.
- Bulk calls are possible my man. I spent my day calling this endpoint and you know it too.
I’m happy they quickly answered to my report and fixed some of the issues but seriously: stop lying, stop denying.
And don’t forget folks: Hack the planet! 🤘