web-dev-qa-db-ja.com

バッファオーバーフローとは何ですか。

バッファオーバーフローについて聞いたことがあります。バッファオーバーフローの原因を知りたいのですが。

誰かが私に小さなバッファオーバーフローの例を見せてもらえますか?新規(そしてそれらは何のために使用されますか?)

30
H4cKL0rD

バッファオーバーフローとは、基本的には、メモリの細工されたセクション(またはバッファ)が意図した範囲外に書き込まれた場合です。攻撃者がプログラムの外部からこれを発生させることができた場合、多くの最新のオペレーティングシステムが最悪のケースから保護しますが、任意のメモリロケーションを操作できる可能性があるため、セキュリティ上の問題を引き起こす可能性があります。

意図した範囲外での読み取りと書き込みの両方は一般に悪い考えと見なされますが、「バッファオーバーフロー」という用語は通常、範囲外のwriteのために予約されています。これにより、攻撃者がコードの実行方法を簡単に変更する可能性があります。 Wikipediaには、 バッファオーバーフロー と、エクスプロイトに使用できるさまざまな方法についての優れた記事があります。

自分でプログラムを作成する方法については、次の簡単な問題になります。

char a[4];
strcpy(a,"a string longer than 4 characters"); // write past end of buffer (buffer overflow)
printf("%s\n",a[6]); // read past end of buffer (also not a good idea)

それがコンパイルされるかどうか、また実行時に何が起こるかは、おそらくオペレーティングシステムとコンパイラに依存します。

26
David Dean

バッファオーバーフローの古典的な例:

// noone will ever have the time to type more than 64 characters...
char buf[64];
gets(buf); // let user put his name

ほとんどの場合、バッファオーバーフローだけでは意図的に発生しません。これは、いわゆる「オフバイワン」エラーが原因で最も頻繁に発生します。あなたが配列サイズを1つ誤って計算したことを意味します-多分あなたは終端のヌル文字を説明するのを忘れたか、あるいは他の何かのためです。

しかし、それはいくつかの邪悪なものに使用することもできます。実際、ユーザーはこの穴を長く知っていて、たとえば70文字を挿入しました。最後の文字には、いくつかのスタックスロットを上書きする特別なバイトが含まれています。ユーザーが本当にトリッキーな場合、スタックのリターンアドレススロットにヒットします。 、それを上書きして、挿入されたばかりのバッファにジャンプします。ユーザーが入力したのは名前ではなく、以前にコンパイルしてダンプしたシェルコードだからです。その後、それが実行されます。いくつか問題があります。たとえば、そのバイナリコードに「\ n」が含まれないように準備する必要があります(getsはそこで読み取りを停止するため)。危険な文字列関数を混乱させる他の方法では、文字列関数がそこへのコピーを停止するため、2進ゼロは問題があります。ゼロバイトを明示的に書き込むことなく、同じ値の2倍のxorを使用してゼロも生成しました。

それが古典的なやり方です。しかし、そのようなことが起こったことを知らせることができるいくつかのセキュリティブロックと、スタックを実行不可能にする他の要素があります。しかし、私は私が今説明したよりもずっと良いトリックがあると思います。一部のアセンブラーの人は、おそらくあなたにそれについて長い話をすることができるでしょう:)

それを避ける方法

常にそうでない場合は、最大長の引数を取る関数も使用します100%バッファが本当に十分大きいことを確認してください。 「ああ、数字が5文字を超えない」などのゲームをプレイしないでください。いつか失敗します。ロケットがそれほど速くなることはないので、科学者がその数は大きさを超えないだろうと言った1つのロケットを思い出してください。しかし、いつかはが実際に速くなり、整数オーバーフローが発生し、ロケットがクラッシュしました( Ariane 5 のバグに関するものです)歴史上最も高価なコンピュータのバグ)。

たとえば、getsの代わりにfgetsを使用します。そしてsprintfの代わりに、適切で利用可能な場合はsnprintfを使用します(またはistreamなどのC++スタイルのものだけ)

最近のLinux OSでは、余分な実験を行わないと、バッファオーバーフローを利用できません。どうして ? [〜#〜] aslr [〜#〜](アドレススタックレイヤーのランダム化)とスタックプロテクターによってブロックされるため、この最新のGNU Cコンパイラ。メモリは[〜#〜] aslr [〜#〜]によってランダムメモリに分類され、-stackによってブロックされます。 protectorプログラムをオーバーフローさせようとした場合。

はじめに、ASLRを0にする必要があります。デフォルト値は2です。

root@bt:~# cat /proc/sys/kernel/randomize_va_space
2
root@bt:~# echo 0 > /proc/sys/kernel/randomize_va_space
root@bt:~# cat /proc/sys/kernel/randomize_va_space
0
root@bt:~#

これは、インターネットから取得したOLD STYLEバッファオーバーフローのチュートリアルではありません。または、aleph oneチュートリアルがシステムで動作しなくなった。

バッファオーバーフローシナリオにプログラムの脆弱性を作成します

---------------------bof.c--------------------------
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv)
{
        char buffer[400];
        strcpy(buffer, argv[1]);

        return 0;
}
---------------------EOF-----------------------------

入力するバイト数をチェックせずに機能するため、スタックプロテクターなしでstrcpy関数を見ると危険です。 Cプログラムのスタックプロテクターを削除するには、追加オプション-fno-stack-protector dan -mpreferred-stack-boundary = 2でコンパイルします。

root@bt:~# gcc -g -o bof -fno-stack-protector -mpreferred-stack-boundary=2 bof.c
root@bt:~# chown root:root bof
root@bt:~# chmod 4755 bof

sUIDルートアクセスシナリオを備えたバッファオーバーフローCプログラムを作成しました。プログラムのセグメンテーション違反を作成するためにバッファに入れる必要があるバイト数を検索できるようになりました

root@bt:~# ./bof `Perl -e 'print "A" x 400'`
root@bt:~# ./bof `Perl -e 'print "A" x 403'`
root@bt:~# ./bof `Perl -e 'print "A" x 404'`
Segmentation fault
root@bt:~#

プログラムのセグメンテーションフォールト(クラッシュ)を作成するために404バイトが必要であることがわかります。上書きする必要のあるバイト数[〜#〜] eip [〜#〜]? EIP命令は後に実行されます。したがって、ハッカーは上書きします[〜#〜] eip [〜#〜]プログラムのバイナリSUIDに必要な命令を悪用します。プログラムがSUIDルートにある場合、命令はルートアクセスで実行されます。

root@bt:~# gdb -q bof
(gdb) list
1       #include <stdio.h>
2       #include <string.h>
3
4       int main(int argc, char** argv)
5       {
6               char buffer[400];
7               strcpy(buffer, argv[1]);
8
9               return 0;
10      }
(gdb) run `Perl -e 'print "A" x 404'`
Starting program: /root/bof `Perl -e 'print "A" x 404'`

Program received signal SIGSEGV, Segmentation fault.
0xb7e86606 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
(gdb) run `Perl -e 'print "A" x 405'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/bof `Perl -e 'print "A" x 405'`

Program received signal SIGSEGV, Segmentation fault.
0xb7e800a9 in ?? () from /lib/tls/i686/cmov/libc.so.6
(gdb)

プログラムGOTセグメンテーション障害の戻りコード。さらにバイトを入力して、EIPレジスタを見てみましょう。

(gdb) run `Perl -e 'print "A" x 406'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/bof `Perl -e 'print "A" x 406'`

Program received signal SIGSEGV, Segmentation fault.
0xb7004141 in ?? ()
(gdb)

(gdb) run `Perl -e 'print "A" x 407'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/bof `Perl -e 'print "A" x 407'`

Program received signal SIGSEGV, Segmentation fault.
0x00414141 in ?? ()
(gdb)

もう少し

(gdb) run `Perl -e 'print "A" x 408'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/bof `Perl -e 'print "A" x 408'`

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb)

(gdb) i r
eax            0x0      0
ecx            0xbffff0b7       -1073745737
edx            0x199    409
ebx            0xb7fc9ff4       -1208180748
esp            0xbffff250       0xbffff250
ebp            0x41414141       0x41414141
esi            0x8048400        134513664
edi            0x8048310        134513424
eip            0x41414141       0x41414141 <-- overwriten !!
eflags         0x210246 [ PF ZF IF RF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb)

今、あなたはあなたの次のステップを行うことができます...

12
Yuda Prawira

バッファオーバーフローは、バッファの終わりを超えて書き込んでいるだけです。

int main(int argc, const char* argv[])
{
    char buf[10];
    memset(buf, 0, 11);
    return 0;
}
10
Tim Lesher

すでに述べたことに加えて、バッファオーバーフローが発生したときにプログラムが「クラッシュ」する場合としない場合があることに注意してください。それ すべき クラッシュし、それが発生することを期待する必要があります。ただし、バッファオーバーフローが、アプリケーションによって割り当てられた別のアドレスに「オーバーフロー」すると、アプリケーションが長時間正常に動作しているように見えることがあります。

Microsoft Visual Studioの新しいエディションを使用している場合-sprintf_s insted of sprintf、ectなどのstdlibの新しい安全な対応物を使用することをお勧めします...

5
NTDLS

これは、受け取った回答に関する一般的なコメントです。例えば:

_int main(int argc, char *argv[])
{
    char buffer[10];
    strcpy(buffer, argv[1]);
}
_

そして:

_int main(int argc, const char* argv[])
{
    char buf[10];
    memset(buf, 0, 11);
    return 0;
}
_

最新のLinuxプラットフォームでは、これは期待どおりまたは意図したとおりに機能しない可能性があります。 FORTIFY_SOURCEセキュリティ機能のため、機能しない可能性があります。

FORTIFY_SOURCEは、memcpystrcpyなどのハイリスク関数の「安全な」バリアントを使用します。コンパイラは、宛先バッファサイズを推定できる場合、より安全なバリアントを使用します。コピーが宛先バッファサイズを超える場合、プログラムはabort()を呼び出します。

テストでFORTIFY_SOURCEを無効にするには、_-U_FORTIFY_SOURCE_または_-D_FORTIFY_SOURCE=0_を使用してプログラムをコンパイルする必要があります。

1
jww

「クラシック」バッファオーバーフローの例は次のとおりです。

int main(int argc, char *argv[])
{
    char buffer[10];
    strcpy(buffer, argv[1]);
}

これにより、バッファーオーバーフローパラメーターを操作して、心のコンテンツに合わせることができます。 " Hacking-The Art of Exploitation "(リンクはアマゾンに移動します)という本は、バッファオーバーフローをいかに回避するかについての詳細を説明しています(明らかに知的運動として)。

1
Larry Osterman

プログラムのバッファオーバーフローをチェックする場合は、 Valgrind などのツールを使用してプログラムを実行できます。彼らはあなたのためにいくつかのメモリ管理のバグを見つけるでしょう。

1
John Smith

これで再現できます:

void buffer_overflow() 
{
    char * foo = "foo";
    char buffer[10];

    for(int it = 0; it < 1000; it++) {
        buffer[it] = '*';
    }

    char accessViolation = foo[0];
}
1
alex2k8

バッファオーバーフローは、割り当てられたメモリが保持できる範囲を超える文字の挿入です。

0
Jcbn

正しい答えが与えられた場合:このトピックをさらに詳しく理解するには、Podcastのセキュリティを今すぐ聞くことをお勧めします。 エピソード39 (しばらくの間)に、彼らはこれについて深く議論しました。これは、本全体を消化することなく、より深く理解するための迅速な方法です。

(リンクでは、複数のサイズのバージョンのアーカイブと、視覚的指向の場合は筆記録が見つかります)。オーディオはこのトピックの完璧なメディアではありませんが、Steveはこれに対処するために不思議に取り組んでいます。

0
Olaf Kock

このコンテキストでは、バッファは特定の目的のために確保されたメモリの一部であり、バッファオーバーフローは、バッファへの書き込み操作が最後を超えていくと発生します(異なる目的のメモリへの書き込み)。これは常にバグです。

バッファオーバーフロー攻撃とは、このバグを利用して、プログラムの作成者が意図していないことを実行する攻撃です。

0
dmckee