2012-03-30 24 views
2

バッファオーバーフローのさまざまなスタイルをレビューしていて、なぜそれが発生するのか覚えていない問題が発生しました。Linuxバッファオーバーフロー環境変数

#include <stdio.h> 

void func(char *buff){ 
    char buffer[5]; 
    strcpy(buffer, buff); 
    printf("%s\n", buffer); 
} 

int main(int argc, char *argv[]){ 
    func(argv[1]); 
    printf("I'm done!\n"); 
    return 0; 
} 

プログラムの中核となる概念は非常に簡単です、私はちょうどfunc()のリターンアドレスを上書きするために、バッファをオーバーフロー:次のようにコードは、私が上のバッファオーバーフローを実行しようとしていますプログラムです。プログラムの<_fini>である0x0804850cのようなアドレスを私が与えるとき、それはすべて素晴らしいです。そのアドレスでオーバーフローを実装すると、最終的にプログラムは終了します。I'm done!を印刷せずに "正常に"終了します。私が今実行している問題は、リターンアドレスを0xbfffd89にある環境変数のようなものにリダイレクトしようとするときです。

その特定の環境変数にあるシェルコードは、helloの後にプログラムを終了するだけです。しかし、それは発生しません、プログラムは単に欠陥をsegし、それはそれです。シェルコードはシェルコードをテストするために書いた前のプログラムで動作することが確認されています。誰もが、なぜこれが動作していないか考えている。 Thx

+1

gdbの下で実行すると、segfaultをトリガーするものが表示されます。私の推測:環境変数は、読み取り可能であるが実行可能ではないメモリ領域にあります。@ EugeneMayevski'EldoSCorp:私は、ここでは "シェルコード"はシェルといくつかの外部コマンドを実行するマシンコードの専門用語であると仮定しています。この場合、実際のシェルは実行されていないようです。 – Celada

+0

@Celada環境変数が読み取り専用であるかどうかをGDBを使って調べる方法に関する提案。また、シェルコードについても正しいです。 – Blackninja543

+0

@ EugeneMayevski'EldoSCorp一般に定義されているシェルコードはバイナリのバイトコードです。この場合、私はx86 ASMに欲しいものを書いてシェルコードを生成しました。関数のリターンアドレスをリダイレクトすると、新しい命令セットを含むメモリ領域に命令が送られます。 – Blackninja543

答えて

2

環境変数は、書き込み許可があるが実行権限はなく、&のメモリ領域にあります。次のように私は簡単にこれを再現:

#include <stdio.h> 
#include <stdlib.h> 

int 
main(int argc, char **argv) 
{ 
void (*function)(void); 

     function = (void (*)(void))getenv("PATH"); 
     function(); 
     return 0; 
} 

gdbの下で実行すると、私はこれだ:私はその後、/proc/PID/maps場合は、アドレス0x00007fffffffeb51を見上げ

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

をして、このような行が見つかりました:

7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0       [stack] 

x(実行)ビットが通常見つかる-があります。

+0

OKだから、環境変数の外で私のシェルコードを実行するための他の可能性がある環境変数のパーミッションを変更することはできません。 – Blackninja543

+1

脆弱なプログラムの考えられるシナリオ:環境変数がヒープにコピーされます。おそらく、環境変数はディレクトリを指定し、ファイル名と連結して 'malloc()'メモリに完全なパス名を形成します。これで、バッファオーバーフローがヒープ上のこのアドレスにジャンプします。実行可能になります。しかし、あなたはこのヒープアドレスが何であるかを推測しなければなりません。それに幸運にも:-) – Celada

0

実行の間に変数のアドレスを確認できますか?システムがASLRのようなものを使用している場合は、実行ごとに異なることがあります。しかし、argv [1]のアドレスはいくつかのレジスタを介して与えられるかもしれません。したがって、このレジスタを介して間接呼び出しを行う命令のアドレスを返す場合は、プログラムでobjdump -dを使用します。このアドレスが実行可能なページにあると仮定して、どんなアドレスにでもコードを実行します。また、ABIではレジスタを使用してパラメータを渡します。しかし、別の問題があるかもしれません...

もっと詳しく説明してください(おそらく、プログラムの逆アセンブルを含めると)、もっと具体的に答えられるかもしれません。

+0

チャンスが得られたら、逆アセンブルしたコードを追加します。アドレス空間のランダム化に関しては、テスト環境では無効にしています。 Celadaが示したように、私自身の環境を調べたところ、私の環境変数は実行不可能ではありませんでした。実行可能にするためにコードシェルコードを挿入する方法について考えてください。私がこの時点で考えることができる唯一の方法は、環境変数を使うことです。 – Blackninja543

2

現代のLinuxディストリビューションは、この種の攻撃に対して強化されています。 NXビットは、たとえば、x86-64のスタックページ用に設定されます。マッピングアドレスはランダム化され、プロセス外から推測する能力が失われます。あなたはいくつかのより多くの作業を行う必要があるとしている近代的なシステムの悪用書きたい場合は、

http://en.wikipedia.org/wiki/Executable_space_protection http://en.wikipedia.org/wiki/Address_space_layout_randomization

基本的には次を参照してください。

+1

正しい。この特定のケースではっきりしないことは、実際には環境変数がスタックと同じメモリマップ領域にあることです。私は今までそれを知らなかった! – Celada

+0

@Celada:実際には、 'argc'、' argv'、 'envp'、' auxv'の各ポインタとそれぞれのポインタはスタック上の各プロセスに渡されます。 – ninjalj

+0

@ninjalj「argv」と「envp」と「auxv」はすべて「ユーザーエリア」と呼ばれるメモリ領域にまとめられていましたが、スタックと同じ領域であることはわかりませんでした。しかし、私はこれを数年前に知ったときにSolarisに戻っていました。物事は変わったかもしれません。解明してくれてありがとう! – Celada