首先,用pwntools检查一下,pwn checksec club。
pwntools
pwn checksec club
结果如上,保护基本都开了,这意味着要泄露地址,不能使用shellcode,可以改got表。
分析get_box函数,发现它会对分配的内存大小进行限制,每个至少相差0x10字节,所以不能用fastbin。
get_box
所以我们的思路就是想办法泄露地址信息,解决PIE。然后利用unsafe_unlink改写__free_hook的值为system函数的地址,然后free一段包含/bin/sh的内存。
unsafe_unlink
__free_hook
system
/bin/sh
最先发现了猜随机数的这个函数,这种类型的题目以前碰到过,如果你没有猜对,程序会将正确的结果返回给你。实际上在这种情况下libc里面的rand函数是可以预测的。规律如下
libc
rand
其中STATEi是int32_t类型。所以可以用
int32_t
来预测,当然,可能猜不准,多猜几次就是了。
seed其实被初始化为了它自己的地址,所以我们得到了seed的地址,也就得到了程序的加载地址。
seed
这个很容易,只要适当的free一个内存,它的fd和bk就指向了main_arena+88。下图是alloc(1, 128), alloc(2, 144), alloc(3, 160), destroy(2)后的堆。得到了main_arena的地址,也就可以算出libc的加载地址了。顺便说一句,作者给的libc就是ubuntu 16.04上面的libc。
fd
bk
main_arena+88
main_arena
给一个网址bcbK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6K6K9r3g2D9L8s2m8Z5K9i4y4Z5i4K6u0r3K9r3!0%4x3X3S2W2j5i4m8Q4x3V1k6T1L8r3!0T1i4K6u0r3L8h3q4K6N6r3g2J5i4K6u0r3N6h3&6K6j5h3k6W2i4K6g2X3N6h3&6D9K9h3&6C8i4K6u0W2j5H3`.`.我觉得这个github repository讲的很好,非常值得看。
网上的资料很多,主要说一下针对这个题的流程。
只有id为2,3的内存才能被释放。先构造出一块大的3内存,并保证它释放的时候不会被合并到Top Chunk。
然后把内存3释放掉,在堆中得到一个空洞。顺便把main_arena的地址泄露出来。
要注意到destroy_box函数除了free内存什么也没做,没有将指针改为NULL,也没有改变size和存在标志。也就是说,即使我们释放了3内存,依然可以使用它。
destroy_box
接着分配两个比较小的内存,但是也要比0x80大,不要落在fastbin里面。
内存1和内存2的大小加起来也比内存3小,所以会在内存3释放后留下的空洞中分配。注意一定要先分配内存1,再分配内存2,因为只有内存2能被free。现在的内存布局如下。
因为我们还有内存3的指针,所以可以任意修改内存1和内存2的值,可以伪造malloc_chunk。
malloc_chunk
到这里差不多就可以写代码了。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
netwind 好文