2019年にマカフィー の Advanced Threat Research(ATR)はBoxLockという製品の脆弱性を明らかにしました。それからしばらくして、英国の企業iParcelBoxの最高経営責任者(CEO)から、同社の製品をテストしてほしいとの依頼がありました。これはATRチームの通常のリサーチとは異なりますが、同社のセキュリティに対する積極的な取り組みに敬意を表し、iParcelBoxのチームから送られてきた同製品を調査することにしました。
iParcelBoxは、不在のときでも宅配業者や隣人が荷物を安全に届けたり取り出したりできるスチール製の大きな箱です。iParcelBoxにはボタンが1つだけついており、そのボタンが押されると、だれかが届け物を入れようとしている旨の通知が所有者の携帯端末に届きます。「解錠」リクエストのプッシュ通知が端末に表示されると、所有者は、承諾か拒否かを選択します。
予備調査
このデバイスは一見して非常にシンプルな作りとなっています。私たちは常に攻撃者の視点から、あらゆる攻撃経路を検討します。このデバイスの場合、外部からの経路はわずか3つです。遠隔クラウドAPI、Wi-Fi、そして単一のボタンです。
iParcelBoxはセットアップ中にモバイルアプリケーションのためのWi-Fiのアクセスポイントを作成し、セットアップ情報を送信します。iParcelBoxにはそれぞれランダムに生成された唯一の16文字のWiFiパスワードが割り当てられ、WPA2キーに対する総当たり攻撃を排除します。さらに、このアクセスポイントは、iParcelBoxがセットアップモードのときだけ有用です。このボタンを押し続けるとiParcelBoxはセットアップモードになりますが、同時に所有者に通知され、またセットアップモードは数分後には切れて通常の操作モードに戻ります。
私たちはいただいたiParcelBoxのWi-Fiパスワードを使ってデバイスに接続し、Webサーバーから何が収集できるかを確認しました。デバイスはポート443のみを開放していました。これは、アプリケーションとiParcelBox間の交信が暗号化されている可能性が高いことを示しており、これは後に検証できました。次にAndroidアプリを使って、セットアップ中にiParcelBoxにどんなメッセージが送信されているかの解読を試みました。
dex2jarを使用すると、APKファイルを逆アセンブルし、アプリ内のコードを確認することができました。iParcelBoxがMQTT(MQ Telemetry Transport)を使用して、iParcelBoxとクラウド間のメッセージのやり取りをしていることがわかりました。MQTTは、デバイスが「トピック」にサブスクライブしてメッセージを受信することができるパブリッシュ・サブスクライブ・メッセージ・プロトコルです。概要説明は、https://youtu.be/EIxdz-2rhLsを参照してください。
通常、次のステップは、デバイスのファームウェアを取得することです。そのため注意を引くURLを探すために逆アセンブルされたAPKコードを調べました。直接のファームウェアリンクは見つかりませんでしたが、いくつかの有用な情報を見つけることができました。
上記のコードには、文字列「config.iparcelbox.com」や、「app」「TBpwkjoU68M」を含む行など、いくつかの興味深い特徴が見られます。これは、セットアップ中にiParcelBoxに送られるアプリユーザーの認証情報とみられます。これについては、後で改めて触れます。URLはインターネット上では割り出せませんでしたが、iParcelBoxアクセスポイントに接続してDigクエリを実行すると、iParcelBoxで解決することがわかりました。
Androidアプリやデバイスのウェブサーバーから何も表示されなかったので、調査をさらに進めることにしました。ターゲット情報を収集する最も一般的な方法の1つは、ユーザーフォームを調べ、デバイスを変更しようとしている人が他にいないかどうかを確認することです。多くの場合、IOTデバイスのホームオートメーションフォーラムには、数多くのAPIの使用例や、こうしたデバイスと交信するためのユーザースクリプトがあります。 iParcelBoxでも同様かどうか調べました。最初にiParcelBoxで検索したときは、マーケティングコンテンツだけしかありませんでしたが、iParcelBox APIに変更して検索すると、いくつかの興味深い投稿が見つかりました。
最初のページからいくつかのバグレポートと「Mongoose-OS」のユーザーフォーラムが検出されました。Mongoose-OSフォーラムをのぞいたところ、ユーザーの1人は明らかにiParcelBox開発チームの一員でした。これにより、デバイスがESP32開発ボード上でMongoose-OSを実行しているということがわかりました。これは、ESP32デバイスを他の多くのタイプのコードでフラッシュできることを示しており、重要です。ユーザーの投稿の追跡を開始すると、デバイスの情報とデバイスの構築プロセス全体にわたる開発の意思決定に関する広範な情報を発見しました。重要なのは、これが多くの分析手法のショートカットにつながったことです。
すでに述べたように、最優先事項は、デバイスのファームウェアに、デバイスから直接取得または、ベンダーのサイトからダウンロードしてアクセスを試行することです。ファームウェアの取得が少し面倒なのは、フラッシュチップにワイヤをはんだ付けするか、フラッシュと連動するためにチップ全体を取り外す必要があるためです。ESP32からファームウェアを取得する前に、フォーラム内でデバイスのフラッシュメモリが暗号化されているという別の投稿に目がとまりました。
この投稿を踏まえ、ESP32へのワイヤのはんだ付けの手順をスキップしました。さらに、すでに技術的に困難なのがわかっていたので、ファームウェアを手動で取得することもしませんでした。これにより、プロビジョニングプロセスとデバイスごとのセットアップ方法についても理解できました。これをもとに、OTA更新のダウンロード方法を調査しました。
検索をしばらく続けていると、iParcelBoxのブート手順とみられる大きなログファイルのファイルアップロードが見つかりました。ログをくまなく検索したところ、ハイリーセンシティブ情報が見つかりました。
上記のスニペットからは、管理者の資格情報とGitHubトークンが送られていることがわかります。言うまでもなく、これはあまり良い方法ではありません。後でそれを使用できるかどうかを確認します。一方で、このログではファームウェアのURLが見つかりました。
ただし、URLにはユーザー名とパスワードが必要でした。
さらに私たちはファームウェアのダウンロードへの意図しないアクセスを防ぐために「.htaccess」が設定されているという内容のフォーラム投稿を見つけました。
以前に見つけた管理者パスワードは認証されなかったため、デバイスからログを取得して、古い認証情報かどうか、新しい資格情報をUARTに出力できるかどうかを確認しました。
ESP32 RXピンとTXピンはUSB-C接続にマッピングされていますが、回路を見ると処理を実行しているFTDI(Future Technology Devices International)チップはなかったため、これは単なるRAWシリアルです。上記の赤で表示したVias(垂直相互接続アクセスError! Hyperlink reference not valid.)にはんだ付けしましたが、それでもデータは転送されませんでした。上図でVias(垂直相互接続アクセス)は赤で強調表示されていますが、データは転送されていません。
そこで再び、この非常に参考になるフォーラムの投稿を検索すると、すぐにその理由がわかりました。
それによると、少なくとも誤って設定したものではなく、UARTを介して単にログが無効になっていることが確認できました。
メソッド#1-RPC
私たちの調査の結果、容易に物理的にiParcelBoxに侵入できないことはほぼ確実なため、ネットワークアプローチを転換することにしました。セットアップ中にiParcelBoxがワイヤレスAPを作成し、それに接続できることはわかっていました。フォーラムから得た知見を武器に、iParcelBoxのWebサーバーに再度アクセスすることにしました。まず、「MOS」(Mongoose-OS)コントロールコマンドを送信して、何がスタックしているかを確認しました。
Mongoose-OSのセットアップ手順はこちらを参照してください。OSに直接インストールする代わりに、移植性の高いDockerでインストールしました。
フォーラムを参照すると、mosコマンドの使用例がいくつか見つかりました。
最初のコマンドは期待を抱かせるもので、必要なのは認証情報の提供だけというものでした。以前にブートログを見つけたときのことを覚えていますか?そう、管理者の認証情報はオンラインに投稿され、実際に使えたのです!
この時点で、私たちは、すべてのファイル、JavaScriptコード、さらに重要なのはAWS証明書と秘密鍵へのアクセスを含むiParcelBoxへの完全で効果的なルートアクセスを取得していました。
デバイスから抽出されたファイルを使用したところ、iParcelBoxの開発者がアクセス制御リスト(ACL)を作成していたことがわかりました。IOTデバイスでは、これは一般的ではありませんが良い方法です。
Android APKで以前に見つけたユーザー名が「app」の認証情報はRPC認証情報でしたが、アクセス許可は制限され、Sys.GetInfo、Wifi.Scan、Wifi.PortalSave、Sys.Rebootしか実行できませんでした。これらの認証情報ではそれほど有益なことはできないため、残る方法として「admin」の認証情報の獲得に集中することにしました。
手元には、必要となる認証情報、証明書、秘密鍵がありますので、他のデバイスでの試行を行います。セットアップ中に、MACアドレスに「TopicID」というラベルが付いていることがわかりました。
すでに見た通り、iParcelBoxはMQTTを使用して、デバイス、クラウド、モバイルアプリケーション間の通信を仲介します。私たちは、認証バリアが設定されているかどうか、また、コマンドをリモートで開始するために必要なのはデバイスのMACアドレスだけかどうかを確認したいと思いました。
もともとルートアクセスはあるので、当然次はロギングを有効化し、デバイスで何が起こっているのかを確認します。Mongoose-OSフォーラムの投稿の1つから、iParcelBoxの構成を変更することで、ローカルデバイスへのUDPをロギングできることがわかりました。
私たちはiParcelBoxを起動し、ボタンを押してセットアップモード(APが有効な状態)に入り、RPC呼び出しを再度有効にしました。次に、「udp_log_addr」をローカルマシンに設定します。
ここまでで複数のログと多くの情報を入手しました。次にテストしたかったのは、MQTTブローカーにアクセスして他のiParcelBoxを変更できるかどうかです。ログでは、MQTTブローカーがAWS IOT上にセットアップされ、以前に取得した証明書と鍵を使用していたことを検証できました。PythonがAWS MQTTブローカー(https://github.com/aws/aws-iot-device-sdk-python)に接続しているいくつかの事例を見付けましたが、それは完全なトピックパス(例:topic_id / command / unlock)を認識していると考えられます。
UDPから抽出されたログを解析すると、「shadow/update」MQTTトピックのフォーマットを見つけることができました。ただし、Pythonスクリプトでサブスクライブすると、MQTTブローカーに接続しているように見えても、メッセージの送受信はできませんでした。最も考えられるのは、トピックごとに1つのサブスクライブに制限されているか、コードが破損しているかです。
デバイスをコントロールするための別の方法をさらに探すことにしました。そこでMongoose-OSフォーラムを再び訪ねました(ここならパターンがわかるはず?)。すると、デバイスがMQTT上でRPCコマンドを実行できることを説明する投稿が見つかりました。
これは、攻撃者にとっては、MQTTにアクセスするだけよりも都合がいいかもしれません。というのも、証明書、鍵、ユーザー構成ファイル、Wi-Fiパスワードなど、デバイスへの完全なアクセスが可能になるからです。同時に、RPCを使用してカスタムコードやカスタムファームウェアを作成することもできます。そのための公式のMongoose-OSサポートはこちら(https://github.com/mongoose-os-libs/rpc-mqtt)から参照でき、ここにはAWS IOTの例も含まれています。
「mos」コマンドに接続すれば、鍵を取り出したデバイスだけでなく、MACアドレスがわかる他のデバイスでも、すべての管理RPCコマンドを実行することができました。
私たちに送られてきた2つのiParcelBoxを調べてみると、MACアドレスは一部異なっており、おそらく増加的に生成されたことを強く示唆しています。
- 30AEA4C59D30
- 30AEA4C59D6C
理論的には、MACアドレスを増分すると、iParcelBoxの各MACアドレスを反復処理する単純なスクリプトを記述し、コネクテッドデバイスを見つけ、必要に応じて制御または変更することができることになります。ただし最もよくある攻撃は、より標的を絞った攻撃であり、攻撃者は宅配荷物や、被害者の自宅のWi-Fiの認証情報を盗もうというものでしょう。攻撃者は「airodump-ng」などのツールを使用して、簡単なネットワークスキャンを実行し、標的とするiParcelboxのMACアドレスを見つけることができます。標的のMACアドレスを入手した攻撃者は次に、管理者の認証情報を使用してMQTTで「mos」コマンドを開始し、ピン#4に向かわせる「GPIO.Toggle」コマンドを実行します。ピン#4は、iParcelBoxの施錠システムを制御するGPIO(汎用入出力)ピンです。そうすると留め金のトグルは反転します。もし、iParcelBoxに鍵がかかっている場合、GPIOトグルは鍵を解除し、蓋が開くようになります。攻撃者が別の動機を持っている場合、彼らは構成のダンプを開始し、iParcelBoxが接続しているWi-Fiの認証情報にアクセスすることもできます。
メソッド#2-AWSの設定ミス
このブログを執筆中に、SSLピン留めが適切に行われたことを再確認したいと思いました。調査中にこの投稿を確認した後、証明書をピン留めしていると想定しました。Fridaを使用して、証明書のピン留めを解除したAndroidをセットアップします。ピン解除がインストールされて機能している場合、アプリケーションとAWSサーバー間の交信を復号化できました。しかし、アプリケーションからiParcelBoxへのデータを復号化できませんでした。Androidデバイスで証明書のピン留めを解除する方法については、この手法に従ってください。
次に、Frida SSL Unpinnerを使用せずにiParcelBoxアプリケーションを再実行しました。同じAWSサーバーのトランザクションが返され、ピン留めが有効にならなかったことを示しています。キャプチャの一部を閲覧したところ、興味深いリクエストが見つかりました。
キャプチャにある「credentials」はすぐに私たちの興味をそそりました。これらは、「Cognito」と呼ばれるサービスによって返されます。Cognitoは、アプリとユーザーがAWSエコシステム内のリソースに短時間だけしかアクセスできず、プライベートリソースへのアクセスが制限されているAWSサービスです。
アプリケーションがAWSサービスにアクセスする場合、特定のタスクについて一時的な認証情報を要求できます。アクセス許可が正しく構成されている場合、Cognitoサービスによって発行される認証情報により、アプリケーションまたはユーザーはその1つのタスクを完了して他のサービスに対するすべての認証情報の使用を拒否できます。
これらの認証情報を使用するには、AWS-CLIインターフェイスが必要でした。AmazonにはAWS-CLI用のDockerの画像もあったため、私たち作業はより容易になりました。Cognitoサービスから返された認証情報を「〜/ .aws」フォルダーに保存しました。次に、これらの認証情報に付与されている役割を確認しました。
Androidアプリケーションから取得した認証情報には、「AppAuth_Role」が付与されています。 「AppAuth_Role」がどこにアクセスしたかを確認するために、認証情報を使用してクラウドサービスの列挙を実行しました。NotSoSecureのチームが提供したスクリプトはこちら(https://github.com/NotSoSecure/cloud-service-enum)を参照してください。AWSスクリプトは、重大なセキュリティホールを検出せず、認証情報が適切に保護されていることを示しました。ただし、次のいくつかのネットワークキャプチャを見ると、これらの認証情報がDynamoDBデータベースへのアクセスに使用されていることがわかりました。
DynamoDBのドキュメントのいくつかを読み込んだ後、データベースクエリを作成することができました。
データベースの「primary key」は「DeviceID」であり、それはiParcelBoxのMACアドレスであるため、このクエリを変更して他のデバイスのデータベースエントリを入手できます。これは倫理的な理由でテストしていませんが、この情報を使用してMQTTサービスにアクセスできただろうと考えています。また、これは稼働中の本番データベースであり、データを破損したくなかったため、データベースへの書き込みは試みませんでした。
さらにいくつかのデータベースインタラクションをトリガーしようとするAndroidアプリケーションを調査して、他にどのようなクエリが送信されているかを確認しましたが、以下に限定されていました。
- アカウント-プレミアムサブスクリプション情報を表示
- 所有者-各iParcelBoxのデバイスとゲストを表示
- ユーザー-各iParcelBoxの所有者を保存するために使用(セットアップ時のみ)
データベース書き込みについて私たちは自ら制限を課していたため、これらのテーブルは何ら役には立ちませんでした。そこで、Androidアプリの逆アセンブルされたコードを調べて、さらに手がかりを探しました。その結果、テーブル名がわかったため、Javaファイル「DBConstants.class」を表示する「ClientID」を検索しました。
この定数ファイルにより、ネットワークトラフィックでまだ見たことがないデータベーステーブルとフィールドがまだたくさんあることがわかりました。「iParcelBox_devices」テーブルでは「TABLE_DEVICES_PASSWORD」が目に留まりました。
このテーブルでは「AppAuth_Role」認証情報もテストしましたが、承認されました。
デバイスのパスワードとシリアル番号はすべてMACアドレスから取得できました。ブログの冒頭にある「iParcelBoxセットアップ情報」の画像と、この情報を安全に保管する必要があると指摘したことを思い起こしてください。この情報を安全に保管する必要があるのは、「Add Manually」(手動で追加)ボタンがあるためQRコードがなくても、MACアドレス、シリアル番号、パスワードを知っていれば、iParcelBoxの所有者になることができるためです。
攻撃者はこの情報を使用して、新しいiParcelBoxアカウントに登録し、アプリケーションにログインし、Cognitoの認証情報を取得し、「setup」プロセスを開始し、「Add Manually」をクリックし、データベースから返された必要なすべての情報を入力して、どんなiParcelBoxでも完全に制御下に置くことができます。「AppAuth_Role」は任意のデータベースエントリを読み取ることができるため、MACアドレスをわかっているだけでこれらすべてのことが実行できてしまいます。
教訓
このプロジェクトは非常に早い段階で、古典的なハードウェア・IOTデバイスの調査プロジェクトから、OSINT調査トピックに移行しました。オンラインデータの衛生管理の単純なミスであっても、攻撃者に重要な詳細情報を公開していることになり、攻撃の経路を絞り込んだり、資格情報などの機密情報を知り得たりすることを示しています。
今回はiParcelBoxによる依頼プロジェクトだったため、この結果をすぐに同社に報告しました。同社はすべてのiParcelBoxの管理者パスワードを即座に変更し、Mongoose-OSの開発者に対し、1デバイスのAWS証明書と秘密鍵が他のデバイスを制御できないように変更するよう依頼しました。開示後12時間以内にパッチが適用されました。iParcelBoxの対応は確認される限り最速のパッチ対応となりました。パッチをテストしましたが、もはや他のデバイスを制御したり、セットアップモードの状態から古い管理パスワードでデバイスにアクセスしたりすることはできませんでした。
iParcelBoxは、Androidアプリケーションが証明書を適切にピン留めしない点についても修正し、DynamoDBへのすべての直接呼び出しを削除しました。それでもFrida SSL Unpinnerを使用して一部の交信を復号化することはできましたが、アプリケーションがフリーズしました。これは、MQTTブローカーがカスタム証明書を承認しないためだと考えられます。DynamoDBクエリは、API呼び出しにラップされ、顧客IDもチェックします。これにより、第三者が抽出されたCognitoの認証情報を使用して、他人のデバイスから情報を取得することができなくなります。API呼び出し内にデータベースクエリをラップすることも効果的なセキュリティ修正です。データベースに収容する前にデータをすべて解析、検証、サニタイズできるためです。
私たちは、iParcelBoxのチームがこの製品の開発全体を通してセキュリティに重点を置いていることに敬意を表します。このデバイスとフォーラムの投稿から、開発者がデバイスの安全性を保とうと当初から努力し、うまく対応してきているのはすぐにわかります。UARTやBluetoothなどの必須ではない機能はすべてデフォルトでオフになっており、SSLの使用とフラッシュメモリの暗号化が示すように、データ保護に重点が置かれているのは明らかです。攻撃者がデバイスから利用できる攻撃対象範囲は多くなく、IOTデバイスのあるべき方向性を明確に示しています。
※本ページの内容は2020年6月18日(US時間)更新の以下のMcAfee Blogの内容です。
原文:My Adventures Hacking the iParcelBox
著者:Sam Quinn