オーバーフローについての勉強
ある本を参考にオーバーフローの勉強をしています。
Ubuntu10.10でgcc4.4.5でやっているのですが、その本がでたときよりもいろいろと
セキュリティが強化されてしまってサンプルソースが上手く動かないんですよね。
そんなこんなで寄り道ばかりしています。
void overflow_function(char *str){ char buffer[20]; strcpy(buffer, str); } int main(){ char big_string[20]; int i; for(i = 0; i < 20; i++){ big_string[i] = 'A'; } overflow_function(big_string); exit(0); }
まずは正常に終了するパターンを。
(gdb) b overflow_function Breakpoint 1 at 0x8048450: file overflow.c, line 1. (gdb) r (gdb) p $ebp $1 = (void *) 0xbffff858 (gdb) p $esp $2 = (void *) 0xbffff810
30byteのスタックフレームがあるようです。
(gdb) p &buffer $3 = (char (*)[20]) 0xbffff838
0xbffff838〜0xbfff84cがbufferの領域っぽいです。
(gdb) s (gdb) (gdb) x/8xw &buffer 0xbffff838: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff848: 0x41414141 0xb4153f00 0x00000000 0x08049ff4
20byteに0x41が入っていることが確認できました。
さて戻りのアドレスはどこにはいってるんでしょうか。
(gdb) disas main Dump of assembler code for function main: 0x08048480 <+0>: push %ebp 0x08048481 <+1>: mov %esp,%ebp 0x08048483 <+3>: and $0xfffffff0,%esp 0x08048486 <+6>: sub $0x30,%esp 0x08048489 <+9>: mov %gs:0x14,%eax 0x0804848f <+15>: mov %eax,0x2c(%esp) 0x08048493 <+19>: xor %eax,%eax 0x08048495 <+21>: movl $0x0,0x14(%esp) 0x0804849d <+29>: jmp 0x80484ad <main+45> 0x0804849f <+31>: mov 0x14(%esp),%eax 0x080484a3 <+35>: movb $0x41,0x18(%esp,%eax,1) 0x080484a8 <+40>: addl $0x1,0x14(%esp) 0x080484ad <+45>: cmpl $0x13,0x14(%esp) 0x080484b2 <+50>: jle 0x804849f <main+31> 0x080484b4 <+52>: lea 0x18(%esp),%eax 0x080484b8 <+56>: mov %eax,(%esp) 0x080484bb <+59>: call 0x8048444 <overflow_function> 0x080484c0 <+64>: movl $0x0,(%esp) 0x080484c7 <+71>: call 0x8048378 <exit@plt> End of assembler dump.
アセンブラを見てみると0x080484c0がoverflow_functionの次に実行されるところです。
(gdb) x/12xw &buffer 0xbffff838: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff848: 0x41414141 0xb4153f00 0x00000000 0x08049ff4 0xbffff858: 0xbffff898 0x080484c0 0xbffff878 0x08049ff4
少し範囲を広げてスタックを見てみると0xbffff85cに戻りのアドレスが入っていることが分ります。
ここが変ってしまうと戻れなくなるわけです。
bufferが20byte確保しているわけだから、あと20byteの40byte分をstrcpyしようとすると
戻りのアドレスが書きかわるはずです。
void overflow_function(char *str){ char buffer[20]; strcpy(buffer, str); } int main(){ char big_string[40]; int i; for(i = 0; i < 40; i++){ big_string[i] = 'A'; } overflow_function(big_string); exit(0); }
こう変えてみました。
(gdb) b overflow_function Breakpoint 1 at 0x8048450: file overflow.c, line 1. (gdb) r Breakpoint 1, overflow_function (str=0xbffff864 'A' <repeats 40 times>) at overflow.c:1 (gdb) s (gdb) disas main Dump of assembler code for function main: 0x08048480 <+0>: push %ebp 0x08048481 <+1>: mov %esp,%ebp 0x08048483 <+3>: and $0xfffffff0,%esp 0x08048486 <+6>: sub $0x40,%esp 0x08048489 <+9>: mov %gs:0x14,%eax 0x0804848f <+15>: mov %eax,0x3c(%esp) 0x08048493 <+19>: xor %eax,%eax 0x08048495 <+21>: movl $0x0,0x10(%esp) 0x0804849d <+29>: jmp 0x80484ad <main+45> 0x0804849f <+31>: mov 0x10(%esp),%eax 0x080484a3 <+35>: movb $0x41,0x14(%esp,%eax,1) 0x080484a8 <+40>: addl $0x1,0x10(%esp) 0x080484ad <+45>: cmpl $0x27,0x10(%esp) 0x080484b2 <+50>: jle 0x804849f <main+31> 0x080484b4 <+52>: lea 0x14(%esp),%eax 0x080484b8 <+56>: mov %eax,(%esp) 0x080484bb <+59>: call 0x8048444 <overflow_function> 0x080484c0 <+64>: movl $0x0,(%esp) 0x080484c7 <+71>: call 0x8048378 <exit@plt> End of assembler dump. (gdb) x/12xw &buffer 0xbffff828: 0x00000000 0x00000001 0x0012d918 0x00000001 0xbffff838: 0x00008000 0x279a6000 0x00237e79 0x0015e785 0xbffff848: 0xbffff898 0x080484c0 0xbffff864 0x08049ff4 (gdb) s (gdb) x/12xw &buffer 0xbffff828: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff838: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff848: 0x41414141 0x41414141 0xbffff800 0x08049ff4
書き換えれました。
進めてみます。
(gdb) s *** stack smashing detected ***: /home/hogehoge/Ubuntu One/hack/pra/overflow terminated ======= Backtrace: ========= /lib/libc.so.6(__fortify_fail+0x50)[0x214970] /lib/libc.so.6(+0xe591a)[0x21491a] /home/hogehoge/Ubuntu One/hack/pra/overflow[0x804847e] [0x41414141] ======= Memory map: ======== 00110000-0012c000 r-xp 00000000 08:01 1050494 /lib/ld-2.12.1.so 0012c000-0012d000 r--p 0001b000 08:01 1050494 /lib/ld-2.12.1.so 0012d000-0012e000 rw-p 0001c000 08:01 1050494 /lib/ld-2.12.1.so 0012e000-0012f000 r-xp 00000000 00:00 0 [vdso] 0012f000-00286000 r-xp 00000000 08:01 1052037 /lib/libc-2.12.1.so 00286000-00288000 r--p 00157000 08:01 1052037 /lib/libc-2.12.1.so 00288000-00289000 rw-p 00159000 08:01 1052037 /lib/libc-2.12.1.so 00289000-0028c000 rw-p 00000000 00:00 0 0028c000-002a6000 r-xp 00000000 08:01 1048655 /lib/libgcc_s.so.1 002a6000-002a7000 r--p 00019000 08:01 1048655 /lib/libgcc_s.so.1 002a7000-002a8000 rw-p 0001a000 08:01 1048655 /lib/libgcc_s.so.1 08048000-08049000 r-xp 00000000 08:01 3547331 /home/hogehoge/Ubuntu One/hack/pra/overflow 08049000-0804a000 r--p 00000000 08:01 3547331 /home/hogehoge/Ubuntu One/hack/pra/overflow 0804a000-0804b000 rw-p 00001000 08:01 3547331 /home/hogehoge/Ubuntu One/hack/pra/overflow 0804b000-0806c000 rw-p 00000000 00:00 0 [heap] b7feb000-b7fec000 rw-p 00000000 00:00 0 b7ffe000-b8000000 rw-p 00000000 00:00 0 bffdf000-c0000000 rw-p 00000000 00:00 0 [stack] Program received signal SIGABRT, Aborted. 0x0012e416 in __kernel_vsyscall ()
Abortしました。
ここまでは分るんですけど・・・