exploit(続2)
id:MaD:20070209の続きです。
自作のバグありプログラムにexploitを仕掛けるということをしていたわけですが、アセンブリを見れば全て解決でした。
crackmeのmain関数の最初と最後で行われている処理のアセンブリを以下に載せます。
ここでは次のような処理が行われていました。
- %ecx = %esp + 4
- %ecxをスタックにpush
- 中略
- 2の値をスタックから%ecxにpop
- %esp = %ecx - 4
ようするに、一番最初にスタックポインタの値(+4)を保存しておいて、最後にその値を取り出してスタックポインタの値を元に戻しているわけです。
バッファオーバーフローが起こるとこのスタック上にある%ecxが書き換わってしまう為に%espを元に戻せなくなる為segmentation faultとなるのだと判明しました。
main: leal 4(%esp), %ecx // %ecx = %esp + 4 andl $-16, %esp // %espの下位4ビットを0に pushl -4(%ecx) // 本来の%esp(%ecx -4)の値をプッシュ pushl %ebp movl %esp, %ebp pushl %edi pushl %esi pushl %ecx subl $140, %esp movl %ecx, -128(%ebp) .. 中略 .. movl $0, %eax addl $140, %esp popl %ecx popl %esi popl %edi popl %ebp //leal -4(%ecx), %esp // %esp = %ecx - 4 ret
んで、本来このように%espの値をいじる必要性はないはずです。(どうなんでしょう?)
試しに一番最後のlealだけをコメントアウトしてみました。これでもプログラムはちゃんと動くはずです。
% gcc crackme.s -o crackme.s % exploit 0 password is incorrect. % echo $? 100
あっさり通りました。ということで、この行の存在の為にexploitが仕掛けられないということが判明。
ちょっとこれだとexploitを仕掛けるのは大変ですね。%ecxの存在するスタック上の位置とその値を正確に割り出して、そこだけ書換えないようにする必要性があります。(文字列上にこの4バイトを仕込む)
何の為にスタックポインタを操作しているんでしょうか??単にexploitを防ぐ為ではないような気がするのですがどうなんでしょう?
関数ポインタの書き換えによるexploit
こっちはめちゃめちゃ簡単。
こんなコードだとあっというまにexploitできちゃいます。やっぱりバッファオーバーフローは危険なので注意ですね。
#include <stdio.h> #include <string.h> void foo(const char* s){ printf("%s\n", s); return; } int main(int argc, char *argv[]) { char buf[10]; void (*func)(const char*); func = foo; strcpy(buf, argv[1]); foo(argv[1]); }