DASCTF2021
fruitpie
思路
这题可以malloc一个指定size的chunk,并且返回chunk的地址,然后可以指定一个偏移,向偏移中写入0x10个字节的数据。这题申请很大的空间以后heap的地址和libc的基地址是相对固定的。
- 申请一个很大的空间,要尽可能的大
- 拿到heap地址根据相对偏移算出libc地址
- 设定指定的偏移值,向
__malloc_hook
中写入gadget
EXP
1 | from pwn import * |
ParentSimulator
程序分析
这是典型的表单题,程序中申请的结构大概如下所示,其大小是0x100。用seccomp-tools检查程序发现程序禁用了execve的syscall,所以考虑利用orw获得提权。
1 | struct baby |
程序中有几个重要的函数分别是birth、change_name、change_des、remove和show
birth有如下功能:
- malloc申请0x100的空间来存储一个baby
- 输入name和设置gender
- 对应标志位置1(use)
change_name用来修改结构中的name(检查标志位是否为1)
change_des用来修改结构中的des(检查标志位是否为1)
remove释放指定的baby,并且对用标志位置0,地址不清空(释放时不检查标志位,而是检查地址不为空)
show将所有的baby的name、gender和des打印出来
思路
获得libc地址
这里remove不清空地址,而且释放时不检查标志位,只检查地址不为空,因此可以重复释放地址(明显的double free)。由于2.31中libc地址会检查tcache的double free的,但是可以利用unsortbin来进行double free。具体步骤如下:
- 首先释放堆块填满 tcache(包含需要double free的堆块chunk0)
- 将需要double free的堆块和在其之前的,相连的堆块chunk1一起释放,两个块合并一起进入unsortbin
- 将tcache中的堆块申请完(chunk0已经被申请)
- 申请chunk1,切割unsortbin使得libc的地址进入chunk0中
- 利用程序的show,获得libc的地址
栈迁移,执行orw
- 继续申请堆块姜chunk0申请出来,现在我们有两个地方存在chunk0,利用uaf,我们先释放掉一个堆块进入tcache中然后再释放一个chunk0,这样chunk0中就有一个堆地址,这时再输出chunk0我们就能拿到heap的地址。
- 利用uaf,利用change_name修改chunk0的fd指针,是指针指向和chunk0的des重合的堆块(为之后栈迁移做准备),从而申请重叠堆块。
- 再将chunk0释放如tache进行uaf。利用change_name修改chunk0的下个堆块到
__free_hook
,然后再连续申请两个就能够拿到__free_hook
的控制权。 - 程序开了沙箱将execve的syscall给禁用了,只能考虑orw。orw依赖栈才能够有效,所以首先要进行栈迁移。推荐一个gadget,此gadget通过rdi控制rdx。利用
__free_hook
执行gadget,然后再配和setcontext+61通过rdx控制rsp来进行栈迁移。
1 | 0x00000000001547a0: mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20]; |
EXP
1 | from pwn import * |
babybabybabyheap
程序首先会给一个puts的地址printf("gift: %p\n", &puts);
,就将libc的地址给泄漏出来了。检查程序开启的保护,发现程序没有开启pie保护,这意味着我们知道程序的地址。
程序主要有三个函数alloc、dlt和vul函数
alloc函数会用malloc申请0x80~0x200的空间并且往里面写入内容(但是没有溢出),并且记录下size大小
dlt会首先检查将要释放的空间的size是否为空,然后释放对应的空间,并且清空对应的size(没有double free)
vul函数只能执行一次,修改指定的堆块的内容,会溢出一个NULL。
思路
程序是有一个offset by none 的漏洞,考虑用unlink进行堆块的合并,然后获得重叠的堆块进行攻击。程序的环境是glibc2.31,由于glibc2.31中会加入一个如下的检查
1 | if (__glibc_unlikely (chunksize(p) != prevsize)) |
原先的unlink consolidate就不再有效,因此需要额外的想法
首先这题没有开pie,也就是说我们是可以知道bss段的地址的
构造fake_chunk将大小设置好
通过程序的分配功能将fake_chunk分配到程序中,将地址写在bss段上再释放,由于程序释放时不会清空地址,所以fakechunk的地址会一直保存在bss段,令这个地址为addr(这个地址我们时知道的)。
将fake_chunk的fd设置为addr-0x18,将fake_chunk的bk设置成addr-0x10,用于绕过检查
1 | mchunkptr fd = p->fd; |
EXP
1 | from pwn import * |