介绍一种在多线程堆题中利用堆溢出达成任意地址分配的手法。
我们知道,一个进程的主线程的堆管理main_arena在libc中,分配的chunk在堆段中。那么子线程的arena和堆块都在哪里呢?
这一大串在libc前面一点点的anon就是给子线程留的arena和堆空间。arena和tcache管理chunk在这个内存段的最上面。(下面那个紫色的800000大小的段好像不是,没见过他被分配。)紫色的用完了就从白色哪里扩展。那么当图中所有的紫色和白色都用完了应该用哪里的内存地址了呢?
程序会用mmap或者其他的什么办法再搞来一段内存空间,然后把蓝色箭头指向的段(刚刚提到的带有arena的那个堆段)上面一些地方的地址分配给他们。这时我们可以发现,只要我们把这次分配的空间再用完,然后在最后一个堆块上实行堆溢出,溢出的部分就能覆盖到子线程的arena。控制了arena就好说了,在fastbin上随便写写就能任意地址分配了。
回到题目
例题:N12018 shopping
题目只有一个malloc功能,malloc完了以后可以在堆块上写点东西也可以不写,没有free没有show没有edit,单纯看下来挺难做的。Read()函数有一个不易察觉的我没发现的洞,只要一次读入数据没有把nbytes用完,那么就可以再读入nbytes,达成堆溢出。这样就可以通过上述手法,申请大量堆块,通过堆溢出覆盖fastbin。达成任意写之后在bss上画一个system就能getshell了,很方便很仁慈。