
Windows x86 PoC: レガシー32ビットWindows上でのカスタムシェルコードを使ったスタックベースのバッファオーバーフロー
これは、32ビットWindows向けのスタックベースのバッファオーバーフローエクスプロイトに関する、シンプルで自己完結型のチュートリアルです。外部のガイドは不要です。必要なものはすべてここにあります。
vulnerable.c: 安全でない gets() 関数を使用するシンプルなプログラム。messageBox.asm: オーバーフロー後に実行される小さなアセンブリペイロード。exploit.c: オーバーフローがどのようにトリガーされるかの例。このプロジェクトは、安全でない入力読み取りにより攻撃者がリターンアドレスを上書きし、実行をリダイレクトできるという核心的なアイデアを教えます。
gets() にサイズ制限がないvulnerable.c では、プログラムは次のように動作します:
char buffer[32];
gets(buffer);
プログラムは buffer に32バイトを確保し、gets() を呼び出して入力を読み取ります。
問題: gets() はバッファサイズをチェックしません。
改行文字に遭遇するまで文字を読み続けます。
ユーザーが40文字や50文字を入力すると、余分な文字が32バイトのバッファを超えてオーバーフローします。
Cの関数が実行されるとき、スタックには次のものが保存されます:
buffer など)EBP(呼び出し元関数のベースポインタ)次のようにイメージしてください:
低いアドレス(図のスタックの上部)
[ buffer (32 bytes) ]
[ saved EBP (4 bytes) ]
[ return address (4 bytes) ]
高いアドレス(下部)
gets() が buffer を大量の入力でオーバーフローさせると、余分なバイトが保存された EBP、次にリターンアドレスを上書きします。
オーバーフローを注意深く構築してリターンアドレスフィールドに特定のアドレスを配置すると、関数が戻ろうとしたときにCPUがそのアドレスにジャンプします。
buffer[32] を割り当てます。gets(buffer) を呼び出してユーザー入力を1行読み取ります。gets() はサイズチェックを行わないため、50バイトすべてをバッファに書き込みます。buffer を超えてオーバーフローし、保存された EBP とリターンアドレスを上書きします。これがバッファオーバーフローによるコード実行の最も単純な形です。
messageBox.asm は、オーバーフロー後に実行されるように設計された小さなコードです。
以下のことを行います:
LoadLibraryA を文字列 "USER32.DLL" で呼び出し、ライブラリがメモリにあることを確認します。ExitProcess を呼び出してプログラムを安全に終了します。重要なのは、これはオーバーフローによって実行がリダイレクトされた後に実行される実行可能コードであることです。 メッセージボックスが画面に表示されると、次の3つのことを証明します:
実際の攻撃では、このペイロードはデータの窃取、ユーザーの作成、マルウェアのダウンロードなど、あらゆることを行えます。 メッセージボックスは、任意のコード実行が発生したことを示す視覚的で安全なデモンストレーションに過ぎません。
この特定のペイロードは、MessageBoxA (0x751D8830) と ExitProcess (0x7437ADB0) にハードコードされたメモリアドレスを使用しています。
これらのアドレスは特定のシステムに固有です。異なる Windows バージョンやシステムではペイロードを調整する必要があります。

最新のWindowsには、このエクスプロイトを防ぐ複数のセキュリティ機能があります:
この学習演習では、これらすべてを無効にします。
MSVC (Microsoft Visual C++) を特定のフラグとともに使用します:
cl /c /GS- /W3 /Zl vulnerable.c
link /SUBSYSTEM:CONSOLE /DYNAMICBASE:NO /NXCOMPAT:NO vulnerable.obj /OUT:vulnerable.exe
フラグの意味:
/GS- はスタックバッファオーバーラン保護を無効にします。/DYNAMICBASE:NO はアドレス空間配置のランダム化 (ASLR) を無効にします。/NXCOMPAT:NO は DEP を無効にし、スタック上のコードの実行を許可します。実行可能ファイルが既にある場合は、editbin を使用して保護を無効にできます:
editbin /NXCOMPAT:NO /DYNAMICBASE:NO vulnerable.exe
vulnerable.exe を起動します。このREADMEでは以下のことを説明しています:
gets() とは何か、なぜ安全でないか(サイズ制限がない)。これでバッファオーバーフローエクスプロイトの全体的な流れを理解しました。 コードファイルを読み、この説明と比較して理解を深めてください。
この例は学習目的のみです。 所有していないシステムやテストの明示的な許可がないシステムに対してこの手法を使用しないでください。 コンピュータシステムへの不正アクセスは違法です。