- Sleep Number HubでUARTコンソールとU-Boot環境変数を使ってrootアクセスを取得すると、SleepIQサーバーを経由しないローカル制御経路を構築できる
- 既存のHomebridgeプラグインはSleepIQ APIを5秒ごとに呼び出しており、数千人規模のユーザー環境ではSleep Numberネットワークに負荷をかけたため、無効化を要請された
- 対象機器はSleep Number Hub 360SIQ01Dで、J16 UARTピン、115200 baudコンソール、FAT32またはExt3のUSBドライブ、SSH公開鍵の登録が重要な条件となる
- rootアクセス後はHubのPython 2.7.18と
/bam/scriptsを活用し、ポート8000のHTTPサーバー経由でベッド設定と状態をローカルネットワーク上で扱える
- HubはSleep Numberサーバーに対してSSHリバーストンネルを開けるため、ローカル制御が十分に整ったら外部インターネット接続を切り、Bluetoothや内部制御を使うほうが安全である
ローカルアクセスを探すことになったきっかけ
- 目標はSleepIQサーバーを経由せず、Sleep Numberベッドをローカルネットワークで制御することだった
- 以前に作成したhomebridgeプラグインでは、HomeKitや自動化からベッド設定を制御できた
- 特に人がベッドにいるかを示すbed presenceの値は、照明を消す、ドアを施錠するといった自動化に役立った
- このプラグインはSleepIQ APIを5秒ごとに呼び出しており、ユーザー数が数千人に増えるにつれてSleep Numberネットワークに負荷を与えた
- Sleep Numberはプラグインの無効化を要請した
- リポジトリのブランディングが公式Sleep Numberツールのように見える可能性があるという問題もあった
- その後、既存の作業は新しいhomebridge-bed-controlプラグインへと引き継がれた
- 新しいプラグインではbed presence監視をデフォルトで無効化し、有効化前に警告を追加している
Hubハードウェアで見つけたアクセス経路
- 当初はCPU近くのJ10ヘッダーを調べたが、UARTデータは得られなかった
- そのCPU構成ではUARTラインが出ていない状態だった
- 基板下側のJ16ヘッダーでUART信号を探すため、ロジックアナライザを10本のヘッダーピンに接続した
- UART-TTYデバイスを接続すると、デバイスコンソールにアクセスできた
- フラッシュをダンプしてファイルシステムや脆弱性を調べたが、UARTなしで誰でもログインできるバックドアは見つからなかった
- その代わり、Sleep NumberがHubへSSH接続できる保守用バックドアを発見した
- Hubは内部ホームネットワークに接続されているため、このアクセス経路は内部ネットワークへつながり得る
- Wi-Fi接続を切り、可能な限りBluetooth制御を使う運用が推奨される
準備物と対象機器
- 手順はSleep Number Hub 360SIQ01Dモデルで実施された
- 必要な機材はUART-TTYデバイスと基板接続用ツールである
- USB-C to UARTまたはUSB-A to UART
- Raspberry Pi Pico WはSSHが動作しない場合のリモートコンソール接続用として内部に恒久設置できる
- 2.54mmピンヘッダーとハンダごて、またはPCBクリップクランプ
- 基板と通信するにはシリアルコンソールが必要
- LinuxとMacでは
minicomが使える
- WindowsではPuTTYが使える
- USB-AフラッシュドライブはFAT32またはExt3形式でなければならない
- 使用中のHubにすでにUSBデバイスが挿さっている場合、それはWi-Fiドングルの可能性があり、このデバイスがないとブートループが発生することがある
rootアクセス手順の要点
- UARTデバイスは基板のJ16ヘッダーに接続する
- pin 1: TX、Hubへ入る信号
- pin 2: RX、Hubから出る信号
- pin 3: ground
- シリアルコンソールは115200 baudに設定する
- Hubの電源投入後2秒以内にSpaceキーを押し、自動起動を停止する
- U-Boot環境変数はまず
printenv -aでバックアップしておく必要がある
- デフォルト値への復旧が必要になる場合があるため、現在の環境との差分を記録しておくべきである
bootcmdではrun set_bootargs;の部分を削除し、ブート引数を手動で設定できるようにする
/initスクリプトはハッシュ化されたbootrom内にあり直接修正できないため、bootargsで実行時に/initの内容を変更する
- デフォルトのスクリプトは
let_me_rootという文言で復号される暗号化ファイルを探す
- 復号処理の行を復号後の値に置き換えることで、暗号化ファイルの要件を回避する
- 最初の起動時には
let_me_rootファイルを含むUSBドライブが必要
- 起動後にコンソールで
root@bam-se:~#プロンプトが表示されれば、rootシェルに入れている状態である
- その後はrootパーティションを読み書き可能で再マウントし、
/root/let_me_rootファイルを作成して、USBなしでもアクセスを維持できるようにする
SSHアクセスの設定
- rootプロンプト取得後は、SSH公開鍵を
/root/.ssh/authorized_keysに追加してネットワーク接続を設定する
- 接続元のローカルマシンでSSH鍵を生成する必要がある
- 例のコマンドは
ssh-keygen -t ed25519
- 説明文では
ecdsa鍵を推奨しているが、実際の例ではed25519を使っている
- 公開鍵追加後は
ssh root@$hub_ip -i <path to id_ed25519>の形で接続をテストする
- 接続できない場合は
authorized_keysの形式とファイル内容を確認する必要がある
ローカルネットワーク制御サーバーの構築
- rootアクセスだけではベッドアプリの制御機能を置き換えにくいため、Hub内でローカルHTTPサーバーを起動する
- HubにはPython 2.7.18が含まれている
- Hubの最終更新は2018年に見える
- Python 2.7.18には必要な機能を提供する
simpleHTTPServerパッケージがある
script_server.pyはポート8000でHTTPサーバーを開き、/bam/scripts内のスクリプトを実行する
- URLパスがスクリプト名になる
argクエリパラメータを複数渡してスクリプト引数として使える
- 実行結果はブラウザに表示される
- スクリプトは
scp -O script_server.py root@$hub_ip:~の形でHubへコピーする
- 再起動後に自動起動させるには、起動スクリプトに追記するか
rc.dスクリプトを追加する必要がある
再起動後の自動実行設定
- 実行中のOSインスタンスは、bootloaderの
/initスクリプトが作成したchroot内で動作している
- 多くのシステムファイルは
tmpfsパーティションに保存されており、直接修正しても再起動後には保持されない
- 元ファイルがあるディスクパーティションを別途マウントすれば、再起動後にコピーされる元の
/etcファイルを修正できる
script_server.sh形式のinitスクリプトを作成してHubへコピーし、元のrootパーティションのtmp/etc/init.dに配置する
rc0.d、rc3.d、rc4.d、rc5.d、rc6.dにシンボリックリンクを追加し、起動時と終了時に実行されるよう設定する
- 再起動後にブラウザで
http://$hub_ip:8000/bamstatへアクセスしてHubの状態情報が見えれば、サーバーは正常に動作している
/bioスクリプトで可能な制御
/bioはベッドの主要な制御スクリプトと思われる
- コマンドは
/bio?arg=XXXX形式で渡す
- Sleep Number値の取得と設定が可能
PSNL, PSNR: 左右ベッド側の最後の設定値を取得
PSNl, PSNr: 左右ベッド側の現在値を取得
PSNX: 両側の最後の設定値と現在値を取得
PSNS&arg=L100: 左側のSleep Number値を100に設定、値の範囲は5..100
- 在床検知とプライバシー設定も扱える
SPAU: プライバシー設定を取得
SPAU&arg=on: プライバシー設定を有効化、offで無効化
LBPL, LBPR, LBPX: 左側、右側、両側の在床値を取得
- Responsive Air、ベッド位置、照明、足元加温機能も含まれる
LRSG: 両側のResponsive Air設定を取得
LRLE&arg=on, LRRE&arg=off: 左右のResponsive Air設定を変更
MFST: 頭部と足部の位置を取得
MFUL, MFUR, MFFL, MFFR: 左右の頭部・足部位置を設定
MFO3, MFSO: アンダーベッド照明またはコンセントの状態と明るさ・タイマーを設定
FWGL, FWGR, FWSL, FWSR: 左右の足元ヒーターのレベルとタイマーを取得・設定
SBAS: ベッド基準値を設定
/bio?arg=helpは実行可能なコマンド一覧を表示する
help呼び出しの第2引数としてコマンドを追加すると、そのコマンドの詳細情報が表示される
bioスクリプトにはfoundation preset、いびき設定、DualTemp制御、状態情報も含まれる
factory resetやradio制御のような破壊的コマンドには注意が必要
- 筆者が使用した
bioバージョンではMFSO項目の順序がLIST内で誤っており、呼び出すには数行上へ移動する必要があった
アクセス後に調べられる領域とセキュリティ上の懸念
- ベッド制御機能は
/bamルートディレクトリに集約されている
- この中の各種スクリプトを見れば、Hubがどのように動作しているかを確認できる
- UARTなしでアクセス可能なバックドアを探そうとしたが、明確なアクセス経路は閉じられていた
- HubはSleep Numberサーバーと通信する際にSSHトンネルを開き、開発者が保守に使えるリバーストンネルを提供している
- 外部利用者が内部ホームネットワークへ直接接続できる可能性があるため、内部ネットワーク制御スクリプトが十分に整ったらHubの外部インターネット接続を切る方法を検討している
- SleepIQアプリを直接置き換えられるシンプルなProgressive Web Appも次の段階の候補である
1件のコメント
Hacker News のコメント
かなりばかげている。昔こういうベッドを使っていたが、すべてがスマートになる前の話だった。ポンプには有線コントローラーが2つ接続されていて、コントローラーには数字表示と上下の調整ボタンがあった。
インターネットも不要、Linux ベースのマイクロコントローラーも不要、ベッドがハックされることもなく、快適に眠れた。
たとえばパーキンソン病から四肢麻痺まで、何らかの運動障害があるなら、音声や標準化された入力方式で動作する共通コントローラーにつながることは大きな利点になり得る。製品ごとにばらばらなアクセシビリティ上の制約に個別に対処しなくて済むからだ。
体に不自由のない人にはスマートホーム機器の大半がほとんど役に立たないように見えるが、別の人にとっては命綱になり得る。
「ハブが Sleep Number のサーバーと通信するときに SSH トンネルを開き、開発者が必要なときにハブへ接続してメンテナンスできるようリバーストンネルを提供する」という部分が気になる。
公開鍵認証を使っているのかパスワードなのか、家へトンネルするときに IP を使うのか DNS を使うのか見てみたい。条件がぴったり揃えば、人類史上いちばん笑えるDNS ハイジャック構成が可能になりそうだ。
Homer Simpson の不朽の表現を借りれば、ベッドが上がり、ベッドが下がる。
新式: Sleep Number のベッドは注文情報とひも付いているので、Sleep Number に侵入して標的を見つけ、その人のベッドに SSH で接続し、家庭内ネットワークへピボットして暗号資産ウォレットを盗む。
どうせお金はいつもマットレスの下に隠すものだから ;)
ベッドがなぜ Linux を動かす必要がある? なぜ?
あり得るすべての時間線の中で、いちばん間抜けな場所に生きている気がする。1GB RAM と完全な OS が入っていない普通のベッドの何が問題だったのか。どこも同じだ。Wi‑Fi に接続しない洗濯機を探すのも一苦労だったし、10年後にまたそれをやることを考えるとぞっとする。
趣味であれ金稼ぎであれ、O(1000) 個くらいの「スマート」機器を破ってきた立場からすると、こういう物を家に入れたくない。だがこうしたLinux 駆動ベッドのような狂気のせいで、避けるのがどんどん難しくなっている。頼むからやめてほしい。
ただ、空のビニールレコードを持って公共図書館まで行き、ソフトウェア更新を受け取っていたことは懐かしくない。うっかりするとトコジラミが出たからだ。
「自分が持っている最新のテック製品は2004年製のプリンターで、予期しない音を出したら即撃つために装填済みの銃を用意している」
1世紀前には抗生物質を見つけ、それは大きな前進だった。その後、明確な病気と明確な治療法をたくさん見つけ、今は複雑で微妙なものが残っている。このベッドは睡眠状態を知らせるために Linux を動かしている。
よく眠れないと、一般に弱いながらもさまざまな悪影響が出るし、それを知れば改善できる。毎晩低強度の睡眠検査をしてくれるようなものなので、価値ある情報になり得る。
Sleep Number のベッドは数千ドルするので、避けようと思えば十分避けられると思う。
財布にも大きな得だし、まだ使える物を埋立地へ送らずに済む満足感も大きい。減らす、再利用する、リサイクルする、というのは重要度の順そのものだ。
最初はこの記事を、法的な理由で会社名を直接言いたくない人が Eight Sleep のベッドのハックを扱ったものだと完全に思い込んでいた。
ところが実在するらしい「Number Sleep Hub」の写真を見て頭がおかしくなった。水冷ベッドを作る会社が2社もあり、片方が Eight Sleep、もう片方が Sleep Number だなんて、この時間線はあまりにも変だ。このインスタンスの乱数生成器が悪いシードを受け取った感じがする。
https://i.ytimg.com/vi/pMiTq6YkJ2c/maxresdefault.jpg
人々は文字どおり、上にフォームが載った高級な調整式エアベッドに数千ドルを払っているわけだ。
こういうベッドには、暗い場所でも手探りで使える物理コントロールがあってほしい。眠ろうとしている最中に調整するためスマホを顔の前に取り出さなければならないのなら、ベッドとマットレスのメーカーが睡眠の質に何が良くて何が悪いのか本当に分かっているのか疑わしい。
Eight Sleep Pod 3にも同じように入る方法がある [0]。一部のモデルには書き換え可能な MicroSD カードが入っているため、追加のハードウェアは少なくて済む
本文の方法は、カードがない Pod で root 権限を得るには良い方法かもしれない。ただ、今知ったのは、Eight Sleep はファームウェア更新に署名しているものの、その更新に署名するために使う秘密鍵も同じパッケージで送ってくるという点
[0]: https://github.com/bobobo1618/ninesleep
もちろん2,000〜4,000ドルは高いが、10年くらい使う一度きりの費用だと考えれば妥当ではある。でも4,000ドル払ったうえに月25ドルも払えというなら、あり得ない
Eight Sleep でも同じことをした人がいるのか気になる。インターネットが切れたという理由でベッドの温度を調整できないというのは、本当にかなり気に障る
Sleep Number は買わない
何年も空気注入式マットレスで寝ていたが、メーカーが中国に外注し始めた後、内部隔壁の縫い目が2つのマットレスで破れた
「このガイドに従うと Sleep Number ハブの内部ファイルを変更する必要があり、保証が無効になる」みたいな戯言を広めるのはやめてほしい
「剥がすと保証無効」ステッカーが法的に執行できないのと同じで、誤用や不十分なメンテナンス以外で製品保証を自動的に無効化するものはない
スマートベッドが壊れたときにコントローラーをいじったという理由だけで、メーカーが保証義務から逃れられるわけではない。黙示保証も含まれる。消費者が製品を壊した、または「不合理な」方法で使った、あるいは適切にメンテナンスしていなかったことを立証する責任はメーカー側にある
JTAG を接続しようとして、うっかり 5V を 3.3V のロジック回路にブリッジしてベッドの頭脳を焼いてしまったなら、それは自分の責任
だが電源装置が吹っ飛んでコントローラーが故障したのなら、JTAG ヘッダーを付け、目玉シールを貼り、ピンク色に塗ったという事実は関係ない。修理すべきだ
ファームウェアを変更していたとしても、その変更が故障の原因だとメーカーが立証しなければならない
ノート PC でゲームをして発熱が多いからといって、保証が無効になるとは考えない。Firefox をインストールしても Linux をインストールしても同じだ。なのに、デバイスが少し「間抜け」だからといってルールが変わると考える理由はない
次はランサムウェアだろう。「1,000ドル払わなければ、これから1か月お前のベッドで眠れなくしてやる」
いくつか事実を見てみよう
Sleep Number のベッドには心拍数を検知するセンサーが入っている。エアマットレス内の圧力差を検知してそれを行う。実質的にはマイク同然で、かなり敏感だ
調べてみると、かなりもっともらしい統計解析を組み合わせて、十分に正確なデータを得ているようだ。興味深い