
超高速™マルチスレッドROP Gadget finder。ropper / ropgadget の代替(現在はx86のみ)
ropr は、超高速のマルチスレッド ROP ガジェット検出器です。
ROP (Return Oriented Programming) ガジェットは、通常 ret 命令で終わる数個のアセンブリ命令の小さな断片であり、各バイナリやライブラリ内に実行可能コードとして既に存在します。これらのガジェットは、バイナリエクスプロイトや脆弱な実行ファイルの乗っ取りに使用される可能性があります。
多くの ROP ガジェットのアドレスがバッファに書き込まれると、ROP チェーンが形成されます。攻撃者がスタックポインタをこの ROP チェーンに移動できれば、制御を完全に攻撃者に移すことができます。
ほとんどの実行ファイルには、チューリング完全な ROP チェーンを書くのに十分なガジェットが含まれています。含まれていない場合は、アドレスが分かれば libc のような同じアドレス空間内の動的ライブラリをいつでも使用できます。
ROP ガジェットを使用する利点は、新しい実行可能コードをどこにも書く必要がないことです。攻撃者はプログラムに既に存在するコードのみを使用して目的を達成できます。
通常、ROP ガジェットを使用するための最初の要件は、ROP チェーンを書き込む場所があることです。これは任意の読み取り可能なバッファで構いません。使用したい各ガジェットのアドレスをこのバッファに書き込むだけです。バッファが小さすぎると、長い ROP チェーンを書き込むのに十分なスペースがない可能性があるため、攻撃者は利用可能なスペースに収まるように効率的な ROP チェーンを作成するよう注意する必要があります。
次の要件は、スタックを制御できることです。これは、スタックポインタの真下に ROP チェーンを書き込むことを可能にするスタックオーバーフロー、または「スタックピボット」(通常、スタックポインタを ROP チェーンの残りの部分に移動する単一のガジェット)という形を取ることができます。
スタックポインタが ROP チェーンの先頭にあると、次の ret 命令がガジェットを順次実行するようにトリガーします。各ガジェットは、自身のスタックフレーム上で次をリターンアドレスとして使用します。
また、ROP チェーンに関数ポインタを追加することも可能です。その際、関数の引数は ROP チェーンの次の要素の後に指定する必要があります。これは通常、「ポップガジェット」と組み合わされ、関数引数の後にスムーズに次のガジェットに移行するために引数をスタックからポップします。
簡単インストール:
cargo install ropr
アプリケーションは ~/.cargo/bin にインストールされます。
ソースから:
git clone https://github.com/Ben-Lichtman/ropr
cd ropr
cargo build --release
結果のバイナリは target/release/ropr に配置されます。
または:
git clone https://github.com/Ben-Lichtman/ropr
cd ropr
cargo install --path .
アプリケーションは ~/.cargo/bin にインストールされます。
USAGE:
ropr [OPTIONS] <BINARY>
ARGS:
<BINARY> 検査するファイルのパス
OPTIONS:
-b, --base-pivot ベースポインタを変更するガジェットをフィルタリングします
-c, --colour <COLOUR> 出力をカラーまたはプレーンテキストに強制します(`true` または `false`)
-h, --help ヘルプ情報を表示します
-j, --nojop "JOP ガジェット" を削除します。これらは、単純な `ret` の代わりに制御可能な分岐、コールなどを持つ場合があります。
-m, --max-instr <MAX_INSTR> ガジェット内の最大命令数 [デフォルト: 6]
-n, --noisy プレフィックス、条件分岐、近接分岐などの低品質なガジェットも含めます(かなり多くのガジェットが見つかります)
-p, --stack-pivot スタックポインタを変更するガジェットをフィルタリングします
-r, --norop 通常の "ROP ガジェット" を削除します
-R, --regex <REGEX> 返されたガジェットに対して正規表現検索を実行し、簡単にフィルタリングします
--range <RANGE> アドレス範囲(16進数)を検索します 例:`0x1234-0x4567`
--raw <RAW> 入力ファイルをコードのブロブとして扱います(`true` または `false`)
-s, --nosys システムコールやその他の割り込みを削除します
-V, --version バージョン情報を表示します
例えば、別のレジスタから rax に値を代入する方法を探している場合、正規表現 ^mov eax, ...; でフィルタリングすることができます:
❯ ropr /usr/lib/libc.so.6 -R "^mov eax, ...;" > /dev/null
==> 0.118秒で197個のガジェットが見つかりました
次に、最高品質の結果を得るためにコマンドラインにフィルタを追加します:
❯ ropr /usr/lib/libc.so.6 -m 2 -j -s -R "^mov eax, ...;"
0x000353e7: mov eax, eax; ret;
0x000788c8: mov eax, ecx; ret;
0x00052252: mov eax, edi; ret;
0x0003ae43: mov eax, edx; ret;
0x000353e6: mov eax, r8d; ret;
0x000788c7: mov eax, r9d; ret;
==> 0.046秒で6個のガジェットが見つかりました
これで、アドレス 0x00052252 に良い mov ガジェットの候補があります。