0.题目来源
写这篇博客的原因是因为BUU上的一道题,这题由于是从正式比赛中复现的,因此靶机的环境有些问题(flag的位置不一样)。
按照预期解,这题应该只是单纯普通简单的unsortedbin attack实现任意内存写改写大数,从而绕到后门函数。但是这题由于给的后门函数是执行 cat /home/pwn/flag 指令的,但是可以证实靶机的flag是位于根目录的,因此后门函数便无效了。
1.情景分析
假设一个程序没有开PIE保护,或是能够泄露程序基地址,且该程序的RELRO没全开。若其堆指针可控,那么我们就可以通过改写堆指针为got表上的地址,从而能够访问并改写got表。例如,改写free_got里面的值为system_plt,并事先让ptr指向 /bin/sh\x00 ,这样再执行free(*ptr)时实际执行的就是system(“/bin/sh”)了;或是能够改写puts,并且能够执行puts(“/bin/sh”)。
2.实例探究
题目是BUU上的EasyHeap,靶机是Ubuntu16。
先checksec:
发现PIE保护没开,且RELRO没开全。
漏洞存在于edit_heap函数,该函数对写入字符长度没有限制,因此会造成堆溢出。
从主函数可以看出当输入4869时,若全局变量magic大于0x1305,则可以执行后门函数。
这道题的预期解法应该是利用unsortedbin attack将magic改写为一个很大的数,从而执行后门函数。
代码如下:
1 | from pwn import * |
但是,很可惜的是,远程环境 /home/pwn/flag 并不存在。(甚至都找不到这个目录)
这样的话,常规做法就行不通了。那么,还有没有别的做法呢?
答案是肯定的。
我们知道,程序没开PIE保护,那么基地址就不会随机化;并且RELRO没开全,就允许我们修改got表。(由于程序不存在show函数,难以leak出libc基地址,因此不考虑攻击__malloc_hook。)
如果直接将fake_chunk构建在got表附近的话,在修改某个函数时会对其前面的函数got产生影响,因此,比较好的做法是在堆指针区(本题是heaparray)附近伪造一个堆块(即在bss段上伪造堆块),通过修改堆指针为free_got使得edit时能够只改写free_got的内容为system_plt,这样再执行free时就会执行system。
可以看出,heaparray上面就是magic。这样伪造堆块也就方便了。只要先用unsortedbin attack将magic修改为0x7f开头的一个大数,再通过一些偏移,就可以绕过检查机制,伪造一个0x7n大小的堆块。
最终可以在magic - 3偏移处伪造一个chunk头:
那么我们的目标就是通过栈溢出修改已释放的fastbin_chunk->fd,使fake_chunk进入fastbin,完成attack。之后再计算偏移修改第一个堆指针(为了不影响其他堆指针)为free_got地址即可实现改写free_got了。
这是实现后的内存布局:
可以看出已经修改成功了。
之后只要再delete掉一个内容是/bin/sh\x00的堆块就可以了。
exp如下:
1 | from pwn import * |
也成功get shell并获取了flag: