学习资料:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/fastbin_attack/
https://www.anquanke.com/post/id/85357
之前稍微了解了一波Use After Free ,运用了fastbin,这次继续学一下fastbin的其他攻击方式,希望能学会吧
简单的介绍如下,图片来自CTFWIKI
Use After Free还是要派上用场的,不错欸
其实Fastbin Attack最精髓的地方就是每一块在fastbin中的堆被释放以后会放在一个链表中,而且free之后,size的prev_inuse标志位不会被清空哦
下面开始学(zhao)习(nue)啦
1.Fastbin Double Free
字面意思就是chunk可以多次释放
看一下是个什么鬼
int main(void) { void *chunk1,*chunk2,*chunk3; chunk1=malloc(0x10); chunk2=malloc(0x10); free(chunk1); free(chunk2); free(chunk1); return 0; }哇,连续释放两次chunk1,不会报错么,继续执行下去了,原因就是指针main_arena,这个就要涉及到arena的管理了,和线程个数有关
主线程使用main_arena,看一下main_arena的变化过程吧,如下
emmmm,不细说了吧,看得懂,主要就是利用了main_arena的检测机制,悄悄的漏过去了
注意因为 chunk1 被再次释放因此其 fd 值不再为 0 而是指向 chunk2,这时如果我们可以控制 chunk1 的内容,便可以写入其 fd 指针从而实现在我们想要的任意地址分配 fastbin 块,能改就出事啦,基本就是这么个操作
看一个具体的操作
typedef struct _chunk { long long pre_size; long long size; long long fd; long long bk; } CHUNK,*PCHUNK; CHUNK bss_chunk; int main(void) { void *chunk1,*chunk2,*chunk3; void *chunk_a,*chunk_b; bss_chunk.size=0x21; chunk1=malloc(0x10); chunk2=malloc(0x10); free(chunk1); free(chunk2); free(chunk1); chunk_a=malloc(0x10); *(long long *)chunk_a=&bss_chunk; malloc(0x10); malloc(0x10); chunk_b=malloc(0x10); printf("%p",chunk_b); return 0; }用pwndbg动态调试一波
我们先执行两个chunk的malloc
第一次释放chunk1和chunk2之后,chunk2的fd指向chunk1,但chunk1的bk不指向chunk2,也侧面验证了fastbin是单链表
然后第二次free chunk1
你看,我们躲避main_arena的检查,double free之后,改变fastbin单链表里的指针
接下来malloc给chunk_a原先chunk1的堆空间,然后赋给了它bss字段0x601080
然后两次malloc不变,先是分配chunk2,然后再次分配chunk1,接着再分配chunk_b时,chunk_b的地址就变为了0x601080
那我们就成功修改了指向的堆,并能输出数据
理完之后,感觉有点强行的意思,想试试看use after free的操作能不能直接输出bss字段
改后的代码如下
typedef struct _chunk { long long pre_size; long long size; long long fd; long long bk; } CHUNK,*PCHUNK; CHUNK bss_chunk; int main(void) { void *chunk1,*chunk2,*chunk3; void *chunk_a,*chunk_b; bss_chunk.size=0x21; chunk1=malloc(0x10); chunk2=malloc(0x10); free(chunk1); free(chunk2); //free(chunk1); malloc(0x10); chunk_a=malloc(0x10); *(long long *)chunk_a=&bss_chunk; chunk_b=malloc(0x10); printf("%p",chunk_b); return 0; }然后我们两次malloc,两次free,再两次malloc之后,可以看到,chunk1的fd又指向了bss字段
继续执行,按照原先的猜想应该还是可以输出0x601090,但是结果如下
就很迷,然后我们其实犯了个很白痴的问题,malloc之后修改堆的fd,bk也没啥用了,因为已经从链表里卸下来了,那就继续新开辟一个堆,那么问题又来了,那最后输出的不应该是0x602040
我们最后malloc之后,的确可以看到chunk_b的地址的确是0x602040
emmmm,最后知道地址指向的应该是数据段才对,要把16个字节的头部去掉,所以就是0x602050
2.House Of Spirit
上面一种方法chunk是真的,但被我们重复利用,现在更进一步,伪造一个chunk,不知道和frame stacking的原理相差大不大,下图来自CTFWIKI
哇,这一顿操作看上去容易,其实感觉不简单啊,光看原因感觉不是很友好,就去网上找了几个场景
你看现在我们妖王目标区域写数据怎么办呢,我们可以把可控区域伪造成fastbin,然后覆盖堆指针指向他们,然后释放掉,等再次调用他们的时候往目标区域写入数据,这样容易懂多了
场景搞定了,我们来看一下上面那些机制为什么要绕过
1.ISMMAP:mmap标志位不能被置上,否则会直接调用munmap_chunk函数去释放堆块
2.对齐:对齐就对齐吧,好像不对齐的确不靠谱
3.size:fastbin是一个单链表结构,遵循FIFO的规则,32位系统中fastbin的大小是在16~64字节之间,64位是在32~128字节之间,超过的话,就不会释放到fastbin里面了
4.next chunk:下一个堆块的大小,要大于2*SIZE_ZE小于system_mem,否则会报invalid next size的错误
例题:湘湖 note
试着做做看吧,我也不知道做不做得出
大概是这么个东西
比较奇怪的是输入5、6都会退出,也不知道为啥,分析一下功能
New_note:创建note,最多创建3个,规定了大小
Show_note:就是Show
Edit_note:
好累…………先咕咕咕了