经历一星期的musl源码审计,和拜读大神们的文章,进行个人的musl总结
1.数据结构
1.malloc_context
1 | struct malloc_context { |
2.meta_area
1 | struct meta_area { |
3.meta
1 | struct meta { |
4.group
1 | struct group { |
5.chunk
1 | struct chunk{ |
2.利用思路
在nontrivial_free函数中存在dequeue函数
1 | static inline void dequeue(struct meta **phead, struct meta *m) |
存在next指针和prev指针互写,且没有检查
free()–>nontrival_free()–>dequeue()
我们需要伪造chunk,甚至group,meta等等才能实现两个地址互写.
并且想要到达dequeue()函数,也要经过一系列检查.
free中调用的get_meta函数
1 | (/src/malloc/mallocng/meta.h, line 129) |
1.meta->mem == base : 检查meta的mem指针是否是原来通过group->meta找到自己的group,即检查双向闭合
2.index <= meta->last_idx : 检查idx的合法性
3.area->check == ctx.secret : 检查area的合法性
4.offset >= size_classes[meta->sizeclass]*index
5.offset < size_classes[meta->sizeclass]*(index+1) : 检查offset和chunk大小是否匹配
6.assert(offset <= meta->maplen*4096UL/UNIT - 1) : 检查offset是否越界
然后再看nontrivial_free
1 | static struct mapinfo nontrivial_free(struct meta *g, int i) |
这里要求mask+self == (2u<
(1) avail_mask 表示只有一个chunk 被使用 ,freed_mask=0,free这个chunk
(2) avail_mask=0, freed_mask 表示只有1个chunk没被释放,即当前这个chunk没释放,free这个chunk
tips: activate_group(ctx.active[sc])建议不要让这条语句执行,因为它在dequeue之后,相当于把next指针的区域链入active[]并且还要activate这个区域,但是这个区域一般是stdout_used是无法控制,来伪造成meta,所以很可能会报错. 所以为了避免执行,我们把sc改掉即sizeclass,使得ctx.active[sc]!=g,activate_new为0.
之后调用free_group
1 | static struct mapinfo free_group(struct meta *g) |
我们不能进入else分支,这样会再一次调用nontrivial_free,因此要使得maplen不为0
3.控制程序流
想控制musl题的程序流,一般都是打IO
IO_FILE
1 | struct _IO_FILE { |
IO_FILE结构体中有4个函数指针,一般利用stdin、
stdout、
stderr
exit()调用链
1 | _Noreturn void exit(int code) |
1 | void __stdio_exit(void) |
1 | static void close_file(FILE *f) |
在close_file函数中当 f->wpos != f->wbase 就会调用f->write函数
1.getshell
1.利用dequeue函数,将可控地址写到stdout_used(__stdout_FILE结构体链表头)中
2.再在FILE结构体头几字节写入”/bin/sh”
3.再修改write指针为system,
4.以及f->wpos != f->wbase
5.触发exit()
2.orw
maigic_gadget
1 | mov rsp, qword ptr [rdi + 0x30] ; jmp qword ptr [rdi + 0x38] |
1.利用dequeue函数,将可控地址写到stdout_used(__stdout_FILE结构体链表头)中
2.再rdi+0x30也就是FILE+0x30写入orw的首地址,在rdi+0x38(也是f->wbase)处写入ret
3.再在write指针处写入magic_gagdet
4.构造好orw链
5.触发exit()