1 ポイント 投稿者 GN⁺ 2023-10-03 | 1件のコメント | WhatsAppで共有
  • 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 4iPhone 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 ブートローダを受け取れる
  • 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 0x21request ID 1 の USB 制御パケットで iBSS イメージを断片ごとに送れる
    • このデータは 0x84000000 から SRAM にコピーされ、SecureROM は次のパケットのコピー先位置を追跡する内部カウンタを保持する
    • デバイスは request type 0xA1request ID 2 の制御パケットにも応答し、0x84000000 のメモリ内容をホストへ送る
  • この読み取り機能は、デバイス上でコードを実行できるときに特に有用である
    • ペイロードが欲しいデータを 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() の役割を果たす
  • 自動スクリプトはエクスプロイト実行後に 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 に パッチ を追加して対処した
  • Rust コードに静的文字列を追加すると、ペイロードが壊れた
    • コンパイルされた静的文字列は __const に配置される
    • シェルコード抽出プロセスは __TEXT,__text だけを残すため、__const のデータはメモリにロードされない
    • その結果、コードはマップされていないアドレスから文字列を読もうとしてクラッシュする
  • 解決策は、静的データを __TEXT,__text 内に含め、安定したロードアドレスを前提にしないよう 命令ポインタ相対アドレッシング を使うことだった
  • 現在の方法では、アセンブリ内で文字列を定義し、そのアドレスを Rust ペイロードのエントリポイントへ渡している

第1部で完成した実行パイプライン

  • 最終的なパイプラインは次の順序で動作する
    • Rust ペイロードを修正する
    • ボタンを押してペイロードをコンパイルする
    • バイナリからシェルコードを抽出する
    • ランナーが接続された DFU iPhone 上で limera1n によりペイロードを実行する
    • ランナーが通信領域として使う 0x84000000 からデータを自動で読み出し、hexdump として表示する
  • この時点で、デバイス上で任意コードを実行できる
  • 任意コード実行によって理論上は多くのことが可能になるが、デバイスに実際に面白いことをさせる作業は別の段階として残っている
  • 次の段階は Part 2: Bypassing the Bootchain へと続く

1件のコメント

 
GN⁺ 2023-10-03
Hacker News のコメント
  • 何年も読むだけだったけれど、この一言を残したくて、ついに Hacker News のアカウントを作った。長い間、多くの人にとって謎めいたブラックボックスだったことを、こうして整理してくれてありがとう。
    iOS 4 が入った iPod 4G を脱獄していたとき、ターミナルのメッセージが次々と流れていくのを見ながら、ものすごく緊張していたのを鮮明に覚えている。その後、学校の昼休みに友人たちの端末もやってあげながら、うっかり電話を壊して数百ドルの文鎮端末にしてしまうのではないかと心配していた。
    何年も経って振り返ると、Apple の壁を突破してユーザーコードを実行するあの「魔法」が、プログラミングにのめり込むきっかけだった。関わったすべての人に心から感謝している。

    • 技術業界で働いていると、目標を立てても、理解できないことや成し遂げられないことで嫌になる日が多い。それでも、こういう文章をたまに読むと、オープンソースや技術コミュニティ全体を諦めてはいけないという気持ちになる。
    • iPhone は好きだけれど、昔いろいろな Android 端末に CyanogenMod を入れていたのが懐かしい。本当にかっこよく感じた。
    • 似たような経験をした。最終的には自分で脱獄 Tweakを作り始め、それが本格的にプログラミングに入っていくきっかけになった。
  • 記事を本当にありがとう。これほど複雑な概念をわかりやすく説明するには、深い理解が必要だ。読んでいるうちに、夜遅くまで脱獄プロジェクトをハックしていた楽しい記憶がよみがえった。

  • 読んでいる間ずっと本当に楽しかった。特に、今でもネイティブコードのリバースエンジニアリングが苦手な身としてはなおさらだった。
    これはシステム復旧メカニズムを使って信頼の連鎖を破り、改変された iOS を起動しているので、テザード脱獄に見える。だとすると、アンテザード脱獄はどう動作するのか気になる。セキュアブートの連鎖をそもそも通らず、そのまま残した状態で、実行中のシステムの特権プロセスまたは非特権プロセスをエクスプロイトし、その後に別途権限昇格する方式で合っているのだろうか。永続性はどう確保し、ブートローダーとカーネル自体の署名検査に手を入れずに、カーネルの署名検査をどうパッチするのかも気になる。

    • たいていは、起動中または起動直後にユーザーランドからカーネルを再度エクスプロイトするよう構成することが多い。覚えている手法としては、新しい launch daemon の追加、開発者証明書でのアプリ署名、動的リンカーの特殊な挙動を悪用して署名検査を回避するバイナリの配置などがあった。
  • 本当に素晴らしい記事。今でもコミュニティで活動している姿を見られてうれしい。

  • これを作ってくれてありがとう。大切な写真がたくさん入っている iPhone 4s があるのだが、うっかり PIN を忘れてしまい、何年も待たなければならない状態になっている。
    写真さえなければそのまま初期化したのだが、これで PIN をリセットして写真をコピーできるのか気になっている。

    • おそらく難しいと思う。[0] によると、パスコードはファイルシステム暗号化キーを保護するために使われるので、パスコードなしではファイルを復号できない。写真が暗号化されて保存されているかは知らないが、そう考えるのが妥当だと思う。
      追記: 自分が間違っているかもしれない。[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 はソフトウェアを担当するより、カミソリのように鋭いアルミ製パームレストでもデザインし続けているべきだったのかもしれない。
    • iPhone は iPhone 4 と iOS 4 で頂点に達したと思う。その後も段階的な改善はあったが、新しい iPhone が本当に大きなアップグレードだと感じた最後の瞬間はあの時だった。アンテナゲートを除けば、ハードウェアとソフトウェアのデザインがどちらもただうまく噛み合っていた。
  • 前半のいくつかを本当に楽しく読んだ。こういう視点で追っていくのはすばらしい。自分も、他の人がエクスプロイトのようなものをどう実装しているのか知ろうとしてソースコードを大量に読むので、他にもそうする人がいるとわかってうれしい。

  • まだ読んではいないが楽しみ。冒頭に挙げられていたTweakは全部使ったことがあり、作ってくれてありがとうと言いたかった。初期の iOS 脱獄は本当に楽しかった。

  • とても良かった。実行してみようとしたが、残念ながら自分の古い端末はそもそも起動しなかった。
    自分も当時 Tweak を作っていて、脱獄を黒魔術のように感じていた。この記事を読んでも、まだある程度はそう感じる。

  • こうしてまとめてくれて本当にありがとう。こういう内容を学ぶことにとても興味がある。特に dafang-hacks のように安価な Wi-Fi セキュリティカメラを自分のカスタムファームウェアで「解放」したり、Kindle Fire タブレットを root 化する新しいエクスプロイトを作ったりする方法を学びたい。
    しかし、その過程を詳しく扱った記事は驚くほど見つけにくい。