静态分析
首先查看保护,全开,64位动态链接成簇,stripped.
用IDA查看程序,函数逻辑如下,主要有4个功能
allocate
可以看到该功能主要负责分配堆块以及记录堆块信息。
fill
该功能先读取索引,然后判断堆块第一位如果是1,那么就输入size,content.这里可以向堆块输入任意长度,造成溢出
Free
dump
利用分析
想要利用,首先是要泄露libc地址。这里采用的是泄露unsortbin链表的地址,先申请四个堆块如图,其中最后一个chunk 3的作用是和top chunk隔离(申请0x68的大小实际上就是0x70):

然后利用堆溢出,堆chunk 0编辑,使chunk 0溢出内容将chunk1 的size修改为0xe1(包含pre_size),即chunk1+chunk2大小的和,然后pre占用位为1,这时释放1,相当于释放了一个size为0xe0的chunk,会被放入unsortbin链表中。(图中可以看到有tcache,一种内存管理机制,代码逻辑位于malloc
函数和free
函数中,具有较高的优先级。属于一种缓存机制,它为每一个线程创建了一个缓存,从而实现了不加锁的堆块分配算法,起到了性能提升的作用。)
这时再申请一个0x70的堆块,便会从unsortbin中分割一个0x70的大小的堆块出来,然后剩下的继续连入unsortbin中。
但需要注意的是,分割之前unsortbin中的那个0xe0大小的堆块是我们通过溢出伪造的堆块,实际上是由一个0x70的(已释放堆块,在前)和一个0x70的(未释放堆块,在后)组成的。这时再申请一个0x70的堆块就会将前一部分已释放的那个堆块重新申请回来,那么后一个堆块就会被作为空闲堆块连入unsortbin中,但实际上这个堆块我们可控,我们可以将其内容输出,就会获得一个指向unsortbin的指针值,便泄露了libc地址。
然后将malloc_hook修改为onegadget,然后申请一个堆块就会完成getshell。
这部分的操作就是,只需要再盛情一个0x70的堆块chunk4,就会发现我们有两个堆块(chunk2和chunk4)同时指向同一个0x70的地址空间。这时我们只需释放chunk2,然后编辑chunk4便可修改fastbin的指针了。
这里都是跟的这篇博客走的,但是复现出现了tcache这样的状况。就顺着理解了一下题目的思路。
参考链接:https://www.bilibili.com/video/BV12v4y1o7DK?spm_id_from=333.337.search-card.all.click
知识点
main_arena
chunk空间的共用情况,也就是下一个的chunk的prev_size域给当前chunk当做数据域使用,这种情况只出现在malloc的大小为8的奇数倍的情况。
在正常情况下,当free掉一块大于max_fast的大小的chunk时,程序将会把他放至unsorted bins中,而由于unsorted是双向链表的结构,所以它有FD
和BK
两个指针,且当fastbin为空时,他的fd
和bk
指针将同时指向main_arena
中,一般也就是main_arena+88
的位置。
main_arena存储在libc.so.6文件的.data段,通过这个偏移我们就可以获取libc的基址。