2

この質問で提供されたコードを試しましたが、うまくいきません。

私の頭を包み込むためにオーバーフローを考案する方法は?

アップデート:

    .file   "hw.cpp"
    .section .rdata,"dr"
LC0:
    .ascii "Oh shit really bad~!\15\12\0"
    .text
    .align 2
.globl __Z3badv
    .def    __Z3badv;   .scl    2;  .type   32; .endef
__Z3badv:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    movl    $LC0, (%esp)
    call    _printf
    leave
    ret
    .section .rdata,"dr"
LC1:
    .ascii "WOW\0"
    .text
    .align 2
.globl __Z3foov
    .def    __Z3foov;   .scl    2;  .type   32; .endef
__Z3foov:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    movl    LC1, %eax
    movl    %eax, -4(%ebp)
    movl    $__Z3badv, 4(%ebp)
    leave
    ret
    .def    ___main;    .scl    2;  .type   32; .endef
    .align 2
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    andl    $-16, %esp
    movl    $0, %eax
    addl    $15, %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    call    __alloca
    call    ___main
    call    __Z3foov
    movl    $0, %eax
    leave
    ret
    .def    _printf;    .scl    2;  .type   32; .endef
4

7 に答える 7

3

投稿したCの例を使用できます。C でも C++ と同じように機能します。

私が考えることができる最小の読みやすい答え:

int main() {
    return ""[1]; // Undefined behaviour (reading past '\0' in string)
}
于 2010-03-28T14:37:50.467 に答える
3

他の質問の例をアセンブリにコンパイルすると、特定のコンパイラとプロセッサに対してスタックがどのように配置されているかを感じることができます。例の+8は、ご使用の環境では正しい数値ではない場合があります。決定する必要があるのは、スタックに格納されている配列に対して、戻りアドレスがスタックに格納されている場所です。

ちなみに、この例は私にとってはうまくいきました。Cygwin、gcc バージョン 4.3.4 を使用して Win XP でコンパイルしました。「機能した」と言うときbad()、その関数がコードによって呼び出されなかったとしても、関数でコードを実行したことを意味します。

$ gcc -Wall -Wextra buffer-overflow.c && ./a.exe
Oh shit really bad~!
Segmentation fault (core dumped)

このコードは実際にはバッファ オーバーフローの例ではなく、バッファ オーバーフローが悪用された場合に起こりうる悪いことの例です。

私は x86 アセンブリが苦手ですが、このエクスプロイトがどのように機能するかについての私の解釈を次に示します。

$ gcc -S buffer-overflow.c && cat buffer-overflow.s
_foo:
        pushl   %ebp           ;2
        movl    %esp, %ebp     ;3
        subl    $16, %esp      ;4
        movl    LC1, %eax      ;5
        movl    %eax, -4(%ebp) ;6
        leal    -4(%ebp), %eax ;7
        leal    8(%eax), %edx  ;8
        movl    $_bad, %eax    ;9
        movl    %eax, (%edx)   ;10
        leave
        ret

_main:
    ...
        call    _foo            ;1
    ...

(1) を呼び出すと、命令mainはmain 内のアドレスをスタックにプッシュし、呼び出しが完了すると戻ります。スタックへのプッシュには、ESP のデクリメントとそこへの値の格納が含まれます。foocallfoo

に入るとfoo、古いベース ポインター値もスタックにプッシュされます (2)。これは返却時に復元されfooます。スタック ポインターは、このスタック フレームのベース ポインターとして保存されます (3)。スタック ポインターは 16 (4) 減分され、ローカル変数用のスペースがこのスタック フレームに作成されます。

リテラル "WOW\0" のアドレスがovermeスタック (5,6) のローカル変数にコピーされます。これは奇妙に思えますが、スタックに割り当てられたスペースに 4 文字をコピーするべきではありませんか? とにかく、WOW (またはそれへのポインター) がコピーされる場所は、現在のベース ポインターの 4 バイト下にあります。したがって、スタックにはこの値、古いベース ポインター、リターン アドレスの順に格納されます。

のアドレスがovermeEAX に入れられ (7)、そのアドレスの 8 バイト先に整数ポインターが作成されます (8)。関数のアドレスがbadEAX に入れられ (9)、そのアドレスが整数ポインターが指すメモリーに格納されます (10)。

スタックは次のようになります。

     // 4 bytes on each row
ESP: (unused)
   : (unused)
   : (unused)
   : &"WOW\0"
   : old EBP from main
   : return PC, overwritten with &bad

最適化を使用してコンパイルすると、興味深いものはすべて「役に立たないコード」として最適化されます (これはそうです)。

$ gcc -S -O2 buffer-overflow.c && cat buffer-overflow.s
_foo:
        pushl   %ebp
        movl    %esp, %ebp
        popl    %ebp
        ret
于 2010-03-28T15:02:16.897 に答える
2

このようなもの?

int main()
{
    char arr[1];
    arr[1000000] = 'a';
}
于 2010-03-28T14:56:20.173 に答える
2

単純なバッファ オーバーフローは次のようになります。

#include <stdio.h>
#include <string.h>

int main() {
   char a[4] = {0};
   char b[32] = {0};

   printf("before: b == \"%s\"\n", b);

   strcpy(a, "Putting too many characters in array a");

   printf("after:  b == \"%s\"\n", b);
}

可能な出力:

前: b == ""
after: b == "配列 a の文字"

プログラムの実際の動作はundefinedであるため、バッファ オーバーフローによって、異なる出力が発生したり、クラッシュしたり、目に見える効果がまったくない場合もあります。

于 2010-03-28T15:01:40.070 に答える
0
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

void process_msg(const char *pSrc)
{
    char cBuff[5];
    strcpy(cBuff, pSrc);
}

void main()
{
    char szInput[] = "hello world!";
    process_msg(szInput);
}

このプログラムを Visual Studio 2008 でデバッグ モードで実行すると、次のメッセージが表示されます。

Run-Time Check Failure #2 - Stack around the variable 'cBuff' was corrupted.

この例では、'cBuff' char 配列がスタックに割り当てられており、サイズは 5 バイトです。指定されたポインタのデータ (pSrc) をその char arrat (cBuff) にコピーすると、スタック フレームのデータが上書きされ、悪用される可能性があります。

この手法はハッカーによって使用されます。ハッカーは、スタック上の「リターン」アドレスへのポインターを上書きし、それをメモリ内の目的の場所に変更する、特別に細工された文字の配列を送信します。

したがって、たとえば、彼らはその「リターン」アドレスを、ポートを開くか接続を確立するシステム/プログラムコードに向けることができ、その後、アプリケーションの権限で PC にアクセスできます (多くの場合、これはルート/管理者を意味します)。 .

詳しくはhttp://en.wikipedia.org/wiki/Buffer_overflowをご覧ください。

于 2010-03-28T15:16:57.257 に答える
0

Eric が指摘した優れた記事に加えて、次の読み物もチェックしてください。

次の記事では、ヒープ オーバーフローについて詳しく説明しています。

これは私の回答hereからコピーされました。

于 2010-03-28T17:57:48.220 に答える
0

バッファ オーバーフローという用語は、正確には、バッファの末尾を超えてアクセスすることを意味します (バッファ アンダーフローの概念も含める必要があります)。しかし、バッファー オーバーフロー、ポインター、配列、割り当て、および割り当て解除に関係する "メモリの安全性の問題" のクラス全体があり、そのすべてがクラッシュを引き起こしたり、コード内の機会を悪用したりする可能性があります。別のメモリ安全性の問題 (およびそれを検出する方法) のこの C の例を参照してください。

于 2011-03-10T15:16:20.043 に答える