iPhone 4脱獄 その1: 侵入点の確保
(axleos.com)- gala は iPhone 4向けの iOS 4 脱獄を自力で実装するプロジェクトであり、第1部では古いデバイスで SecureROM 脆弱性を利用して 初期コード実行 を得る過程に焦点を当てる
- iOS の起動は SecureROM が LLB または iBSS を検証し、その後の段階が次の段階を検証する 信頼の連鎖 へと続き、SecureROM は製造後のアップデートで置き換えられない
- limera1n は A4 SoC の SecureROM を対象に、DFU モードで iBSS 転送を待つデバイスを攻撃し、USB 制御メッセージのファジングで発見されたクラッシュがヒープオーバーフローとシェルコード実行につながるとみられる
- pod2g の SecureROM dumper を参考に、
0x84000000の通信領域と0xA1:2の USB 読み取りリクエストを活用し、SecureROM ダンプとデバッグ値をホストへ取り込む流れを再実装する - Rust で書いたペイロードを Mach-O の
__TEXT,__textからシェルコードとして抽出して実行するパイプラインを作ったが、静的文字列が__constに配置されるため、命令ポインタ相対アドレッシング とアセンブリ配置が必要になった
iPhone 4脱獄プロジェクトの出発点
- gala は iPhone 4向け iOS 4 脱獄 を作るプロジェクトで、この文書はその第1部「Gaining Entry」に当たる
- 以前の iOS tweak 開発経験は、Cydia 配布、SpringBoard 機能の変更、Objective-C ランタイムの直接利用、クローズドソースバイナリのリバースエンジニアリングへとつながっていた
- 自分で脱獄を書こうとした目的は、脱獄のプロセスが実際にどう動くのかを理解することにある
- この作業は p0sixninja と axi0mX がオープンソースで共有した知見に大きく依存している
古い iPhone と Boot ROM 脆弱性の選定
- 最初の一歩は eBay で iPhone 4 と iPhone 3GS を購入することだった
- 最新の Xcode では古い iOS バージョン向けターゲットが許可されず、2010年代のやり方でアプリをビルド・インストールする道はすぐに閉ざされた
- 古い Mac OS X と Xcode を VM に入れる案も検討したが中止した
- Apple が今でもレガシー iOS ターゲットのバイナリに署名してくれるかも不明だった
- 代替案は Boot ROM 脆弱性 を直接狙う方法だった
- 古いツールチェーンや VM なしでも、ホストマシンから USB 経由でデバイスとやり取りするコードだけで試せる
- iPhone Wiki の
Vulnerabilities and Exploitsセクションで limera1n のエクスプロイトコードを確認した
SecureROM と iOS 起動の信頼の連鎖
- Apple 用語でいう SecureROM は iOS 起動プロセスの最初の段階で、次のブート段階を開始する
- SecureROM は 2 つのコンポーネントをロードできる
- 通常起動では NOR のディスクパーティションから
Low Level Bootloader、つまり LLB を起動する - DFU モードで USB 経由でコンピュータに接続されると、
Restore iPhoneの過程でiBoot Single Stage、つまり iBSS ブートローダを受け取れる
- 通常起動では NOR のディスクパーティションから
- SecureROM は LLB または iBSS が Apple に署名された信頼可能なイメージかどうかを確認する
- その後、LLB と iBSS も自分がロードする次の段階を検証し、信頼の連鎖 を形成する
- SecureROM は最初の段階なので前段階からの検証を受けず、製造時に読み取り専用メモリへ焼き込まれる
- 他の段階は iOS アップデートで置き換え可能
- 特定の SecureROM バージョンの脆弱性は、そのバージョンで製造されたデバイスに恒久的に残る
limera1n で DFU デバイス上のコード実行を得る
- limera1n は geohot が 2010 年に公開し、同名の脱獄ツールとしてパッケージ化した SecureROM エクスプロイトである
- DFU モードのデバイスが USB 経由でホストから iBSS を受け取るため待機しているときに limera1n を使える
- A4 SoC に含まれる SecureROM が脆弱なため、iPhone 4 は適切な標的になる
- limera1n の正確な動作原理は公開情報として完全には整理されていない
- geohot はなぜ動くのか分からないと述べていた
- p0sixninja は理論を推測していた
- クラッシュは USB 制御メッセージのファジングで発見され、ヒープオーバーフローにつながるレースコンディションのように見え、シェルコード注入と実行を可能にしているとみられる
DFU モードデバイスでメモリを読む
- pod2g の SecureROM dumper は、limera1n 実装、ペイロード例、USB ベースのメモリ読み取り方法をあわせて示す参考実装になった
- SecureROM dumper は、SecureROM がマップされた
0x0のメモリを USB 受信領域へコピーし、その後ホストが USB 制御メッセージでデータを読む - 理解した流れは次のとおり
- A4 の MMU は SRAM の先頭を
0x84000000にマップする - ホストは
request type 0x21、request ID 1の USB 制御パケットで iBSS イメージを断片ごとに送れる - このデータは
0x84000000から SRAM にコピーされ、SecureROM は次のパケットのコピー先位置を追跡する内部カウンタを保持する - デバイスは
request type 0xA1、request ID 2の制御パケットにも応答し、0x84000000のメモリ内容をホストへ送る
- A4 の MMU は SRAM の先頭を
- この読み取り機能は、デバイス上でコードを実行できるときに特に有用である
- ペイロードが欲しいデータを
0x84000000へコピーする - ホストは
A1:2読み取りリクエストでそのデータを取得できる
- ペイロードが欲しいデータを
- p0sixninja の 2013 年の Hack In the Box Malaysia 発表 スライドでは、pod2g の SecureROM dumper は SHAtter ベースとされているが、実際のユーティリティは limera1n 実装を使っている
- 独自の limera1n 実装で SecureROM ダンプに成功した
0x84000000 を使ったペイロードのデバッグ
- コード実行を得た後は、シェルコードがどこで実行されるのか、スタックがどこにあるのか、シェルコードがどのメモリを上書きするのかを確認する必要があった
- SecureROM dumper の読み取りフローをデバッグ出力用に再利用した
- ペイロードが命令ポインタ (instruction pointer) とスタックポインタ (stack pointer) の値を
0x84000000にコピーする - ホスト側コードが同じ方法でその値を再び読む
- この方法はメモリダンプを通じた簡易
print()の役割を果たす
- ペイロードが命令ポインタ (instruction pointer) とスタックポインタ (stack pointer) の値を
- 自動スクリプトはエクスプロイト実行後に
0x84000000の先頭数ワードをダンプし、出力ウィンドウに表示する - 確認できた値は、シェルコードの実行位置とスタック位置を示していた
- 命令ポインタは
0x8402b048付近だった - スタックポインタは
0x8403bfa0だった - スタックポインタは SecureROM が設定した通常のスタック領域内にあり、命令ポインタは受信イメージ領域内にあった
- 命令ポインタは
Rust ペイロードと Mach-O シェルコード抽出
- アセンブリだけでペイロードを書く代わりに、Rust ペイロード をビルドしてシェルコードへ変換するビルドシステムを構築した
- Rust は 2020 年初頭に
armv7-apple-iosターゲットのサポートを打ち切ったが、rustupにより古いサポート付きツールチェーンへ切り替えられる - 高水準言語でコンパイルすると、生のマシンコードだけでなく、メタデータ、仮想アドレス空間設定情報、シンボルテーブル、リンカ情報を含むバイナリが生成される
- エクスプロイトにはメモリへ注入してジャンプするバイト列だけが必要なので、Mach-O 全体ではなく
__TEXTセグメントの__textセクションだけが必要になる - strongarm は Mach-O 解析ライブラリで、ビルドシステムでは Mach-O を解析して
__TEXT,__textセクションをファイルへ抽出するために使われている - 抽出されたファイルのバイト列が、limera1n によってデバイス上で実行されるシェルコードになる
リンカと静的データの問題
- 通常のバイナリは OS インフラと
startまたは_mainのようなエントリポイントシンボル規約を使うが、このシェルコード用途ではそのようなシンボルは不要である - リンカはデフォルトでは
_mainまたはstartがないとエラーを出す -U _main,-U start,-staticオプションを組み合わせることで、dyld を使わない Mach-O ファイルを作れた- strongarm は当初
LC_DYLD_INFOロードコマンドがないバイナリを処理できず、例外を投げていた- そのバイナリは dyld を使わないため
LC_DYLD_INFOがない - strongarm に パッチ を追加して対処した
- そのバイナリは dyld を使わないため
- Rust コードに静的文字列を追加すると、ペイロードが壊れた
- コンパイルされた静的文字列は
__constに配置される - シェルコード抽出プロセスは
__TEXT,__textだけを残すため、__constのデータはメモリにロードされない - その結果、コードはマップされていないアドレスから文字列を読もうとしてクラッシュする
- コンパイルされた静的文字列は
- 解決策は、静的データを
__TEXT,__text内に含め、安定したロードアドレスを前提にしないよう 命令ポインタ相対アドレッシング を使うことだった - 現在の方法では、アセンブリ内で文字列を定義し、そのアドレスを Rust ペイロードのエントリポイントへ渡している
第1部で完成した実行パイプライン
- 最終的なパイプラインは次の順序で動作する
- Rust ペイロードを修正する
- ボタンを押してペイロードをコンパイルする
- バイナリからシェルコードを抽出する
- ランナーが接続された DFU iPhone 上で limera1n によりペイロードを実行する
- ランナーが通信領域として使う
0x84000000からデータを自動で読み出し、hexdump として表示する
- この時点で、デバイス上で任意コードを実行できる
- 任意コード実行によって理論上は多くのことが可能になるが、デバイスに実際に面白いことをさせる作業は別の段階として残っている
- 次の段階は Part 2: Bypassing the Bootchain へと続く
1件のコメント
Hacker News のコメント
何年も読むだけだったけれど、この一言を残したくて、ついに Hacker News のアカウントを作った。長い間、多くの人にとって謎めいたブラックボックスだったことを、こうして整理してくれてありがとう。
iOS 4 が入った iPod 4G を脱獄していたとき、ターミナルのメッセージが次々と流れていくのを見ながら、ものすごく緊張していたのを鮮明に覚えている。その後、学校の昼休みに友人たちの端末もやってあげながら、うっかり電話を壊して数百ドルの文鎮端末にしてしまうのではないかと心配していた。
何年も経って振り返ると、Apple の壁を突破してユーザーコードを実行するあの「魔法」が、プログラミングにのめり込むきっかけだった。関わったすべての人に心から感謝している。
記事を本当にありがとう。これほど複雑な概念をわかりやすく説明するには、深い理解が必要だ。読んでいるうちに、夜遅くまで脱獄プロジェクトをハックしていた楽しい記憶がよみがえった。
読んでいる間ずっと本当に楽しかった。特に、今でもネイティブコードのリバースエンジニアリングが苦手な身としてはなおさらだった。
これはシステム復旧メカニズムを使って信頼の連鎖を破り、改変された iOS を起動しているので、テザード脱獄に見える。だとすると、アンテザード脱獄はどう動作するのか気になる。セキュアブートの連鎖をそもそも通らず、そのまま残した状態で、実行中のシステムの特権プロセスまたは非特権プロセスをエクスプロイトし、その後に別途権限昇格する方式で合っているのだろうか。永続性はどう確保し、ブートローダーとカーネル自体の署名検査に手を入れずに、カーネルの署名検査をどうパッチするのかも気になる。
本当に素晴らしい記事。今でもコミュニティで活動している姿を見られてうれしい。
これを作ってくれてありがとう。大切な写真がたくさん入っている iPhone 4s があるのだが、うっかり PIN を忘れてしまい、何年も待たなければならない状態になっている。
写真さえなければそのまま初期化したのだが、これで PIN をリセットして写真をコピーできるのか気になっている。
追記: 自分が間違っているかもしれない。[0] には、しばらくの間は Mail の保存領域だけが暗号化され、デフォルトが iOS 7 で変わったとも書かれている。なので iPhone が iOS <= 6 なら、この方法で端末にアクセスして写真をコピーできるかもしれない。[1] のツールが役に立つ可能性がある。
[1] https://code.google.com/archive/p/iphone-dataprotection/
[0] https://darthnull.org/ios-encryption/
本当に良い記事だった。ただ、昔の iOS インターフェイスがスキューモーフィックデザインの栄光をそのまま見せている場面には、胸が悪くなった。John Ive がどれほど嫌いかを改めて感じた。
Jony はソフトウェアを担当するより、カミソリのように鋭いアルミ製パームレストでもデザインし続けているべきだったのかもしれない。
前半のいくつかを本当に楽しく読んだ。こういう視点で追っていくのはすばらしい。自分も、他の人がエクスプロイトのようなものをどう実装しているのか知ろうとしてソースコードを大量に読むので、他にもそうする人がいるとわかってうれしい。
まだ読んではいないが楽しみ。冒頭に挙げられていたTweakは全部使ったことがあり、作ってくれてありがとうと言いたかった。初期の iOS 脱獄は本当に楽しかった。
とても良かった。実行してみようとしたが、残念ながら自分の古い端末はそもそも起動しなかった。
自分も当時 Tweak を作っていて、脱獄を黒魔術のように感じていた。この記事を読んでも、まだある程度はそう感じる。
こうしてまとめてくれて本当にありがとう。こういう内容を学ぶことにとても興味がある。特に dafang-hacks のように安価な Wi-Fi セキュリティカメラを自分のカスタムファームウェアで「解放」したり、Kindle Fire タブレットを root 化する新しいエクスプロイトを作ったりする方法を学びたい。
しかし、その過程を詳しく扱った記事は驚くほど見つけにくい。