NULL_FXCK 复现
1 | GNU C Library (Ubuntu GLIBC 2.32-0ubuntu3) release release version 2.32 |
1 | main: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=1463577d47e320d9b46df83575b5778e3368f79f, for GNU/Linux 3.2.0, stripped |
- 64位,dynamically,全开
开了沙盒:
1 | 0000: 0x20 0x00 0x00 0x00000004 A = arch |
- 只能用 ORW
漏洞分析
1 | void __fastcall edit() |
- 有一个 off-by-one
入侵思路
这次尝试使用 House Of Kiwi 来解题,首先要使用这个 off-by-one 来进行 leak,但 libc-2.29 版本以后增加了一些检查:
1 | /* consolidate backward */ |
- 需要 last chunk->size == victim chunk->presize
unlink 中也有一些检查:
1 | if (chunksize (p) != prev_size (next_chunk (p))) |
- 需要 victim chunk->size == next chunk->presize
1 | if (__builtin_expect (fd->bk != p || bk->fd != p, 0)) |
- fd->bk == p:chunkP 的下一个 chunk 的上一个 chunk 是不是 chunkP
- bk->fd == p:chunkP 的上一个 chunk 的下一个 chunk 是不是 chunkP
由于没法 leak heap_base,就要通过以下的办法进行绕过:
- 使用 large chunk 遗留的 fd_nextsize 和 bk_nextsize 指针
- 以 fd_nextsize 为 fake_chunk 的 fd
- 以 bk_nextsize 为 fake_chunk 的 bk
- 也可以使用 unsorted chunk 或者 large chunk 的 FD BK 指针,就是对堆风水的要求比较高
heap 风水的构建
我自己弄的时候一头雾水,忙活了一个下午也没有搞出来,晚上参考了几个 wp,这里我说下思路:
思路一:
- 合并两个 unsortedbin,在
0x000
处留下如下的 heap 结构
1 | pwndbg> telescope 0x5639c214c000 |
- 利用 unsortedbin 遗留下来的 FD BK 指针进行操作,往
0xa00->bk
和0x400->fd
中写入0x030
,然后利用程序的末尾置空把0x030
改为0x000
- 修改
0x000->size=0xa00
,修改0xa00->pre_size=0xa00
1 | add(0x148) #0 |
思路二:
- 合并两个 unsortedbin,在
0xd00
处留下如下的 heap 结构
1 | pwndbg> telescope 0x55f18f2d1d00 |
- 利用 unsortedbin 遗留下来的 FD BK 指针进行操作,往
0x2b0->bk
和0x350->fd
中写入0xd20
,然后利用程序的末尾置空把0xd20
改为0xd00
- 申请一个大 chunk 使
0x350
进入 largebin,这里主要是为了改变 chunk 的取出方式(largebin 从大到小进行组织-插头取头,unsortedbin FIFO-插头取尾) - 修改
0xd00->size=0xc91
,修改0x990->pre_size=0xc90
1 | add(0x418) #0 |
- PS:可能需要一些爆破来得到远程 TLS 的偏移
- 参考这位大佬的博客:通过LIBC基址来爆破TLS
两个思路最核心的地方就是:
- 获取两个 unsorted chunk 进行合并,其中的第二个 chunk 末地址必须为
\x00
(遗留下 FD BK 指针) - 重新申请大 unsorted chunk 后释放(不破坏原来的 heap 结构),然后再次进行分割,使第二个 chunk 的末尾地址为
\x30
或者\x40
\x50
等等(有一定偏移的地址都可以) - 之后利用 unsortedbin 进行调整,在 FD->bk 和 BK->fd 中写入
\x30
,然后覆盖为\x00
因为 [思路二] 可以泄露 heap_base,这里选择 [思路二]
通过 TLS 劫持 tcache struct 以实现三次 WAA
House Of Kiwi 需要三次 WAA,用常规的 WAA 不能到达目的,只能劫持 main_arena
malloc_init 会在 heap 段开设一个内存用于管理 tcache(第一个 chunk,tcache struct),而 tcache struct 的地址,可以从 heapbase 被我们劫持到另一个地方:
- tcache struct 的地址被记录在 TLS 段中,只要修改这里就可以劫持 tcache struct
- 通过以下方法可以找到 TLS 段的位置:
1 | pwndbg> p &main_arena |
接下来就通过 largebin attack 来修改 0x7fddd4a116f8
处存储的 tcache struct addr:
- 由于前面已经实现了 heap overlapping,存在一个大 chunk,其中包含了一个小 chunk,两者都可以被控制
- 于是我们先释放小 chunk,再释放大 chunk
- 接下来申请大 chunk,在小 chunk 中完成 large attack 的布局
进行攻击前:
1 | pwndbg> telescope 0x7f8bed8866e8 |
进行攻击后:
1 | pwndbg> telescope 0x7f8bed8866e8 |
而 0x350
也是可控地址,申请这片区域然后在此伪造 fake tcache struct,分别布置好 IO_file_jumps+0x60
, IO_helper_jumps+0xa0
, top_heap
House Of Kiwi 的攻击基本上已经完成了
完整 exp:
1 | # -*- coding: utf-8 -*- |
小结:
这个题的堆风水真是够呛,好在让我整理学习了一些思路,以后按照这个来改应该没有问题
我还重新复习了下 off-by-one 和 unlink 的基础检查,各个 libc 版本的源码都对比着看了看,算是把以前的东西捡起来了吧
学习使用了 House Of Kiwi