1

バッファの悪用の例を作成しようとしています ( http://insecure.org/stf/smashstack.htmlの example3.c)) Debian Lenny 2.6 バージョンで動作します。gcc のバージョンと OS のバージョンが Aleph One で使用されているものとは異なることはわかっています。-fno-stack-protector および sysctl -w kernel.randomize_va_space=0 引数を使用してスタック保護メカニズムを無効にしました。私のセットアップと Aleph One の違いを説明するために、次の 2 つのパラメーターを導入しました。offset1 -> buffer1 変数から戻りアドレスまでのオフセットと、offset2 -> ステートメントをスキップするためにジャンプするバイト数。アセンブリ コードを解析してこれらのパラメーターを把握しようとしましたが、うまくいきませんでした。そこで、基本的に (1-60) のオフセット 1 とオフセット 2 の値を同時に指定してバッファー オーバーフロー プログラムを実行するシェル スクリプトを作成しました。しかし、驚いたことに、私はまだこのプログラムを破ることができません。誰かが私を同じように導くことができれば、それは素晴らしいことです。検討のためにコードとアセンブリ出力を添付しました。本当に長い投稿で申し訳ありません:)

ありがとう。


// Modified example3.c from Aleph One paper - Smashing the stack
void function(int a, int b, int c, int offset1, int offset2) {
   char buffer1[5];
   char buffer2[10];
   int *ret;

   ret = (int *)buffer1 + offset1;// how far is return address from buffer ?
   (*ret) += offset2; // modify the value of return address
}

int main(int argc, char* argv[]) {
  int x;
  x = 0;
  int offset1 = atoi(argv[1]);
  int offset2 = atoi(argv[2]);
  function(1,2,3, offset1, offset2);
  x = 1; // Goal is to skip this statement using buffer overflow
  printf("X : %d\n",x);
  return 0;
}

-----------------
// Execute the buffer overflow program with varying offsets
#!/bin/bash
for ((i=1; i<=60; i++))
do
   for ((j=1; j<=60; j++))
   do
    echo "`./test $i $j`"
   done
done

-- Assembler output
(gdb) disassemble main
Dump of assembler code for function main:
0x080483c2 <main+0>:    lea    0x4(%esp),%ecx
0x080483c6 <main+4>:    and    $0xfffffff0,%esp
0x080483c9 <main+7>:    pushl  -0x4(%ecx)
0x080483cc <main+10>:   push   %ebp
0x080483cd <main+11>:   mov    %esp,%ebp
0x080483cf <main+13>:   push   %ecx
0x080483d0 <main+14>:   sub    $0x24,%esp
0x080483d3 <main+17>:   movl   $0x0,-0x8(%ebp)
0x080483da <main+24>:   movl   $0x3,0x8(%esp)
0x080483e2 <main+32>:   movl   $0x2,0x4(%esp)
0x080483ea <main+40>:   movl   $0x1,(%esp)
0x080483f1 <main+47>:   call   0x80483a4 <function>
0x080483f6 <main+52>:   movl   $0x1,-0x8(%ebp)
0x080483fd <main+59>:   mov    -0x8(%ebp),%eax
0x08048400 <main+62>:   mov    %eax,0x4(%esp)
0x08048404 <main+66>:   movl   $0x80484e0,(%esp)
0x0804840b <main+73>:   call   0x80482d8 <printf@plt>
0x08048410 <main+78>:   mov    $0x0,%eax
0x08048415 <main+83>:   add    $0x24,%esp
0x08048418 <main+86>:   pop    %ecx
0x08048419 <main+87>:   pop    %ebp
0x0804841a <main+88>:   lea    -0x4(%ecx),%esp
0x0804841d <main+91>:   ret    
End of assembler dump.

(gdb) disassemble function
Dump of assembler code for function function:
0x080483a4 <function+0>:    push   %ebp
0x080483a5 <function+1>:    mov    %esp,%ebp
0x080483a7 <function+3>:    sub    $0x20,%esp
0x080483aa <function+6>:    lea    -0x9(%ebp),%eax
0x080483ad <function+9>:    add    $0x30,%eax
0x080483b0 <function+12>:   mov    %eax,-0x4(%ebp)
0x080483b3 <function+15>:   mov    -0x4(%ebp),%eax
0x080483b6 <function+18>:   mov    (%eax),%eax
0x080483b8 <function+20>:   lea    0x7(%eax),%edx
0x080483bb <function+23>:   mov    -0x4(%ebp),%eax
0x080483be <function+26>:   mov    %edx,(%eax)
0x080483c0 <function+28>:   leave  
0x080483c1 <function+29>:   ret    
End of assembler dump.
4

1 に答える 1

1

あなたが提供した逆アセンブリは、あなたのCコードとは対照的に、とfunctionのハードコードされた値を使用しているようです。offset1offset2

のアドレスはretbyte/char offsets: を使用して計算する必要があります。そうしないと、ポインター計算ret = (int *)(buffer1 + offset1)にヒットします(特にこの場合、戻りアドレスから適切に整列されたオフセットにない場合)。buffer1

offset10x9 + 0x4は( で使用されるオフセットlea+ 4 バイト)と等しくなければなりませんpush %ebp。ただし、これはコンパイルするたびに予期せず変更される可能性があります。スタック レイアウトが異なる場合や、コンパイラが追加のスタック アラインメントを作成する場合などがあります。

offset27(スキップしようとしている命令の長さ)と等しくなければなりません。


ここで少し幸運なことに注意してください - は呼び出し規則functionを使用します。cdeclつまり、呼び出し元は、関数から戻った後にスタックから引数を削除する責任があります。通常は次のようになります。

push arg3
push arg2
push arg1
call func
add esp, 0Ch ; remove as many bytes as were used by the pushed arguments

コンパイラは、この修正を の後の修正と組み合わせることを選択しましたprintfが、関数呼び出しの後にこれを行うことも決定できます。この場合、add esp, <number>リターン アドレスとスキップしたい命令の間に命令が存在します。

于 2012-09-23T09:11:49.520 に答える