引っ越し先の部屋にあった謎のIoT機器の正体をエンジニアが明らかにする過程
低レベルのRustエンジニアであるニキータ・ラプコフ氏が、引っ越し先の部屋に設置してあった謎のIoT機器が一体何であるのかを突き止める過程をブログに投稿しました。
What's that touchscreen in my room? | Nikita Lapkov
https://laplab.me/posts/whats-that-touchscreen-in-my-room/
アパートのさまざまな家電製品のマニュアルが入ったバインダーを調べると下図のパンフレットが出てきました。このパンフレットを見つけたことで、IoT機器がエネルギーの消費量を通知するものだと判明。
パンフレットには電力メーターに取り付けるデバイスについても記載されており、実際にラプコフ氏が電力メーターを見に行くと下図のデバイスが取り付けられていたとのこと。ぱっと見では何か分かりませんが、パンフレットと同じ「NetThings」というブランドが記されていたためラプコフ氏はこの機器がメーター側のデバイスだと判断しました。
パンフレットには「SSID」と「Pwd」が記されたシールが貼り付けてあり、メーター側のデバイスと表示用のタッチスクリーンはどうやらWi-Fiで接続される模様です。両者の距離は数メートルで、間に2〜3枚の壁があるだけだったため、ラプコフ氏はケーブルを通さずにわざわざWi-Fiを使用するという「無駄な複雑さ」があることに恐怖を抱いたとのこと。
ただし、IoT機器に詳しいラプコフ氏の友人によるとこうした近距離でもWi-Fiを使用することはIoT機器の分野では一般的だそう。ラプコフ氏は「IoTの『C』はコスト効率の頭文字に違いない」と記述しています。
タッチスクリーンをよく観察すると側面に小さな穴が空いています。
この穴をピンで押し続けるとAndroidタブレットが起動しました。かなり古いもので、2013年にサービスを終了したGoogle Talkや2020年に開発終了となったAdobe Flashなど興味深いアプリがインストールされていたとのこと。ラプコフ氏はアプリの中に「NetThings」という名前のものを発見し、起動してみるとWi-Fiの選択画面が表示されました。しかし、パンフレットに記載されたSSIDとパスワードを入力してみても接続できませんでした。
メーター側のデバイスを再度確認してみると、他の部屋のデバイスは電源が入っているのにラプコフ氏の部屋のデバイスには電源が入っていませんでした。
ラプコフ氏はイギリス在住で、イギリスでは全ての電源にヒューズが備わっています。今回のデバイスのヒューズボックスを開けてみるとヒューズが入っていませんでした。ラプコフ氏が3Aのヒューズを購入して設置するとメーター側のデバイスの電源が入ったとのこと。
今度はAndroidタブレットのアプリでパンフレットに記載されているWi-Fiを選択でき、接続すると下図の画面になりました。
タップするとメニューが登場。電力監視以外にも水道や暖房というメニューがありますが、実際には電力しか機能しなかったそうです。
電力監視モニターのメイン画面はこんな感じ。この画面について、ラプコフ氏は「UXデザイン史上最も残念な画面」と酷評しています。まず右側のインジケーターは何を表しているのか不明で、電力消費量だとしてもどの位置だとどれくらい消費していることになるのか分かりません。左側に表示される5つの数字についても実際に正しいのは「現在のエネルギー消費量のkW数」だけで、他の4つの数字は電力会社によって全く異なります。なお、パンフレットによると支払う金額やkWあたりのCO2の値などを設定するのは初期設定のみにおいて可能と記されていましたが、初期設定をやり直せるようにシステムをリセットする方法については記載されていませんでした。
おまけにパンフレットには「⏰日時は常に正しいため全く調整する必要はありません」と書かれていました。しかしこのデバイスはインターネットに接続していないため補正されるはずもなく、ほぼ15分のずれが発生していたとのこと。ラプコフ氏は「なぜこの記述をしたのか分かりません」とこぼしています。
ラプコフ氏は「全てがとても残念」としつつ、メーター側のデバイスのWi-Fiネットワークに直接接続してkW消費量を抽出できれば正しいレートにかけてGrafanaインスタンスに表示できると考えたとのこと。ノートPCからIPスキャンをしてメーター側デバイスのIPを割り出し、ブラウザでアクセスするとAndroidタブレットで見慣れた内容が表示されました。
ラプコフ氏は「ウェブで表示しているだけなのであれば開発者ツールで通信内容を見ればAPIが一発で分かるはず」と考えて通信を確認すると、なんとSocket.IOが使用されていました。今回のクライアントはサーバーから5つの数字を受け取るだけのため、Socket.IOは完全に過剰と言えます。クライアントのコードも動作の単純さからは考えられないような複雑な挙動をしており、6つのRequireJSモジュールが異なるリクエストに対して動的にロードされているとのこと。
ここで、ラプコフ氏は「Socket.IOが実行されているならメーター側のデバイスはJavaScriptを実行しているはず」と気づき、メーター側のデバイスをハックしてみることにしました。IoTにはセキュリティの頭文字である「S」もないのですぐできるだろうと高をくくっていたとのこと。
しかし、直接SSHを実行すると接続が拒否されてしまったため、ラプコフ氏はまずどのポートが利用可能なのかを調べることにしました。結果は下図の通りで、SSH用には41142番ポートが用意されていました。そのほか、DHCPサーバーやNode.jsサーバーに加えて「1534」番ポートを謎のサービスが使用していることが分かります。
SSH接続は拒否されなかったものの、rootはパスワードで保護されており、「admin/admin」や「root/root」など単純な組み合わせは通らなかったためラプコフ氏は1534番ポートを使用している「micromuse-lm」について調べることにし、下図の投稿を見つけました。この投稿によると「tcf-agent」というものが関連している模様。
tcf-agentについての調査は骨が折れるものだったとのこと。さまざまなサイトにパズルのピースが分散しているため横断的に読んで自分で組み合わせる必要があり、さらに用語を理解しないとサイトの情報を把握できませんでした。こうした調査の結果、ラプコフ氏が突き止めた「tcf-agent」の正体は下記の通り。
TCFはターゲットコミュニケーションフレームワークの略称で、テキストプロトコルであり、ファイルシステムの読み取りや新たなプロセスの開始、プロセスへの信号の送信などをターゲットシステムで行うことが可能です。TCFはEclipseエコシステムと密接に結びついており、ガイドではtcf-agentと対話するのにEclipse用のプラグインが提案されています。ただし、ラプコフ氏がプラグインをEclipseにインストールしようとすると依存関係が他の依存関係と競合してしまいインストールできなかったとのこと。
TCFプロジェクトにはPython SDKが存在しています。もちろんこのSDKを発見するまでには今回の調査の他の全てのことと同様にさまざまなウェブサイトのリンクを3回たどる必要がありました。
tcf-agentはシステムのさまざまな部分を公開するサービスを提供しています。例えばアクセス中のユーザー情報を取得するためのコマンドは下図の通り。このコマンドによってラプコフ氏はtcf-agentがrootユーザーで実行されることを突き止め、「こうしたルートへのアクセス権を放置したままなぜわざわざSSHにパスワードを設定する必要があるのか全く理解できません」と書いています。
tcf-agentを通してroot権限でファイルを取得できるようになったので、ラプコフ氏はまずSSHのパスワードの解読を試みたとのこと。しかし約7時間解読を続けたものの結局解読できず、ラプコフ氏は別の方法を試すことに。
Googleで調べたところ「/etc/shadow」を変更するだけでrootユーザーのパスワードを空にできることが判明。しかしこの手順を踏まえてもSSHのログインは拒否され、ラプコフ氏はsshdの設定ファイルを確認することにしました。するとSSH接続でrootによるログインを拒否する「PermitRootLogin no」という設定が行われていました。「非常に賢明なセキュリティ対策です。ネットワーク経由で完全なディスクアクセスを提供しない場合に限りますが」とラプコフ氏はコメントしています。
そしてようやくラプコフ氏はSSHでrootログインすることに成功しました。
このデバイスでは2013年半ばにリリースされたLinux 3.10が実行されており、デバイスが2014年から2015年に開発されたことを考えるとかなり新しいバージョンが使用されています。組み込みデバイスのためCPUにはARMのチップが使用されています。
CPUの詳細情報はこんな感じ。Wiiにも使用されているARM9ファミリーのチップが搭載されています。Javaのバイトコードの直接実行が行えるという特徴があります。
RAMの容量は118MBでした。ラプコフ氏は「私はLinuxの専門家ではないが、かなりの量だと思う」と記述しています。
ラプコフ氏は訴訟のリスクを負いたくないとしてソースコードの公開は避けましたが、ディレクトリの様子については公開しています。デバイスでは主に2つのアプリが実行されており、1つは「Pulse」というGPIOピンからデータを読み取ってCSVファイルに書き込むアプリ。
もう一つはCSVファイルからデータを読み出してウェブUIで表示するNode.jsのサーバーアプリです。
ラプコフ氏は最後にホームディレクトリに小さなメモを残すことにしました。「この文章を直接読むことになるのはおそらく私だけだと思う」と書きつつも「もしかしたら遠い将来、別のソフトウェアエンジニアがこのアパートに住んでこの文章を発見するかもしれない」と期待を記しています。
なお後日談として、ラプコフ氏はデバイスの時刻設定が誤っていてもウェブUIを開くと正しい時刻が表示される不思議な現象をmastodonで報告しています。この現象について調査してみたところ、ブラウザでウェブUIを開いた際に「/set-time/+Date.now()」にリダイレクトされており、このリダイレクトによって「現在」を担当しているNode.jsアプリにグローバル変数として時刻の情報が保存されるとのこと。アクセスしてくるPCの時刻データを利用して時刻を補正するこの仕組みについて「独創的で革新的な時刻同期メカニズム」とラプコフ氏は述べました。