12

私はCの行をスキップしx=1;たいbufferoverflow. ただし、 から までの 7 バイトをカウントしているにもかかわらず、アドレス から4002f4次のアドレスにスキップできない理由がわかりません。4002fb<main+35><main+42>

また、Debian および AMD 環境で randomniZation および execstack 環境のオプションを構成しましたが、まだx=1;. この手順の何が問題なのですか?

dba を使用して、スタックとメモリ アドレスをデバッグしました。

0x00000000004002ef <main+30>:    callq  0x4002a4 **<function>**  
**0x00000000004002f4** <main+35>:    movl   $0x1,-0x4(%rbp)  
**0x00000000004002fb** <main+42>:    mov    -0x4(%rbp),%esi  
0x00000000004002fe <main+45>:    mov    $0x4629c4,%edi  

void function(int a, int b, int c)  
{
  char buffer[5];
  int *ret;

  ret = buffer + 12;
  (*ret) += 8; 
}

int main()
{
   int x = 0; 
   function(1, 2, 3);
   x = 1;
   printf("x = %i \n", x);  
   return 0;  
}
4

4 に答える 4

4

infunction()をスキップするために within のリターン アドレスを変更するには、2 つの情報が必要です。x = 1main()

1. スタック フレーム内のリターン アドレスの位置。

この値を決定するために gdb を使用しました。( ) にブレークポイントを設定し、ブレークポイントまでコードを実行しfunction()( ) 、現在のスタック フレームのメモリ内の場所を取得し (または)、( ) のメモリ内の場所を取得します。取得した値を使用して、リターン アドレスの場所を特定できます。break functionrunp $rbpinfo regbufferp &buffer

(GCC-gフラグを使用してコンパイルし、デバッグ シンボルを含め、64 ビット環境で実行)

(gdb) break function
...
(gdb) run
...
(gdb) p $rbp
$1 = (void *) 0x7fffffffe270
(gdb) p &buffer
$2 = (char (*)[5]) 0x7fffffffe260
(gdb) quit

(フレーム ポインタ アドレス + ワードのサイズ) - バッファ アドレス = ローカル バッファ変数からリターン アドレスまでのバイト数
(0x7fffffffe270+ 8) -0x7fffffffe260= 24

コール スタックの仕組みを理解するのが難しい場合は、コール スタック関数プロローグのウィキペディアの記事を読むと役立つ場合があります。これは、C で「バッファ オーバーフロー」の例を作成することの難しさを示しています。24 からのオフセットbufferは、特定のパディング スタイルとコンパイル オプションを想定しています。現在、 GCC は、スタック カナリアを挿入しないように指示しない限り、喜んで挿入します。

2. スキップする戻りアドレスに追加するバイト数x = 1

0x00000000004002f4あなたの場合、保存された命令ポインターは( )を指し<main+35>、関数が戻った後の最初の命令です。0x00000000004002fb割り当てをスキップするには、保存された命令ポインターが( )を指すようにする必要があります<main+42>

これが 7 バイトであるという計算は正しいです ( 0x4002fb- 0x4002fb= 7 )。

gdb を使用してアプリケーション ( disas main) を逆アセンブルし、私の場合の計算も検証しました。この値は、分解を調べて手動で解決するのが最適です。


Ubuntu 10.10 64 ビット環境を使用して、次のコードをテストしたことに注意してください。

#include <stdio.h>

void function(int a, int b, int c)  
{
    char buffer[5];
    int *ret;

    ret = (int *)(buffer + 24);
    (*ret) += 7; 
}

int main()
{
     int x = 0; 
     function(1, 2, 3);
     x = 1;
     printf("x = %i \n", x);  
     return 0;  
}

出力

x = 0


function()これは、実際のバッファ オーバーフローではなく、単にリターン アドレスを変更しているだけです。実際のバッファ オーバーフローでは、オーバーフローbuffer[5]して戻りアドレスを上書きします。ただし、最新の実装のほとんどは、これを防ぐためにスタック カナリアなどの手法を使用しています。

于 2011-04-06T18:28:48.507 に答える
4

あなたは、楽しみと利益のためにスタックを破壊するという記事を読んでいるに違いありません。私は同じ記事を読んでいて、その指示をスキップしなかったのと同じ問題を発見しました。IDA で数時間のデバッグ セッションを行った後、コードを次のように変更し、x=0 と b=5 を出力しています。

#include <stdio.h>

void function(int a, int b) {
     int c=0;
     int* pointer;

     pointer =&c+2;
     (*pointer)+=8;
}

void main() {
  int x =0;
  function(1,2);
  x = 3;
  int b =5;
  printf("x=%d\n, b=%d\n",x,b);
  getch();
}
于 2011-03-25T22:52:49.523 に答える
2

ここで行っていることは、従来の bufferoverflow 攻撃とはあまり関係がないようです。bufferoverflow 攻撃の全体的な考え方は、「関数」の戻りアドレスを変更することです。プログラムを逆アセンブルすると、ret命令 (x86 を想定) がどこからアドレスを取得するかがわかります。これは、 を指すように変更する必要があるものですmain+42

ここで bufferoverflow を明示的に引き起こしたいと思いますが、通常は「関数」の入力を操作して誘発する必要があります。

スタックポインタを間違った方向に動かしていると宣言するだけbuffer[5]で (生成されたアセンブリを見てこれを確認してください)、戻りアドレスはスタック内のどこか深いところにあります (呼び出し命令によってそこに置かれました)。x86 では、スタックは下向き、つまり下位アドレスに向かって成長します。

int*を宣言し、リターンアドレスがプッシュされた指定されたアドレスに到達するまで上に移動し、その値をポイントするように変更してmain+42function を許可することで、これにアプローチしますret

于 2011-03-12T07:17:15.247 に答える
1

このようにすることはできません。これは、従来の bufferoverflow コード サンプルです。キーボードから 5 文字、次に 6 文字を入力するとどうなるか見てみましょう。それ以上の場合 (16 文字で十分です)、ベース ポインターを上書きしてから、関数の戻りアドレスを上書きすると、セグメンテーション フォールトが発生します。あなたがしたいことは、どの4文字が戻りアドレスを上書きするかを把握することです. プログラムにコードを実行させます。Linuxスタック、メモリ構造に関するGoogle。

 void ff(){
     int a=0; char b[5];
     scanf("%s",b);
     printf("b:%x a:%x\n" ,b ,&a);
     printf("b:'%s' a:%d\n" ,b ,a);
 }

 int main() {
     ff();
     return 0;
 }
于 2011-03-12T15:53:41.657 に答える