サイトアイコン 大人のためのゲーム講座

Pro CFWで使われている6.60 kxploitの仕組み

wololo.netでjigsaw氏がPSPのexploitが内部でどのような動作をしているのかについての解説記事を投稿していました。6.60 kxploitはsome1氏が発見し、Pro CFWで使われているカーネルexploitです。その6.60 kxploitに焦点を当てて解説されていますので翻訳してみました。

6.60 kxploit(注: kernel exploitのことをいつからかkxploitと呼ぶようになっています)はmbuf[1]をPSPに移植したifhandle.pfxの中にあります。mbufはネットワークパケットやソケットバッファのメモリ管理をする基本的なユニットです。元々はBSDのものですがBSDライセンスに従って広く商用利用されています。ifhandleはFreeBSD 4のものに若干の修正を加えて移植されたものです。一部のifhandleのルーチンは100%オリジナルのmbufコードそのものです。

kxploitを調べる前に、まずkxploitでどんなことができるのかを確認しておきましょう。その答えは単刀直入に言うとカーネル特権で自分で用意したルーチンを実行することが可能になるということです。カーネル特権があれば非署名自作コードの実行やバージョンチェックスキップなどを実行するためにカーネルへパッチをすることができます。

複雑な話ではありませんが、どうすればカーネル特権を得ることができるのかは簡単な話ではありません。カーネルルーチン[3]を実行するためのsyscallを思い出してみてください。カーネルルーチンをどうにかして自分で用意したルーチンへリダイレクトできれば、その用意したルーチンは即座にカーネルレベルのルーチンになります。カーネルルーチンのリダイレクトはどのようにすれば可能なのかについて考えてみましょう。ケースバイケースですが、殆どの場合カーネルルーチンが配置されるカーネル領域のモディファイが必要になります。

それはまるでジレンマです。カーネル特権を得るためにはカーネル特権が要求されるカーネル領域をモディファイしなければならないということだからです。これこそ
kxploitが必要な理由です。殆どの場合、kxploitはカーネル領域に値を書き込むことができてしまうというカーネルのバグのことです。

通常kxploitにはある種の制限が存在します。例えば6.39 kxploitの場合どこにでも0xFFFFFFFFという値が書き込めますが、6.20 kxploitの場合はその値が0×0です。こういったケースの場合アドレスのコントロールはできますが、そこに書き込む値はコントロールできません。とはいってもそれ以上のことは必要ないので実はそれで十分なのです。カーネル特権をチェックしたりルーチンのオフセットをロードするところを1文字変えるだけでカーネルルーチンのリダイレクトは可能になります。肝心なチェックポイントだけを変えてやることで自分で用意したルーチンのアドレスをロードしてコールできるようカーネルに命令を下せることができるようになります。

通常はカーネル領域にゼロの値を書き込みます。これはMIPSのゼロというのがNOP、つまりNo-operation(何もしない)を意味し、他のMIPS命令をマスクするのに都合が良いからです。

つまり、結論としてはこうです: カーネル領域の任意のアドレスにゼロという値を書き込む方法を探す必要がある。[4]

では、6.60 kxploitを詳しく見て行きましょう。

以下はsceNetMCopydataの1行です:

memcpyの第1と第2引数に注目します。それぞれ行き先とデータのソースです。
規則[5]ではルーチンの第1引数である$a0を見てみます。

sceNetMCopydataの第4引数($a3)はmemcpyの行き先にあたります。引数に関してはチェックされません。そのためカーネル領域のアドレスを引数にセットすることが可能であれば…
しかし、sceNetMCopydataはユーザー領域へエクスポートできません。つまり直接コールすることができないということです。ところが運良くsceNetMCopydataはユーザー領域から簡単にアクセスできる他のsyscallからコールされるのです。ここではsceNetMPulldownがターゲットです。

ここでsceNetMCopydataをコールする方法を見つけるためsceNetMPulldownの主要部分を解析してみましょう。sceNetMPulldownでは2ヶ所でsceNetMPulldownをコールしています。ここでは0×00003018でのコールに注目します。その理由は0x00002E9Cでのコールがユーザーでは扱えないsceNetMallocInternalによって割り当てられるmbufへのデータコピーだからです。

既に述べた通り、ifhandleはmubfが実装されたものがベースになっていますので、参考としてオリジナルのFreeBSDのコードを入手することができます。ifhandleのライン間マッピングのことがこれで分かります。m_pulldownについては http://fxr.watson.org/fxr/source/kern/uipc_mbuf2.c?v=FREEBSD4 で分かります。

MIPSアセンブラについては詳しくなっておいてください。簡単に理解できるようコメントを多用してあります。

見ての通り、コードはほとんどがmbufそのものです。
0×00003018のsceNetMCopydataに行くまでにいくつものトラップを回避しています。例えばm_flagsやm_len、m_nextがセットしてあるところなどです。一方で2つのmbufが互いに行き来できるようなリンクが必要です。自分で考えて欲しいのと、PRO CFWを見れば分かることなのでこのkxploitを有効にするにはどうすればいいのかについてはここでお話しするつもりはありません。
これはkxploitがどんなものなのかをお見せして、どうすればkxploitを見つけることができるのかをお見せするためのものです。今までに公開されたほとんどのkxploitはメモリーアドレスのチェックを無くすという同じような内容です。

理論的にはユーザー領域からカーネル領域のポインター(メモリーアドレス)はどれも有効になるはずです。しかし経験上PSPが発表されてから10年近く経ちますがまだこういったkxploitが存在しています。もちろんこういったkxploitを見つかることはめったにありませんし、場合によってはsyscallの制限[6]のため必ず有効なものとも限りません。

一方で他の種類のkxploitも存在します。カーネルメモリーのモディファイなしに直接コールすることでユーザーコードを有効にできるスタックオーバーフロー(プログラム中で関数呼び出しが多すぎる時に発生する脆弱性で、バッファオーバーフローの一種)もその一つです。次回はそのことについて触れてみましょう。

ところで、kxploitにはWindowsやLinuxのような主要なOSではありがちなヒープオーバーフロー(OSやアプリケーションが動的に確保するメモリ領域(ヒープ)からデータがあふれてしまう脆弱性で、バッファオーバーフローの一種)というものもあります。しかしPSPでは見つかったことも公開されたこともありません。いつかヒープオーバーフローの美しさもお見せできる機会があるといいですね。

モバイルバージョンを終了