web-dev-qa-db-ja.com

この単純なバッファオーバーフローはどのように機能しますか?

私はこの簡単なコードを持っています

vuln.c

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

int main(int argc, char** argv)
{
    char buffer[500];
    strcpy(buffer, argv[1]);
    printf("%s", buffer);
    return 0;
}

バッファオーバーフローを実行しようとしています

  • 悪意のあるコードでバッファを埋める
  • 悪意のあるコードにリダイレクトするように返信アドレスを変更する

理想的には、500バッファーを上書きすると、次にベースポインターが上書きされ、その後に戻りアドレスが続くと思います。

これが私がバッファをオーバーフローさせようとした方法です

gcc vuln.c
./a.out $(python -c 'print "\x41" * 501')

501 "A"をバッファに入れているので、理論的にはオーバーフローするはずです。しかし、これは起こっていません。セグメンテーション違反は発生しませんが、代わりに「AAAA ..」の出力が表示され、プログラムは正常に終了します。 (私はAsの数を数えませんでした。)。

そこで、GDBを起動して、doがセグメンテーション違反を取得するまで、Asの数を試してみました。そして、私は520の "A"を置くとセグメンテーション違反が発生することに気づきました。どうやって?

520 A、GDBのinfo registers与えてくれます enter image description here

そして、521 Aで同じGDBコマンドを実行すると、 enter image description here

ご覧のとおり、画像1ではベースポイントが\ x41(Aの場合は16進数)で埋められており、画像2ではBPが\ x41sで埋められており、IPも同様に埋められています。

分かりません。だから私の質問は-なぜ520なのか?そして、なぜそれは501でオーバーフローしなかったのですか?

3
Izy-

これは、128ビット(16バイト)で動作する SIMD命令 との互換性のためにコンパイラがx86(_64)で行う16バイトへのアライメントによるものです。そのため、バッファと保存されたレジスタの間に「パディング」がいくつかあります。この場合は12バイトです。

技術的には、500 A文字をプログラムに渡した場合、文字列がnullで終了しているため、バッファはすでにオーバーフローしています。ただし、そのゼロバイトは、最初のパディングバイトを上書きするだけです。これらのパディングバイトと保存されたripの間には、保存されたrbp(8バイト)もあります。したがって、レイアウトは基本的に次のようになります( canaries が使用されている場合--fstack-protector-次に、カナリア値がパディングと保存されたレジスタの間に配置されます):

buffer [500 bytes] | padding [12 bytes] | saved rbp [8 bytes] | saved rip [8 bytes]

したがって、520 A文字では、保存されたrbpの最初のバイトがゼロバイトで上書きされる前に、最初にパディングと保存されたripを上書きします。

4
ecdsa