关于SHSTK保护
目前,雖然許多文章都表示SHSTK技術已經十分完備,但是從linux官方文檔來看,想要实际对于一个程序,启用SHSTK,需要运行程序者主动声明。因此,即使很多elf在checksec下能够检查出来,其实这也只是声明了,此elf具有SHSTK标签,实际启用SHSTK,还需要许多部分同步启用。这就导致,目前可以说,几乎所有赛题,都没有SHSTK。除非有特殊声明。
bph
这题的glibc非常新,我使用libc_database下到了非常后面的版本,还是没search出来,当时又看到SHSTK,觉得即使知道了libc_database ,在没有ROP的情况下,打orw也很困难,于是有点放弃了。
目前靶机已经关闭,根据 Polaris 战队提供的wp,了解到是使用 ubuntu24.04 搭建。通常对应了glibc2.39。
程序的漏洞非常明显 : 如果malloc失败,malloc实际上返回的是0 , 而之后有个无视malloc是否返回成功,在ptr + size -1 位置写入\x00 的代码。实际上就是给出了任意地址写入\x00
但是目前状态下,没有泄露stack / lilbc / heap 任何一个部分的base。
在前面输入token的部分 可以泄露 libc or stack 考虑到写入一个字节是一个非常弱小的primitive,应该是需要扩大写入权限的,如果泄露栈上地址,并且还不知道text 段地址 几乎没任何意义。反而在libc中,由于有stdin的iofile,打IOfile 可能可以扩大写入权限,进行进一步的攻击。
在IO_file 中,存在一个指定缓冲区位置的指针”IO_buf_base”,它指定了一个file的缓冲区的起点。通常,对于一个file,会有个内联的缓冲区short_buf,它是紧跟在IO_file结构体之后的,这也是为什么有时候通过直接泄露stdin里面的内容可以泄露flag,当short_buf 空间不足时(shortbuf只有一个字节大小,也就是说,如果不是0缓冲就不用这个了) 会从heap上申请空间,迁移IO_buf_base 和 IO_buf_end指针,其他像IO_write_base等指针会跟进迁移。
打印一个stdin的 IO_file来看一下
pwndbg> p *(FILE *) 0x7ffff7f6e8e0 |
这个stdin是从bph 中取出来的
这是还没读取进信息时的stdin
尝试输入token,基本上内容都是一样的,因为此时是0缓冲。
用gdb修改base到stdin起点
调用read 会发现所有write_base read_base 等指针都跟进了
pwndbg> p *(FILE *) 0x7ffff7f6e8e0 |
但是并没有看到篡改现象,因为read是非常底层的函数。
再在gdb调用gets(ptr) 随便输入点数据 看看会发生什么
pwndbg> x/10gx 0x7ffff7f6e8e0 |
篡改出现了。同时 read_ptr read_end 都同步了
_IO_read_ptr = 0x7ffff7f6e8e6 <_IO_2_1_stdin_+6> "", |
这就表示我们可以扩大利用范围了。有控制iofile的权利,通常的思路就是控制vtable,在高版本中,vtable会检查是否在合法的范围内,因此最好是通过调用io有关函数,来控制需要的寄存器。
另外,IOfile攻击,通常需要考虑一两次的利用就达成目的,而题目要求打orw, 通常使用ROP更好,因此需要进行一次栈迁移,这里有个方便的函数: setcontext 。 传入一个sigframe, setcontext 就能控制大部分的寄存器。
polaris的解法基本上就基于上面的思路,利用方式很像house_of_apple
所以下面扩展一下 , house_of_apple 的原型
house of apple1
能从main返回或能exit
heap地址和libc地址泄露
一次largebin attack
fcloseall 利用链:
fcloseall -> 遍历_IO_list_all ,调用vtable->_overflow。
largebin attack 可以伪造_IO_FILE结构体,apple1在此基础上 通过_wide_data 扩大利用范围。
具体来说 运用到了_IO_wstrn_overflow
_IO_wstrn_overflow (FILE *fp, wint_t c) |
typedef struct |
从上述部分可以看到 假设有伪造的_IO_file A , 并且里面有伪造的_wide_data字段B , 伪造vtable为_IO_wstrn_jumps , 就可以将B 到 B + 0x38 写成 A+0xf0 或 A + 0x1f0 (0x1f0不知道哪来的 但是原博客就是这么写的)
为了绕过free ,还需要设置_flags2字段为8
一个demo
|
发现使用的glibc版本是 2.34 ubuntu3.2
❯ ./demo |
总体上来说,house_of_apple1,将一个largebin_attack的initialtive扩展到了任意地址写入已知地址,便于进一步利用。前提是能够泄露libc和heap地址。
利用思路
一、 修改Tcache线程变量tcache_pthread_struct
二、 修改mp_结构体:_IO_wstrn_overflow函数修改mp_.tcache_bins为很大的值
三、 修改pointer_guard 打 house of emma。
四、 修改global_max_fast 释放超大的chunk,去覆盖掉point_guard或者tcache变量。house of apple + house of corrision。
house_of_apple2
神级的利用方法,出现的概率特别高!
前提:
heap泄露+libc泄露
控制程序执行io操作main return,exit,__malloc_assert..
劫持vtable 和 _wide_data,一般使用largebin attack 控制
原理: 和house_of_apple一致,也是利用了_wide_vtable 指针没有被检查合法性,而是直接通过宏去调用了它内部的指针。
可以劫持IO_FILE的vtable为_IO_wfile_jumps,控制_wide_data为可控的堆地址空间,进而控制_wide_data->_wide_vtable为可控的堆地址空间。控制程序执行IO流函数调用,最终调用到_IO_Wxxxxx函数即可控制程序的执行流。
利用链
利用的最终目的不是wfile_overflow ,而是通过 IO_OVERFLOW 跳转到wfile_jumps 内部的函数,通过这个函数做中转,再跳转到另一个wfile_jumps 中的函数,强网杯这次的题就非常灵活的利用到了这个思想。
Roderick 大佬提供的三个比较方便的利用链:
_IO_wfile_overflow |
伪造:
_flags设置为~(2 | 0x8 | 0x800),如果不需要控制rdi,设置为0即可;如果需要获得shell,可设置为sh;,注意前面有两个空格vtable设置为_IO_wfile_jumps/_IO_wfile_jumps_mmap/_IO_wfile_jumps_maybe_mmap地址(加减偏移),使其能成功调用_IO_wfile_overflow即可_wide_data设置为可控堆地址A,即满足*(fp + 0xa0) = A_wide_data->_IO_write_base设置为0,即满足*(A + 0x18) = 0_wide_data->_IO_buf_base设置为0,即满足*(A + 0x30) = 0_wide_data->_wide_vtable设置为可控堆地址B,即满足*(A + 0xe0) = B_wide_data->_wide_vtable->doallocate设置为地址C用于劫持RIP,即满足*(B + 0x68) = C
_IO_wfile_underflow_mmap |
_flags设置为~4,如果不需要控制rdi,设置为0即可;如果需要获得shell,可设置为sh;,注意前面有个空格vtable设置为_IO_wfile_jumps_mmap地址(加减偏移),使其能成功调用_IO_wfile_underflow_mmap即可_IO_read_ptr < _IO_read_end,即满足*(fp + 8) < *(fp + 0x10)_wide_data设置为可控堆地址A,即满足*(fp + 0xa0) = A_wide_data->_IO_read_ptr >= _wide_data->_IO_read_end,即满足*A >= *(A + 8)_wide_data->_IO_buf_base设置为0,即满足*(A + 0x30) = 0_wide_data->_IO_save_base设置为0或者合法的可被free的地址,即满足*(A + 0x40) = 0_wide_data->_wide_vtable设置为可控堆地址B,即满足*(A + 0xe0) = B_wide_data->_wide_vtable->doallocate设置为地址C用于劫持RIP,即满足*(B + 0x68) = C
_IO_wdefault_xsgetn |
_flags设置为0x800vtable设置为_IO_wstrn_jumps/_IO_wmem_jumps/_IO_wstr_jumps地址(加减偏移),使其能成功调用_IO_wdefault_xsgetn即可_mode设置为大于0,即满足*(fp + 0xc0) > 0_wide_data设置为可控堆地址A,即满足*(fp + 0xa0) = A_wide_data->_IO_read_end == _wide_data->_IO_read_ptr设置为0,即满足*(A + 8) = *A_wide_data->_IO_write_ptr > _wide_data->_IO_write_base,即满足*(A + 0x20) > *(A + 0x18)_wide_data->_wide_vtable设置为可控堆地址B,即满足*(A + 0xe0) = B_wide_data->_wide_vtable->overflow设置为地址C用于劫持RIP,即满足*(B + 0x18) = C
另外 要求rdx 不为0
house_of_apple3
在劫持FILE->_codecvt的基础上,直接控制程序执行流。
使用条件和 house of apple2 几乎相同
如果是伪造整个结构体 需要合适的_wide_data 如果只能伪造部分FILE成员,就保持fp->_wide_data是默认地址
感觉这玩意不如house_of_apple2 好用,直接贴链接得了
[原创]House of apple 一种新的glibc中IO攻击方法 (3)-Pwn-看雪论坛-安全社区|非营利性质技术交流社区
bph
这个题的独特之处在于,最初可以任意写入的部分就在libc 内部的_IO_file ,因此相比最原始的 house_of_apple2 ,更加灵活。 但是同时 ,程序使用了seccomp 沙箱限制了要打orw ,这就导致不好通过一个backdoor 解决,于是想到通过setcontext中的gadget进行栈迁移。但是这就需要能够提前控制rdx。
基于house_of_apple2 的核心思想,通过wfile_jumps中的一个函数进行中转。最后执行任意函数,那么这里wfile_jumps中就应该找一个可以伪造rdx的函数,任意函数就是setcontext。
