Ret2lib
基本情報
Ret2Libcの本質は、脆弱なプログラムの実行フローを、スタック上の攻撃者提供のシェルコードを実行する代わりに、共有ライブラリ内の関数(たとえば system、execve、strcpy)にリダイレクトすることです。攻撃者は、ペイロードを作成し、スタック上の戻りアドレスを望ましいライブラリ関数を指すように変更し、同時に呼び出し規約に従って必要な引数が正しく設定されるように配置します。
手順の例(簡略化)
呼び出す関数(たとえば system)のアドレスと呼び出すコマンド(たとえば /bin/sh)を取得する
最初の引数をコマンド文字列を指すようにし、関数への実行フローを渡すためのROPチェーンを生成する
アドレスの検索
現在のマシンで使用されている
libc
がどこにメモリにロードされるかを見つけるには:
ASLRがlibcのアドレスを変更しているかどうかを確認したい場合は、次のようにします:
使用されているlibcを知っていると、
system
関数へのオフセットを見つけることも可能です:
使用されているlibcを知っている場合、文字列
/bin/sh
関数へのオフセットを見つけることも可能です:
gdb-peda / GEFを使用する
使用しているlibcを知っている場合、PedaまたはGEFを使用して、system関数、exit関数、および文字列**/bin/sh
**のアドレスを取得することも可能です:
/proc/<PID>/mapsを使用する
プロセスが子プロセスを作成している場合(ネットワークサーバーなど)、そのファイルを読み取ろうとしてみてください(おそらくroot権限が必要になるかもしれません)。
ここで、プロセス内でlibcがロードされている場所と、プロセスの各子プロセスにロードされる場所を正確に見つけることができます。
この場合、0xb75dc000にロードされています(これがlibcのベースアドレスになります)
未知のlibc
バイナリがロードしているlibcがわからない可能性があります(アクセス権限がないサーバーにあるかもしれません)。その場合、脆弱性を悪用していくつかのアドレスを漏洩させ、どのlibcライブラリが使用されているかを見つけることができます:
pageLeaking libc address with ROPまた、これに対するpwntoolsのテンプレートを以下で見つけることができます:
pageLeaking libc - template2つのオフセットでlibcを知る
https://libc.blukat.me/をチェックし、libc内の関数のいくつかのアドレスを使用して、使用されているバージョンを特定します。
32ビットでのASLR回避
これらのブルートフォース攻撃は32ビットシステムにのみ有用です。
攻撃がローカルの場合、libcのベースアドレスをブルートフォースしてみることができます(32ビットシステムに有用):
リモートサーバーを攻撃する場合、
libc
関数usleep
のアドレスを10(例)として試行することができます。サーバーが10秒余分に応答するようになったら、この関数のアドレスを見つけました。
ワンガジェット
libc
内の特定のアドレスにジャンプしてシェルを実行します:
x86 Ret2libコード例
この例では、ASLRブルートフォースがコードに統合されており、脆弱性のあるバイナリがリモートサーバーに配置されています:
x64 Ret2lib コード例
以下の例を確認してください:
pageROP - Return Oriented ProgramingARM64 Ret2lib 例
ARM64の場合、ret 命令は x30 レジスタが指す場所にジャンプし、スタックレジスタが指す場所にはジャンプしません。そのため、少し複雑です。
また、ARM64では命令がそのままの動作をします(命令の途中でジャンプして新しい命令に変換することはできません)。
以下の例を確認してください:
pageRet2lib + Printf leak - arm64Ret-into-printf (またはputs)
これにより、printf
/puts
を呼び出すことで、特定のデータを引数として渡すことで、プロセスから情報を漏洩させることができます。たとえば、puts
のGOT内のアドレスを puts
の実行に置くことで、メモリ内の puts
のアドレスを漏洩させることができます。
Ret2printf
これは、ret2lib
を悪用して printf
フォーマット文字列の脆弱性に変換することを意味します。ret2lib
を使用して、その値を使用して printf
を呼び出し、それを悪用することが可能です(無駄に聞こえるかもしれませんが、可能です):
その他の例と参照
Ret2lib、libc内の関数のアドレスを漏洩させ、ワンガジェットを使用する
64ビット、ASLR有効、PIEなし、最初のステップは、canaryのバイト0x00までオーバーフローを埋め、その後putsを呼び出して漏洩させる。canaryを使用して、putsのアドレスをGOTから漏洩させ、
system('/bin/sh')
を呼び出すためのROPガジェットを作成します。64ビット、ASLR有効、canaryなし、メイン関数内のスタックオーバーフローからの子関数。putsを呼び出して、GOTからputsのアドレスを漏洩させ、その後ワンガジェットを呼び出します。
64ビット、PIEなし、canaryなし、relroなし、nx。write関数を使用して、write(libc)のアドレスを漏洩させ、ワンガジェットを呼び出します。
スタックからcanaryを漏洩させるためにフォーマット文字列を使用し、システムに呼び出し、
/bin/sh
のアドレスを持つGOTにアドレスを渡します。32ビット、relroなし、canaryなし、nx、pie。スタックからlibcとヒープのアドレスを漏洩するために悪いインデックスを悪用します。バッファオーバーフローを悪用して、
system('/bin/sh')
を呼び出すret2libを実行します(チェックをバイパスするためにヒープアドレスが必要です)。
Last updated