IO FILE 之vtable check 以及绕过 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

IO FILE 之vtable check 以及绕过

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

上一篇引见了libc2.23之前版本的挟制vtable以及FSOP的应用要领。如今vtable包括了云云多的函数,功用这么壮大,没有庇护的机制实在是有点说不过去。在人人都最先应用修正vtable指针举行掌握顺序流的时刻,glibc在2.24今后加入了响应的搜检机制,使得传统的修正vtable指针指向可控内存的要领失效。但道高一尺,魔高一丈,很快又涌现了新的绕过体式格局。本篇文章重要引见libc2.24今后的版本关于vtable的搜检以及响应的绕过体式格局。

之前几篇文章的传送门:

  • IO FILE之fopen详解
  • IO FILE之fread详解
  • IO FILE之fwrite详解
  • IO FILE之fclose详解
  • IO FILE之挟制vtable及FSOP

vtable check机制剖析

glibc 2.24引入了vtable check,先体验一下它的搜检,运用上篇文章中的东华杯的pwn450的exp,但将glibc改成2.24。(运用pwn_debug的话,将exp内里的debug('2.23')改成debug('2.24')就能够了,或许运用local形式)。

在2.24的glibc中直接运转exp,能够看到报了以下的毛病:
IO FILE 之vtable check 以及绕过
能够看到第一句memory corruption的毛病在2.23版本也是有的,第二句的毛病Fatal error: glibc detected an invalid stdio handle是新涌现的,看起来似乎是对IO的句柄举行了检测致使毛病。

glibc2.24的源码中搜刮该字符串,定位在_IO_vtable_check函数中。依据函数名猜想应当是对vtable举行了搜检,之前exp中是修正vtable指向了堆,多是致使搜检不过的缘由。

下面举行动态调试举行确认,起首搞清楚在那里下断。对vtable的搜检应当是在vtable挪用之前,FSOP触发的vtable函数_IO_OVERFLOW是在_IO_flush_all_lockp函数中举行挪用的,因而将断点下在_IO_flush_all_lockp处。

最先跟踪顺序,发如今实行_IO_OVERFLOW时,先实行到了IO_validate_vtable函数,然则看函数挪用_IO_OVERFLOW时并没有显著的挪用IO_validate_vtable函数的陈迹,猜想_IO_OVERFLOW宏的定义发生了变化。检察它的定义:

#define _IO_OVERFLOW(FP, CH) JUMP1 (__overflow, FP, CH)

再检察JUMP1的定义:

#define JUMP1(FUNC, THIS, X1) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1)

末了再看_IO_JUMPS_FUNC的定义:

# define _IO_JUMPS_FUNC(THIS) \
  (IO_validate_vtable                                                   \
   (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS)   \
                 + (THIS)->_vtable_offset)))

原来是在终究挪用vtable的函数之前,内联进了IO_validate_vtable函数,跟进去该函数,源码以下,文件在/libio/libioP.h中:

static inline const struct _IO_jump_t *
IO_validate_vtable (const struct _IO_jump_t *vtable)
{
  uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;
  const char *ptr = (const char *) vtable;
  uintptr_t offset = ptr - __start___libc_IO_vtables;
  if (__glibc_unlikely (offset >= section_length)) //搜检vtable指针是不是在glibc的vtable段中。
    /* The vtable pointer is not in the expected section.  Use the
       slow path, which will terminate the process if necessary.  */
    _IO_vtable_check ();
  return vtable;
}

能够看到glibc中是有一段完整的内存存放着各个vtable,个中__start___libc_IO_vtables指向第一个vtable地点_IO_helper_jumps,而__stop___libc_IO_vtables指向末了一个vtable_IO_str_chk_jumps完毕的地点:
IO FILE 之vtable check 以及绕过
平常掩盖vtable到客栈上的体式格局没法绕过此搜检,会进入到_IO_vtable_check搜检中,这就是最先报错的终究输出毛病语句的函数了,跟进去,文件在/libio/vtables.c中:

void attribute_hidden
_IO_vtable_check (void)
{
#ifdef SHARED
  /* Honor the compatibility flag.  */
  void (*flag) (void) = atomic_load_relaxed (&IO_accept_foreign_vtables);
#ifdef PTR_DEMANGLE
  PTR_DEMANGLE (flag);
#endif
  if (flag == &_IO_vtable_check) //搜检是不是是外部重构的vtable
    return;

  /* In case this libc copy is in a non-default namespace, we always
     need to accept foreign vtables because there is always a
     possibility that FILE * objects are passed across the linking
     boundary.  */
  {
    Dl_info di;
    struct link_map *l;
    if (_dl_open_hook != NULL
        || (_dl_addr (_IO_vtable_check, &di, &l, NULL) != 0
            && l->l_ns != LM_ID_BASE)) //搜检是不是是动态链接库中的vtable
      return;
  }

...

  __libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n");
}

进入该函数意味着现在的vtable不是glibc中的vtable,因而_IO_vtable_check推断顺序是不是运用了外部正当的vtable(重构或是动态链接库中的vtable),假如不是则报错。

glibc2.24中vtable中的check机制能够小结为:

  1. 推断vtable的地点是不是处于glibc中的vtable数组段,是的话,经由过程搜检。
  2. 不然推断是不是为外部的正当vtable(重构或是动态链接库中的vtable),是的话,经由过程搜检。
  3. 不然报错,输出Fatal error: glibc detected an invalid stdio handle,顺序退出。

所以终究的缘由是:exp中的vtable是堆的地点,不在vtable数组中,且没法经由过程后续的搜检,因而才会报错。

绕过vtable check

vtable check的机制已搞清楚了,该怎样绕过呢?

第一个想的是,是不是还能将vtable掩盖成外部地点?依据vtable check的机制要想将vtable掩盖成外部地点且依然经由过程搜检,能够有两种体式格局:

  1. 使得flag == &_IO_vtable_check
  2. 使_dl_open_hook!= NULL

第一种体式格局不可控,因为flag的猎取和比对是相似canary的体式格局,其对应的汇编代码以下:

0x7fefca93d927 <_IO_vtable_check+7>     mov    rax, qword ptr [rip + 0x32bb2a] <0x7fefcac69458>
0x7fefca93d92e <_IO_vtable_check+14>    ror    rax, 0x11
0x7fefca93d932 <_IO_vtable_check+18>    xor    rax, qword ptr fs:[0x30]
0x7fefca93d93b <_IO_vtable_check+27>    cmp    rax, rdi

我们没法掌握fs:[0x30]和获得它的值,因而不容易掌握flag == &_IO_vtable_check前提。

而关于第二种体式格局,理论上可行,然则假如我们能够找到存在往_dl_open_hook中写值的要领,完整应用该要领来举行更加简朴的应用(如写其他hook)。

看起来没法将vtable掩盖成外部地点了,另有其他啥要领?

现在来讲,存在两种方法:

  • 运用内部的vtable_IO_str_jumps_IO_wstr_jumps来举行应用。
  • 运用缓冲区指针来举行恣意内存读写。

这里重要形貌第一个要领运用内部的vtable_IO_str_jumps_IO_wstr_jumps来举行应用,第二个要领因为篇幅限定且功用也相对较自力,将在下一篇中论述。

怎样应用_IO_str_jumps_IO_wstr_jumps完成进击?在vtable的check机制涌现后,大佬们发现了vtable数组中存在_IO_str_jumps以及_IO_wstr_jumps两个vtable,_IO_wstr_jumps_IO_str_jumps功用基础一致,只是_IO_wstr_jumps是处置惩罚wchar的,因而这里以_IO_str_jumps为例举行申明,后者应用要领完整相同。

_IO_str_jumps的函数表以下
IO FILE 之vtable check 以及绕过
函数表中存在两个函数_IO_str_overflow以及_IO_str_finish,个中_IO_str_finish源代码以下,在文件/libio/strops.c中:

存在SSTI破绽的CMS合集

存在SSTI漏洞的CMS合集 前言 代码审计,考察的是扎扎实实的本领,CMS的漏洞的挖掘能力是衡量一个Web狗的强弱的标准,强网杯的时候,Web题目考的了一个CMS的代码审计,考察到了SSTI漏洞,菜鸡一枚的我过来汇总一下在PHP中的SSTI漏洞,忘能抛砖引玉,引起读者的共鸣。 SSTI漏洞概述 概念 SSTI(服务端模板注入)和常见Web注入的成因一样,也是服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分,在进行目标编译渲染的过程中,执行了用户插入的恶意内容,因而可能导致了敏感信息泄露、代码执行、GetShell 等问

void
_IO_str_finish (_IO_FILE *fp, int dummy)
{
  if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
    (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base); //实行函数
  fp->_IO_buf_base = NULL;

  _IO_default_finish (fp, 0);
}

能够看到,它运用了IO 组织体中的值看成函数地点来直接挪用,假如满足前提,将直接将fp->_s._free_buffer看成函数指针来挪用。

看到这里应用的体式格局应当就很显著了。起首,固然依然须要绕过之前的_IO_flush_all_lokcp函数中的输出缓冲区的搜检_mode<=0以及_IO_write_ptr>_IO_write_base进入到_IO_OVERFLOW中。

接着就是症结的组织IO FILE组织体的部份。起首是vtable搜检的绕过,我们能够将vtable的地点掩盖成_IO_str_jumps-8的地点,如许会使得_IO_str_finish函数成为了捏造的vtable地点的_IO_OVERFLOW函数(因为_IO_str_finish偏移为_IO_str_jumps中0x10,而_IO_OVERFLOW为0x18)。这个vtable(地点为_IO_str_jumps-8)能够绕过搜检,因为它在vtable的地点段中。

组织好vtable以后,须要做的就是组织IO FILE组织体其他字段来进入把fp->_s._free_buffer看成指针的挪用。先组织fp->_IO_buf_base不为空,而且看到背面它将作为第一个参数,因而能够运用/bin/sh的地点;然后组织fp->_flags要不包括_IO_USER_BUF,它的定义为#define _IO_USER_BUF 1,即fp->_flags最低位为0。满足这两个前提,将会运用IO 组织体中的指针看成函数指针来挪用。

末了组织fp->_s._free_buffersystemone gadget的地点,末了挪用(fp->_s._free_buffer) (fp->_IO_buf_base)fp->_IO_buf_base为第一个参数。

_IO_str_jumps中的另一个函数_IO_str_overflow也存在该状况,然则它所需的前提会更加庞杂一些,道理一致,就不举行形貌了,有兴致的能够本身去看。而另一个vtable_IO_wstr_jumps_IO_str_jumps表中的函数指针功用一致,因而也是完整一样的运用要领。

末了,假如libc中没有_IO_wstr_jumps_IO_str_jumps表的标记,给出定位_IO_str_jumps_IO_wstr_jumps的要领:

  • 定位_IO_str_jumps表的要领,_IO_str_jumps是vtable中的倒数第二个表,能够经由过程vtable的末了地点减去0x168
  • 定位_IO_wstr_jumps表的要领,能够经由过程先定位_IO_wfile_jumps,获得它的偏移后再减去0x240等于_IO_wstr_jumps的地点。

实践

末了给出两道题举行响应的实践,现实体验下怎样运用_IO_str_jumps来绕过vtable check。从网上挑选了一圈,找了两道题。一道题是hctf 2017的babyprintf,应当是很典范的一道题了;一道是ASIS2018的fifty-dollars,这道题用了FSOP中的两次_chain链接,很有意义,值得一看。

babyprintf

问题中格式化字符串以及堆溢出很显著。

然则格式化字符串破绽运用__printf_chk,该函数限定了格式化字符串在运用%a$p时须要同时运用%1$p%a$p才能够,而且禁用了%n。因而只能运用破绽来泄漏地点。

堆溢出应用的要领与上篇的东华杯pwn450的用法基础一致,掩盖top chunksize,使得体系挪用sysmalloc将top chunk放到unsorted bin里,然后应用unsorted bin attack改写_IO_list_all,指向捏造好的IO 组织体,vtable运用的地点是_IO_str_jumps-8,末了组织出来的IO组织体数据以下:
IO FILE 之vtable check 以及绕过

个中fp->_mode为0且fp->_IO_write_ptr>_fp->_IO_write_base,经由过程了house of orange的搜检,能够进入到_IO_OVERFLOW的挪用;同时vtable表指向_IO_str_jumps-8在vtable段中,也可绕过vtable的check机制;末了fp->_flags为0,fp->_IO_buf_base不为空,且指向/bin/sh字符串地点,能够顺遂进入到(fp->_s._free_buffer) (fp->_IO_buf_base)的挪用。在exp中能够运用pwn_debugIO_FILE_plus模块的str_finish_check函数来搜检所组织的字段是不是能经由过程搜检。

vtable表指针以下,能够看到当前的__overflow函数确实为_IO_str_finish
IO FILE 之vtable check 以及绕过

末了再看跳转的目的地点,确实为system函数且参数_IO_buf_base/bin/sh的地点,因而实行system("/bin/sh"),胜利拿到shell。
IO FILE 之vtable check 以及绕过
IO FILE 之vtable check 以及绕过

固然这题也能够用fastbin attack做,因为top chunksize不够的时刻是运用free函数来开释的,因而也会放到fastbin中去。

fifty_dollars

这题是一道菜单题,供应请求、打印以及开释的功用,free了今后指针没清空,致使uaf,能够完成堆地点恣意写的功用。

先说一下怎样运用uaf组织出unsroted bin,以下面一个demo,重如果经由过程fastbin attack修正响应chunk的size,再开释时,将会开释至unsorted bin中:

A=alloc(0)
B=alloc(1)
C=alloc(2)
delete(A)
delete(B)
delete(A)
#此时构成fastbin attack
A=alloc(0,data=p64(addressof(C)-0x10) # 修正fastbin的fd指向c-0x10
B=alloc(1)
A=alloc(0)

evil=alloc(3,data=p64(0)+p64(0xb1)) #修正C的size为0xb0
delete(C) #此时C将被开释至

可经由过程开释到fastbin的链表中,再show能够泄漏出堆地点;经由过程将堆块开释到unsorted bin中,再show可泄漏libc地点。

这题的限定是只能请求0x60大小的堆块,运用house of orange进击的时刻没法把unsorted bin 开释到small bin为0x60的数组中(即满足fp->_chain指向我们的堆块中),为此只能想方法开释一个终究构成fp->_chain->_chain指向我们堆块的地点的堆块(即大小为0xb0的堆块)。经由过程两次chain的索引,终究完成掌握IO FILE组织,挪用_IO_OVERFLOW掌握顺序实行流。

末了捏造_IO_list_all组织以下,_IO_list_all指向unsorted bin的指针的位置:
IO FILE 之vtable check 以及绕过
_IO_list_all->_chain指向unsorted bin+0x68的位置即smallbin size为0x60的位置:
IO FILE 之vtable check 以及绕过
_IO_list_all->_chain->_chain指向unsorted bin+0xd0的位置,即smallbin size为0xb0的位置,此时因为存在我们已开释的堆的地点,因而它指向了我们捏造的组织。
IO FILE 之vtable check 以及绕过

堆内容的组织则和上一题babyprintf没有区分,以至能够运用同一个模版,不再细说。掩盖vtalbe为_IO_str_jumps-8,绕过vtable的check,同时设置好IO FILE的字段绕过响应搜检,终究进入到_IO_flush_all_lockp触发FSOP,经由两次_chain的索引就会实行system("/bin/sh")

重要应用FSOP两次_chain的头脑,照样很有意义的。

小结

这是本系列的倒数第二篇文章,引见了vtable的check机制和其响应的绕过要领之一。vtable数组中的各个成员都有其响应的功用,终究在内里找到了_IO_str_jumps_IO_wstr_jumps两个虚表来完成应用。

相干文件和剧本在github


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

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

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