5

これは、bufferoverflow の脆弱性を悪用するためのシェルコードです。を設定し、setuid(0)を使用してシェルを生成しますexecve()。以下は私がそれを解釈した方法です:

xor    %ebx,%ebx       ; Xoring to make ebx value 0
lea    0x17(%ebx),%eax ; adds 23 to 0 and loads effective addr to eax. for setuid()
int    $0x80           ; interrupt
push   %ebx            ; push ebx
push   $0x68732f6e     ; push address // why this address only????
push   $0x69622f2f     ; push address // same question
mov    %esp,%ebx
push   %eax
push   %ebx
mov    %esp,%ecx
cltd                   ; mov execve sys call into al
mov    $0xb,%al
int    $0x80           ; interrupt

誰かが全体の手順を明確に説明できますか?

4

1 に答える 1

11

intソフトウェア割り込みをトリガーするオペコードです。ソフトウェア割り込みには (0 から 255 までの) 番号が付けられ、カーネルによって処理されます。Linux システムでは、割り込み 128 (0x80) がシステム コールの従来のエントリ ポイントです。カーネルは、レジスタ内のシステム コール引数を想定しています。特に、%eax レジスタは、どのシステム コールについて話しているかを識別します。

  1. %ebx を 0 に設定
  2. %ebx+23 を計算し、結果を %eax に保存します (オペコードはlea「ロード有効アドレス」ですが、メモリ アクセスは関係しません。これは単なる足し算の不正な方法です)。
  3. システムコール。%eax には 23 が含まれています。これは、システム コールが であることを意味しますsetuid。このシステム コールは、%ebx にある 1 つの引数 (ターゲット UID) を使用します。この引数には、その時点で都合よく 0 が含まれています (最初の命令で設定されています)。注: システム コールの戻り値を含む %eax を除いて、レジスタは変更されません。通常は 0 (呼び出しが成功した場合) です。
  4. %ebx をスタック (まだ 0) にプッシュします。
  5. $0x68732f6e をスタックにプッシュします。
  6. $0x69622f2f をスタックにプッシュします。スタックは「下に」成長し、x86 プロセッサはリトル エンディアン エンコーディングを使用するため、命令 4 から 6 の効果は、%esp (スタック ポインタ) が値 2f 2f 62 69 6e 2f の 12 バイトのシーケンスを指すようになることです。 73 68 00 00 00 00 (16 進数)。これは、「//bin/sh」文字列のエンコーディングです (終端ゼロと、その後に 3 つの余分なゼロがあります)。
  7. %esp を %ebx に移動します。%ebx には、上で構築された「//bin/sh」文字列へのポインタが含まれています。
  8. スタックに %eax をプッシュします (その時点で %eax は 0 です。これは から返されたステータスですsetuid)。
  9. %ebx をスタックにプッシュします (「//bin/sh」へのポインター)。命令 8 と 9 は、スタック上に 2 つのポインターの配列を構築します。最初のポインターは "//bin/sh" へのポインターで、2 番目のポインターは NULL ポインターです。その配列は、execveシステム コールが 2 番目の引数として使用するものです。
  10. %esp を %ecx に移動します。%ecx は、命令 8 と 9 で構築された配列を指します。
  11. %eax を %edx:%eax に符号拡張します。cltdは、Intel のドキュメントで と呼ばれている AT&T 構文ですcdq。その時点で %eax はゼロであるため、これにより %edx もゼロに設定されます。
  12. %al (%eax の最下位バイト) を 11 に設定します。%eax はゼロだったので、%eax の全体の値は 11 になりました。
  13. システムコール。%eax (11) の値は、システム コールを として識別しますexecveexecve%ebx (実行するファイルの名前を指定する文字列へのポインター)、%ecx (文字列へのポインターの配列へのポインター。これらはプログラムの引数であり、最初の引数はプログラム名のコピーであり、呼び出されたプログラム自体によって使用される) および %edx (環境変数である文字列へのポインターの配列へのポインター; Linux は、空の環境の場合、その値が NULL であることを許容します) にそれぞれ対応します。

したがって、コードは最初に を呼び出しsetuid(0)、次に2 つのポインターの配列を指すexecve("//bin/sh", x, 0)whereを呼び出します。最初の 1 つは "//bin/sh" へのポインターであり、もう 1 つは NULL です。x

このコードは、ゼロを回避したいため、非常に複雑です。バイナリ オペコードにアセンブルされると、命令のシーケンスはゼロ以外のバイトのみを使用します。たとえば、12 番目の命令がmovl $0xb,%eax(%eax の全体を 11 に設定する) 場合、そのオペコードのバイナリ表現には値 0 の 3 バイトが含まれます。ゼロがないため、そのシーケンスはゼロの内容として使用できます。で終わる C 文字列。もちろん、これはバッファ オーバーフローを介してバグのあるプログラムを攻撃するためのものです。

于 2010-11-09T14:23:39.393 に答える