House Of Einherjar
介绍
house of einherjar 是一种堆利用技术,由 Hiroki Matsukuma
提出。该堆利用技术可以强制使得 malloc
返回一个几乎任意地址的 chunk 。其主要在于滥用 free
中的后向合并操作(合并低地址的 chunk),从而使得尽可能避免碎片化。
此外,需要注意的是,在一些特殊大小的堆块中,off by one 不仅可以修改下一个堆块的 prev_size,还可以修改下一个堆块的 PREV_INUSE 比特位。
原理
后向合并操作
free
函数中的后向合并核心操作如下
1 | /* consolidate backward */ |
后向合并是合并低地址的chunk,和prev_size和prev_inuse有关,只要我们可以控制这俩个,修改prev_size的大小,我们就可以通过后向合并,将合并后的chunk定位到任何地方。
但是在合并的过程中需要进行unlink,需要在对应chunk构造好fake chunk来绕过unlink的检测。这种利用方式和chunk extend/overlapping比较相似。
这里的绕过unlink操作和之前有点不一样。
1 | p->fd = p |
下面以一道例题讲解一下:
2016 Seccon tinypad
checksec检查:
1 | Arch: amd64-64-little |
main函数如下:
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
漏洞函数如下:
1 | unsigned __int64 __fastcall read_until(__int64 a1, unsigned __int64 a2, unsigned int a3) |
利用:
1.程序free的时候只将size位清空,而没有将指针清空,就导致uaf漏洞,我们可以通过该漏洞泄露heap_base。
1 | add(0x70,'L0ne1y') |
2.通过UAF泄露libc_base。
1 | free(3) |
因为chunk3和top chunk相邻,所以释放时不会被加入Unsorted Bin。然后直接合并到top chunk中。然后此时,fastbin中有两个相邻堆块,并且与top chunk相邻,会触发合并,fastbin-> 1-> 2,首先1会先被加入unsorted bin中,此时chunk 1’so fd和bk指针会指向main_arena + 88(Unsorted Bin)地址。然后chunk 2和chunk 1合并成一个新的chunk放入unsorted bin中。这个过程并不会改变chunk 1的fd和bk指针。所以此时输出memo 1的内容就会输出unsorted bin的地址,继而算出libc地址。
3.house of einherjar攻击
1 | add(0x18, 'a'*0x10) #1 |
1 | add(0x100, 'b'*0xf8+'\x11') #2 |
因为off by one 导致chunk3的size位变为0,所以需要伪造上。
1 | edit(3,'c'*0x20+fake_chunk) |
这里需要在tinypad伪造chunk,为后续house of einherjar做准备。
1 | add(0x18,'a'*0x10+p64(offest)) |
覆盖prev_size,准备unlink
1 | edit(4, "4"*0x20 + p64(0) + p64(0x101) + p64(main_arena + 88)*2) |
0x101是为了后面分配用的,而p64(leak_libc+88)*2 这里,你只要bk是个可写的地址就行了,不要是不可写的就行,unsortedbin攻击里讲过。
1 | #在 glibc/malloc/malloc.c 中的 _int_malloc 有这么一段代码,当将一个 unsorted bin 取出的时候,会将 bck->fd 的位置写入本 Unsorted Bin 的位置。 |
4.获取environ指针
1 | one_gadget=libc_base+0xf1207 |
在 Linux 系统中,glibc 的环境指针 environ(environment pointer) 为程序运行时所需要的环境变量表的起始地址,环境表中的指针指向各环境变量字符串。从以下结果可知环境指针 environ 在栈空间的高地址处。因此,可通过 environ 指针泄露栈地址。
相关知识:
http://0x4c43.cn/2018/1013/stack-overflow-smash-utilization/
5.get shell
1 | add(0xf0, '1'*0xd0 + p64(0x18) + p64(environ_pointer)+'a'*8+p64(0x602148)) |
1 | add(0xf0, '1'*0xd0 + p64(0x18) + p64(environ_pointer)+'a'*8+p64(0x602148)) |
将[tinypad +256]中的Chunk2的堆栈地址修改为chunk1,将chunk1的堆栈地址修改为Environ_pointer,泄露Environ_pointer的栈地址,得到main_ret地址,再造成main_ret->one_gadget的情况。
exp如下:
1 | #! /usr/bin/env python |
参考链接:
https://v1ckydxp.github.io/2019/07/07/House_Of_Einherjar--2016-Seccon-tinypad-writeup/
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/house_of_einherjar-zh/