その時々

その時々で違うんです。特に決まっていないんです。

オーバーフローについての勉強

ある本を参考にオーバーフローの勉強をしています。
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しました。

ここまでは分るんですけど・・・