2016-09-28 15 views
3

が、私はこの機能を使用してstrcpyので古典的なオーバーフローを使用してスタックバッファオーバーフローを再作成しようとして機能していませんスタック保護gcc -o vuln vuln.c -fno-stack-protector -g -z execstackと同様に、ASLRをsudo echo 0 > /proc/sys/kernel/randomize_va_spaceで削除します。無効スタック保護は

私が保存されたEIPを上書きするために私のNOP-シェルコード・アドレスを取得することができますが、それはRETにクラッシュします。私はHANDLE SIGSEGV ignoreなどでgdbのSIGSEGVを無効にすることを考え出しましたが、GDBの外で実行していましたが、どこにリターンアドレスを設定してもセグメンテーションフォールトは引き続き発生します。

gccの古いバージョンを取得する以外にも、現在gccバージョン6.1.1を使用しています。

答えて

4

LinuxはW^X原則に従います:彼らはコードセクションの一部である場合を除き、それは非実行可能ファイルとしてメモリページをマーク。これは、コンパイルされたアプリケーションの範囲を超え、正当な理由があります。 OSは、システム上で実行されるすべてのプログラムからのバッファオーバーフロー攻撃を防御するこの責任を負っています。特にあなたのようなバッファオーバーフロー攻撃を積極的に試みているプログラム。

あなたはbufを経由して、スタック上のコードを書いて、新たに挿入されたコードに実行をジャンプする関数の戻りアドレスを上書きしようとしています。関数が復帰すると、プログラムカウンタはオーバーライドされたリターンアドレスに設定され、スタックメモリを指すようになります。 SIGSEGVは、プログラムカウンタがスタックメモリページ上の無効な実行許可のために次の命令を実行しようとするとスローされます。

は、スタックから実行するには、OSのスタック保護を無効にする必要があります。

幸いにも、Linuxはユーザーの裁量で使用するような場合のためにexecstack提供します。

は、より一般的な情報についてthisのUnix &のLinuxスタック為替ポストを参照してください。あなたがGDBでSIGSEGVを取得している場合は


デバッグが

データを注入し、それはおそらく試みをオーバーランあなたのバッファに多少の誤差があることを意味します。デバッグに

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

char injection_code[] = ""; // buffer overrun data here 


void foo() { 
    char buf[100]; 

    // memcpy used to copy the full injection string, including any nested 0s 
    memcpy(buf, injection_code, 108); // +8 here to handle 64-bit system RAs 
} 

int main (int argc, char** argv) { 
    foo(); 
    printf("Done!\n"); 
    return 0; 
} 

利用GDB:mainの終わりにクリーンアップをいじり避けるために、私はあなたのバッファオーバーランを行うには、メインから呼び出す機能を作ることをお勧め。私はfooの最後にブレークポイントを置き、info registersで期待していたものとレジスタの行を確認することをお勧めします。あなたはおそらく、info registers rip(64ビット)またはinfo registers eip(32ビット)でチェックできる命令ポインタに最も興味があります。

GDBでprintまたはx/xを使用すると、スタックの外観を調べることができます。たとえば、$rbp+8をチェックすると、戻りアドレス(RA)がスタック上にあるかどうかを確認できます。

GDBは、無効な場所にRAポイントであればret命令にSIGSEGVます:

Program received signal SIGSEGV, Segmentation fault. 
0x00000000004005bc in foo() at bufferoverflow.c:27 

あなたはそれが故障の時に命令ポインタアドレスをチェックしてret指示に障害が発生かどうかを確認することができます(上の例では、それは0x00000000004005bcとなります)(GDBのdisassemble function_nameを使います)。

リターンアドレスがスタックに戻って指している場合、それはあなたのリターンアドレスが正しく整列されていないか、またはあなたの注入された命令が不正な形式されていることを意味不当命令、のためSIGILLを投げることがあります。

Program received signal SIGILL, Illegal instruction. 
0x00007fffffffdc13 in ??() 

繰り返しになりますが、GDBを使用してスタックを調べて理由を確認することができます。

GDBは、バッファオーバーフローの構造を正しく取得するのに便利です。 しかし、それが意図したとおりに動作すると、特に、デバッグフラグ(-g)なしでコンパイルすると、GDBの外部で実行されたときにメモリアドレスがシフトする可能性があります。あなたは「生きている」環境でそれをしたい場所に戻すために、リターンアドレスで少しでも遊ばなければなりません。


アンは別に

一般的には、直接注入コードを実行するバッファオーバーフロー攻撃は、今日のスタック保護メカニズムと一般実現できないです。通常、任意のコードを実行するために追加の脆弱性が存在する必要があります。

+2

もちろん、この点は、OPが想定している攻撃の種類を正確にフォイルすることです。この機能が広く普及しているため、そのような攻撃の可能性は従来のものよりはるかに低くなります。 –

+0

私はgcc '-z execstack'と' sudo execstack -s vuln'を使ってexecstackを使い、 'readelf -l vuln'でGNUスタックがRWE(read、write execute)に設定されていることを確認しました。 。私が間違っていることについて考えてみませんか?バッファオーバーフローに必要な量は108バイト以上で、むしろ116バイトです。 – nrabbit

+0

@nrabbit私は今それを行う時間がありませんが、私のマシンで実験し、あなたに戻ってきます。 – sdsmith

1

私はついにこの問題を理解しました。 GCCは命令と変数を16バイトの境界に合わせていました。そのように、それはプロローグにアセンブリの指示、すなわちlea ecx,[esp+0x4]などを追加していました。そして、関数のエピローグでスタックポインタを少し動かすことでスタックのレイアウトを混乱させました。私は-mpreferred-stack-boundary=2で再コンパイルし、GDBの問題を修正しました。今はあなたが言及したような返信アドレスで遊ぶだけです。ありがとう!!

関連する問題