WHO COVID-19 Mobile App · Report #1064149
Improper Input Validation on User's Location on PUT /WhoService/putLocation Could Affect Availability/Falsify Users
Summary
This refers to sanitization of an API that is already scheduled to be deleted. It doesn't appear to be exploitable. https://github.com/WorldHealthOrganization/app/pull/1826
How it was found
Summary: Note: I noticed that that the team has fixed issues like an XSS that's caused only from a header value (typically OOS since it's not directly exploitable) https://github.com/WorldHealthOrganization/app/pull/855, so in the spirit of this I'm also reporting another "good-to-fix" issue.
On the WHO app, users send approximate location data to the WhoService API:
/app/client/flutter/lib/pages/onboarding/location_sharing_page.dart:
Future<void> _allowLocationSharing() async { try { await Location().requestPermission(); if (await Location().hasPermission() == PermissionStatus.granted) { if (await Location().requestService()) { LocationData location = await Location().getLocation(); Map jitteredLocationData = JitterLocation().jitter( location.latitude, location.longitude, 5 /kms refers to kilometers/);
await WhoService.putLocation(
latitude: jitteredLocationData['lat'],
longitude: jitteredLocationData['lng']);
}
}
} catch(_) {
// ignore for now.
} finally {
_complete();
}
} Which in turn translates to a call to https://staging.whocoronavirus.org/WhoService/putDeviceToken:
curl --request POST
--url 'https://hackerone.whocoronavirus.org/WhoService/putLocation'
--header 'content-type: application/json'
--header 'who-client-id: ██████████'
--header 'who-platform: ios'
--data '{
"latitude": 22222222,
"longitude": "9999999"
}'
This returns a 200 OK response. On the server side, we see that it uses the following logic:
@Override public Void putLocation(PutLocationRequest request) throws IOException { Client client = Client.current(); client.latitude = request.latitude; client.longitude = request.longitude; S2LatLng coordinates = S2LatLng.fromDegrees(request.latitude, request.longitude); client.location = S2CellId.fromLatLng(coordinates).id(); ofy().save().entities(client); return new Void(); } There is no validation on request.latitude, request.longitude before it is stored into the Google App Engine datastore. This is because the S2LatLng.fromDegrees (which transforms the values into a S2LatLng object) from the s2-geometry-library-java library specifically does not validate these values because, according to their comments at https://github.com/google/s2-geometry-library-java/blob/master/src/com/google/common/geometry/S2LatLng.java:
Like the rest of the "geometry" package, the intent is to represent spherical geometry as a mathematical abstraction, so functions that are specifically related to the Earth's geometry (e.g. easting/northing conversions) should be put elsewhere. Thus, even these values:
"latitude": 22222222,
"longitude": "9999999"
Are accepted and stored in the database even though they are technically non-existent coordinates on earth.
To reproduce, just run this request with different who-client-id UUID you generated yourself and impossible latitude and longitude.
curl --request POST
--url 'https://hackerone.whocoronavirus.org/WhoService/putLocation'
--header 'content-type: application/json'
--header 'who-client-id: ████████'
--header 'who-platform: ios'
--data '{
"latitude": 22222222,
"longitude": "9999999"
}'
Impact
An attacker can exploit this to affect the Availability or Integrity of the analytics data by injecting false location values and falsifying user data. A fix for this would be to implement a quick lat lng validator that is specifically meant to validate Earth geometry, instead of the S2LatLng class.