ライトアウト:たった一つの小さなメッセージがShelly Pro 4PMをクラッシュさせ、スマートホームから締め出す方法

ライトアウト:たった一つの小さなメッセージがShelly Pro 4PMをクラッシュさせ、スマートホームから締め出す方法

Shelly Pro 4PMは、4つの電気回路を監視・制御するためのスマートなネットワーク接続リレーです。 家庭、スマートビル、軽工業環境などで使用され、機器のオン/オフ制御、電力測定、ウェブインターフェースやAPIを介した自動化プラットフォームとの連携を実現します。Nozomi Networks 研究により重大な問題が発見されました:デバイスのリモート制御インターフェースに過剰なサイズの要求を送信することで、攻撃者(あるいは誤動作する統合システム)がShelly Pro 4PMの再起動を強制できるのです。 突然自宅が暗闇に包まれる可能性があり、設定によってはガレージやゲートの遠隔操作が不能になる恐れがあります。このサービス拒否(DoS)行為は単一機能に限定されず、30のAPIメソッドに影響を及ぼすため、特別な権限なしに繰り返し障害を引き起こすことが可能です。 本ブログ記事では、この脆弱性の開示に加え、Shelly Pro 4PMの組み込みファームウェア解析、RPCメカニズムコードのリバースエンジニアリング、および本機能によって露呈する攻撃面の発見に至る全手順を公開します。我々が用いた手法を共有することで、他の研究者も同様の手法を用いて類似の標的を探索し、連携型ホーム/ビルシステム全体のセキュリティ水準を共同で向上させられることを願っています。

リサーチ範囲

Shelly Pro 4PMは、各チャンネルに電力計測機能を備えた4チャンネルスマートリレーです。DINレールに取り付け可能で、イーサネット、Wi-Fi、またはBluetoothで接続します。設定と日常的な制御はローカルWebダッシュボードを通じて行われます。ローカルネットワークに接続後、本デバイスはダッシュボードを公開し、ユーザーは以下の機能を含む製品の全機能を容易に管理できます:

  • リレーのオン/オフ切替
  • 電力のリアルタイム測定値を表示
  • スケジュールとタイマーを設定する
  • MQTT、WebSocket、クラウドアクセスなどのオプションを設定する

各リレーチャンネルは単一の回路を制御し、「電源投入時の動作」設定により再起動後の状態(オン、オフ、前回状態復元、入力に一致)が決定されます。デバイスが予期せぬ障害で再起動した場合、一時的に応答を停止します。オンライン状態に戻ると、各チャンネルはこの設定を適用します。 チャンネルがオフ状態に戻った場合(再起動時など)、そのチャンネルが制御する回路(照明、Wi-Fi・インターホン・ガレージ/ゲート制御装置の電源コンセントなど)は、電源を復旧させるかリレーを切り替えるまで停止したままとなります。

図1. Shelly Pro 4PMによって公開されるWebダッシュボード。

Modern Shelly (Gen2+) デバイスは、サードパーティ製ソフトウェアがネットワーク経由で同様の操作を実行できるように、リモートプロシージャコール (RPC) API も提供します。この API は JSON‑RPC 2.0 に準拠し、HTTP、WebSocket、MQTT の複数のチャネルで利用可能です。当社の調査では、広く使用されテストが容易な HTTP RPC チャネルに焦点を当てました。 具体的には、HTTP RPCとやり取りが必要なクライアントは、ID、メソッド、およびオプションのパラメータを含むJSONをボディとしたHTTPリクエストを/rpc APIに送信するだけで済みます。例えば、KVS(キーバリューストア)ペアの一覧を取得する必要がある場合、以下のパラメータでKVS.Listメソッドを使用できます:

$ curl -X POST -d '{"id":1,"method":"KVS.List","params":{"match":"項目"}}' http://${SHELLY}/rpc

一部の項目が見つかった場合、次のような応答が返されます:

{

 "id": 1,

 "src": "shellyplus1-a8032abe54dc",

 "params": {

   "keys": {

     "item1": {

       "etag": "0DWty8HwCB"

     },

     "item2": {

       "etag": "0DMHqWL0P0"

     }

   },

   "rev": 2744

 }

}

このAPI内では、キーバリューストア(KVS)メソッド(KVS.List、KVS.Get、KVS.GetMany)だけでなく、ユーザー入力を文字列として処理する全てのメソッド(例:Shelly)を詳細に検証しました。これにより、ファームウェアが信頼できない入力をどのように処理するか検証を必要とする攻撃ベクトルに適した対象となりました。

これらの脆弱性の影響

Shelly Pro 4PMのJSON-RPCインターフェースで確認された入力処理の脆弱性は、特にリレーが重要な負荷を制御している場合に、重大な運用リスクをもたらす可能性があります。以下に、この脆弱性を悪用することで発生し得る攻撃シナリオの例を示します:

  • 制御の否定 (T0813)。巧妙に作成された過剰なリクエストにより、デバイスが再起動を余儀なくされる可能性があります。これらの事象が発生すると、リレーが一時的に利用不能となり、スケジュールの未達成、遠隔操作の喪失、サービス中断を引き起こす恐れがあります。リクエストが繰り返されると、ダウンタイムが長期化し、保守作業が増大する可能性があります。
  • 閲覧拒否 (T0815)。デバイスの再起動中は、電力計測データとステータス更新が利用できません。これによりダッシュボードやアラートに盲点が生じ、異常な消費の検知やコマンドが有効になったことの確認が困難になります。
  • 安全性の喪失 (T0880)。リレーがポンプ、ヒーター、ゲート、照明などの機器を制御している場合、リレーの故障によりオン/オフ動作が遅延したり、スタッフが介入するまで回路が望ましくない状態に放置されたりする可能性があります。タイムリーな切り替えに依存する施設(例:空調設備や水循環システム)では、これが不快感、プロセス逸脱、または機器への負荷増加につながる可能性があります。

要約すると、この脆弱性はデータ窃取やコード実行を可能にするものではないものの、可用性を繰り返し低下させる性質から、家庭用およびビルオートメーションの両環境において重大な信頼性上の懸念事項となる。

脆弱性リストと影響を受けるバージョン

Nozomi Networks 、Shelly Pro 4PMバージョン1.4.4において以下の問題をNetworks :

CVE IDCWECVSS v3.1 ベーススコアCVSS v3.1 ベクトル
11243制限やスロットリングのないリソースの割り当て(CWE-770)8.3CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H 


脆弱性スポットライト

ファームウェアイメージの収集

Shelly Smart Control Androidアプリを使用すれば、クラウド経由またはローカル接続で、どこからでもすべてのShellyスマートホームデバイスを簡単に管理できます。このアプリを通じて、ファームウェア更新などShelly Pro 4 PMの全機能を設定・管理することが可能です。  

図2. シェリー・スマートコントロール。

Androidアプリのファームウェア更新チェック機能を活用したところ、診断ウェブページで以下のログメッセージを確認しました:

shelly_http_client.:303 0x3ffef5ec: HTTPS GET https://updates.shelly.cloud/update/Pro4PM (CA shelly_cloud.pem,ca.pem)  

このHTTPエンドポイントにアクセスしたところ、最新のファームウェア更新プログラムの保存場所が表示されることが判明しました:

$ curl -k -v https://updates.shelly.cloud/update/Pro4PM

{

 "stable": {

   "version": "1.4.4",

   "build_id": "20241011-114451/1.4.4-g6d2a586",

   "url": "https://fwcdn.shelly.cloud/gen2/Pro4PM/76cfaf1e4bb3cb311c0f752b1c17c3d58aa217e3934361df56090ac0567ae86c"

 },

 "時間": 1731591067

}

この情報を得て、以下のコマンドでファームウェアイメージのダウンロードに成功しました:

$ wget --no-check-certificate "https://fwcdn.shelly.cloud/gen2/Pro4PM/76cfaf1e4bb3cb311c0f752b1c17c3d58aa217e3934361df56090ac0567ae86c"

シェリーファームウェア分析

ダウンロードしたファームウェアイメージは、以下の内容を含む暗号化されていないZIPアーカイブファイルです:

$ unzip -l 76cfaf1e4bb3cb311c0f752b1c17c3d58aa217e3934361df56090ac0567ae86c.zip

アーカイブ: 76cfaf1e4bb3cb311c0f752b1c17c3d58aa217e3934361df56090ac0567ae86c.zip

 長さ 日付 時間 名前

--------- ---------- ----- ----

    1598 1980-00-00 00:00 manifest.json

   25280 1980-00-00 00:00 bootloader.bin

    4096 1980-00-00 00:00 partition-table.bin

    8192 1980-00-00 00:00 otadata.bin

 1961872 1980-00-00 00:00 Pro4PM.bin

  524288 1980-00-00 00:00 fs.img

--------- -------

 2525326 6ファイル

manifest.jsonファイルを分析すると、対象ハードウェアアーキテクチャがESP32であること、およびデバイスフラッシュメモリ内の*.binファイルが格納されるマッピング情報が判明します:

$ head -n20 manifest.json

{

"name": "Pro4PM",

"プラットフォーム": "esp32",

"version": "1.4.4",

"build_id": "20241011-114451/1.4.4-g6d2a586",

"build_timestamp": "2024-10-11T11:44:51Z",

"parts": {

 "boot": {

  "type": "boot",

  "src": "bootloader.bin",

  "addr": 4096,

  "size": 25280,

  "cs_sha1": "4943c9bbc147d5af910876b0b8ddcba6f072a144",

  "cs_sha256": "2c3c7a476d016023b74a5975a42b39c397c360ec921cecebc3876656ba64eaa3",

  "encrypt": true,

  "min_version": "1.0.0"

 },

esp32knife GitHubプロジェクトのesp32partgen.pyスクリプトを使用すると、partition-table.binファイルから追加情報を抽出できます:

$ python3 esp32partgen.py --no-verify partition-table.bin

バイナリパーティション入力の解析中...

# ESP-IDF パーティションテーブル

# 名前, タイプ, サブタイプ, オフセット, サイズ, フラグ

nvs ,データ ,nvs ,0x9000 ,16K,

otadata ,data ,ota ,0xd000 ,8K ,暗号化済み

app_0 ,app ,ota_0 ,0x10000 ,2M ,暗号化済み

fs_0 ,データ ,spiffs ,0x210000 ,512K ,暗号化済み

app_1 ,app ,ota_1 ,0x290000 ,2M ,暗号化済み

fs_1 ,データ ,spiffs ,0x490000 ,512K ,暗号化済み

補助 ,85,0 ,0x510000 ,2992K ,

shelly ,データ,136 ,0x7fc000 ,16K ,暗号化済み

パーティションテーブルとブートローダーを超えて、app_0 セクションと app_1 セクションが、Shelly Pro 4PM デバイスが提供するすべてのコア機能を実装する中核ファームウェアイメージであるメインの Pro4PM.bin 実行ファイルを保持する 2 つのスロットであることは明らかです。

Espressifのesptool.pyを使用すると、Shellyアプリケーションの情報を取得できます:

$ python3 esptool.py -c esp32 image_info Pro4PM.bin

esptool.py v3.0-dev

警告: 一部の予約済みヘッダーフィールドにゼロ以外の値が設定されています。この画像は新しいバージョンのesptool.pyで生成された可能性があります。

画像バージョン: 1

エントリポイント: 400812ac

6つのセグメント

セグメント 1: 長さ 0x43614 ロードアドレス 0x3f400020 ファイルオフセット 0x00000018 チェックサムに含める=True [DROM]

セグメント 2: 長さ 0x00004 ロード 0x3ff80000 ファイルオフセット 0x00043634 チェックサムに含める=True [RTC_DRAM]

セグメント 3: 長さ 0x03b90 ロード 0x3ffbdb60 ファイルオフセット 0x00043640 チェックサムに含める=True [BYTE_ACCESSIBLE, DRAM]

セグメント 4: 長さ 0x08e38 ロードアドレス 0x40080000 ファイルオフセット 0x000471d8 チェックサムに含める=True [IRAM]

セグメント 5: 長さ 0x178a00 ロード 0x400d0020 ファイルオフセット 0x00050018 チェックサムに含める=True [IROM]

セグメント 6: 長さ 0x16544 ロードアドレス 0x40088e38 ファイルオフセット 0x001c8a20 チェックサムに含める=True [IRAM]

チェックサム: b0 (有効)

検証ハッシュ: 6fac70b80f2abbdfaa0adefe525df09d0e87bd36b27fea40441e3112f0445b60 (有効)

フラッシュメモリイメージの再構築

esp32knifeなどの一般的なESP32リバースエンジニアリングツールは、解析入力として単一の連続したフラッシュイメージを想定しています。このため、8MBフラッシュメモリ(すなわち シェリー・フラッシュ.bin ファームウェア更新ZIPアーカイブ内の個々のバイナリファイルから生成されるバイナリファイル。これらのバイナリファイルを配置すべき場所は、 manifest.json ファイルと、パーティションテーブル解析後に返される出力。このタスクを実行する擬似コードは以下の通りです:

FLASH_SIZE = 8 * 1024 * 1024

flash = bytearray(FLASH_SIZE)

place('bootloader.bin', 0x1000)

place(‘partition-table.bin’, 0x8000)

place('otadata.bin', 0x00_0D000)

place('Pro4PM.bin', 0x00_10000) # app_0

place('fs.img', 0x00_210000) # fs_0

place('Pro4PM.bin', 0x00_290000) # app_1

place('fs.img', 0x00_490000) # fs_1

write('shelly_flash.bin', flash)

最後に、Shellyファームウェアのバイナリにはオリジナルのesp32knifeツールがサポートしていないセクションが存在したため、以下の変更で修正しました:

図3. Shellyファームウェアをサポートするためのesp32knife.pyへのパッチ。

これらのパッチを適用した後、再構築されたフラッシュメモリを適切に解析し、静的解析ツールによるリバースエンジニアリングが可能な最終的なELFファイルを生成することができました:

$ python3 esp32knife.py --chip esp32 load_from_file shelly_flash.bin

出力ディレクトリを準備する:

   - ディレクトリの作成: 解析済み

   ファームウェアを読み込み中: shelly_flash.bin

   警告: 一部の予約済みヘッダーフィールドにゼロ以外の値が設定されています。この画像は新しいバージョンのesptool.pyで生成された可能性があります。

   ブートローダーを書き込む先: parsed/bootloader.bin

...

  プログラムヘッダーの追加

   セクション .iram0.vectors と .iram0.text を一つのプログラムセグメントに結合する

   prg_seg 0 : 3f400020 00043614 読み書き可能 .flash.rodata

   prg_seg 1 : 3ff80000 00000004 rw .rtc.dummy

   prg_seg 2 : 3ffbdb60 00003b90 読み書き .dram0.data

   prg_seg 3 : 40080000 0001f37c 読み書き実行可能 .iram0.vectors

   prg_seg 4 : 400d0020 00178a00 rx .flash.text

   プログラムヘッダー:

プログラムヘッダー:

   タイプ オフセット 仮想アドレス 物理アドレス ファイルサイズ メモリサイズ フラグ アラインメント

    1 0000029b 3f400020 3f400020 00043614 00043614 6 1000

    1 000438af 3ff80000 3ff80000 00000004 00000004 6 1000

    1 000438b3 3ffbdb60 3ffbdb60 00003b90 00003b90 6 1000

    1 00047443 40080000 40080000 0001f37c 0001f37c 7 1000

    1 000667bf 400d0020 400d0020 00178a00 00178a00 5 1000

ELFを解析済み/part.4.app_1.elfに書き込んでいます...

ストリップされたELFに関する情報の復元

予想通り、Pro4PM.elf(すなわち part.4.app_1.elf)実行ファイルにはシンボルが含まれていない。この状況を部分的に克服するため、ファームウェアがアプリケーションのデバッグに一連のロギング関数を使用していることを確認した:

図4. ファームウェアで使用されるデバッグ関数の擬似コード。

ご覧の通り、一部のログは関数が存在するソースコードを報告する一方、他のログは元の関数名も明示しています。これらのログ機能のおかげで、関数を自動的にリネームするGhidraスクリプトを開発しました。

例えば、関数が次のデバッグ関数を使用する場合:

FUN_401acb04(0,"shos_dns_sd_packets.cpp",0xc2,(byte *)"ドメイン解析: %zu %d ",*param_3,0);

そしてその元の名称は FUN_4011fa20その後、そのファイルは次のように名前が変更されます:

shos_dns_sd_packets.cpp--FUN_4011fa20

これらの手順により、未知の関数を対応するソースコードファイルにグループ化し、Shelly Pro 4PMのファームウェアにおけるそれらの使用方法を部分的に理解することができました。

脆弱性研究

我々の研究の次の段階では、Shelly Pro 4PMファームウェアがRPCメカニズムをどのように実装し処理しているかを特定することを目的とした。既知のRPCメソッドを検索することで、各関数群(例:KVSメソッド)が専用の関数によって登録されていることを容易に確認できた。以下の証拠が示すように、 shos_rpc_inst.c--FUN_40127840 関数は、KVSメソッド(例: KVS.リスト対応するハンドラ関数(例: shelly_kvs_rpc.cpp--handle_KVS.List).

図5. KVSメソッドのハンドラを登録する関数。

以下の証拠が示すように、各メソッドハンドラが最初に実行する命令の一つは、Cesantaが開発したオープンソースのFrozenライブラリの一部であるjson_scanf関数を呼び出すことです:

int json_scanf(const char *str, int str_len, const char *fmt, ...);

図6. KVS.List関数は内部でFrozen json_scanfメソッドを使用している。

json_scanf関数の使用例は以下の通りです:

json_scanf(str, strlen(str), "{match: %Q}", &s)

str変数が指す場所 "{match: AAAAA…}" RPCから引数として受け取った文字列。

Frozenライブラリのソースコードを分析した結果、同ライブラリの%Qフォーマット指定子が文字列値のメモリ割り当て時に適切な境界チェックを行っていないことを確認しました。クライアントが極端に長いマッチ値を含むRPCリクエストを送信すると、パーサーは文字列全体を格納するのに十分な領域を割り当てようとします。しかし、リソース制約のあるデバイスでは、これによりヒープメモリが枯渇し、対象デバイスでクラッシュまたは再起動が発生します。

図7. %Q フォーマット文字列は内部で malloc 関数を呼び出す。  

このクラッシュはHTTP RPCチャネル経由で簡単に再現できます。例えば、以下のURLにHTTP POSTリクエストを送信することで再現可能です: KVS.リスト 特大のマッチ紐付き:

$ curl -X POST -d '{"id":1,"method":"KVS.List","params":{"match":"AAAA…"}}' http://${SHELLY}/rpc

この発見は、以下の理由により極めて重要である:

  • 事前認証脆弱性。この脆弱性は、認証検証やアクセス制御リスト(ACL)がチェックされる前の初期解析段階で発生します。
  • ユニバーサル攻撃ベクトル。メソッド検証の前に解析が行われるため、存在しないメソッドを含むあらゆるRPCメソッド名を使用して脆弱性を引き起こすことが可能ですさらに、HTTP、WebSocket、MQTTなど、RPCメカニズムを公開するすべてのネットワークプロトコルにおいて、まったく同じ結果を再現できます。

結論と改善策

当社の調査により、Shelly Pro 4PM v1.4.4において複数のJSON-RPCメソッドへの予期せぬ入力がリソースを枯渇させ、デバイスの再起動を引き起こす可能性があることが判明しました。この問題はコード実行やデータ窃取を可能にするものではありませんが、体系的に繰り返し発生する障害を引き起こすために悪用される可能性があり、家庭環境およびビル環境における自動化ルーチンと可視性に影響を及ぼします。

この種の攻撃から身を守るための最も効果的な対策は以下の通りです:

  • ファームウェアの更新を適用してください。ローカルWebインターフェースまたはShelly Smart Controlアプリケーション経由で利用可能になり次第、バージョン1.6.0(またはそれ以降)に更新してください。
  • 露出を最小限に抑える。インターネットへの直接露出を避ける。ウェブおよび/rpcアクセスを信頼できる管理ネットワークまたはVPNに制限する。

組織が脆弱なデバイスが自社環境に存在するかどうかを迅速に特定し、運用障害や侵害、さらなる攻撃の進展につながる前に悪用試行を検知・警告するために、お客様Nozomi Networks IoT の高度な機能を活用できます。本プラットフォームはネットワークトラフィックとデバイス動作に対する深い可視性を提供し、IoT にわたる効果的な脆弱性および脅威の検知を実現します。

図8. Shelly Pro 4PMの脆弱なデバイスの検出。

図9. Shelly Pro 4PM アセットに関するCVE-2025-11243の詳細。

図10. CVE-2025-11243の悪用試行の検出

この積極的な監視により、セキュリティチームは脆弱性や攻撃に迅速かつ効果的に対応でき、重要ネットワークを標的とした攻撃の影響を最小限に抑えます。Nozomi Networks IoT 詳細と実際の動作を確認するには、今すぐデモをご請求ください

Networks 使命に沿い、当社の目標は、運用者やベンダーに実用的な知見を提供し、接続システムの信頼性を強化することです。このため、スマート環境をサイバーセキュリティ攻撃からより安全かつ強靭にする方法について、責任を持って協業し、知識を共有し続けてまいります。

見つかりませんでした.
見つかりませんでした.