Web
Signin
源代码:
|
|
/:主路由,返回 HI
/download:下载任意文件,但有一定过滤
/secret:判断 cookie 是 admin 还是其他,admin 则返回’The secret has been deleted!’,其他则返回’Forbidden!'
先在/download 下获取 secret.txt,因为过滤的不完全,我们可以通过./隔开../来获取
/download?filename=./.././../secret.txt
![]()
获取密钥为 Hell0_H@cker_Y0u_A3r_Sm@r7
接下来应该要伪造 admin 的 cookie,这里因为使用了 bottle 模块,这里是 bottle-0.13,根据更新已知其中存在 pickle 反序列化漏洞

原始的 cookie 的 name 值:!4SSvdzbD0UYv84Lnpmm1VLtPBddCrvhgQOLkNQbhjek=?gAWVGQAAAAAAAABdlCiMBG5hbWWUfZRoAYwFZ3Vlc3SUc2Uu
根据 get_cookie 函数:

确定了 cookie 的格式,其中有 pickle 反序列化
cookie 的格式:pickle 序列化后使用密钥进行 sha256 加密生成 base64 格式的签名,"!+{签名}+?+{数据}"
pickle 序列化构造代码:(需要在 linux 环境中运行)
|
|
其结果为 gASVKgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjA9scyAvID4gL2xzcy50eHSUhZRSlC4=
用已知的密钥进行 sha256 加密,得到签名:2jKMFEOWf73NL1W2eYJ8t0kfmB0+Hdpd4tXIPV8NHFQ=
将其构成 cookie:
Cookie: name="!2jKMFEOWf73NL1W2eYJ8t0kfmB0+Hdpd4tXIPV8NHFQ=?gASVKgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjA9scyAvID4gL2xzcy50eHSUhZRSlC4="
然后发包

利用/download 路由读取 ls.txt 文件
/download?filename=./.././../lss.txt

再读取 flag 文件
/download?filename=./.././../flag_dda2d465-af33-4c56-8cc9-fd4306867b70
得到 flag

flag{We1c0me_t0_XYCTF_2o25!The_secret_1s_L@men7XU_L0v3_u!}
ez_puzzle
连点 f12 卡出开发者工具
将源代码中的文件放在本地,在本地运行此网站
在 js 文件中找可疑点,不断尝试,发现有个 checkiffinish 函数,return imageIndexForPosition,盲猜 rangeindexposition 给图片随机定位跟这个变量有关,找 imageIndexForPosition 的引用,发现有赋值点,将赋值点改为下图的值

运行网站后略微修改一下拼图即可弹出 flag

flag{Y0u__aRe_a_mAsteR_of_PUzZL!!@!!~!}
Pwn
Ret2libc’s Revenge

-
题目主函数实现了类似 gets 函数功能,可以 stack 溢出
- 但是若果将垃圾数据全部填为相同的是不能实现溢出,不知为何
- 通过尝试发现垃圾数据填充为这样 payloda = b"\x11"*(0x200) + b"\x22"*0x20 + b"\x33"*0x3 + p64(target_addr)即可,关键应该在 0x210 左右
-
需要 leak 出 libc 基地址,但是发现交互没有回显,注意到 init 函数中,设置 stdout 为全缓冲,所以首先要填满缓冲区,重复执行 main 函数通过唯一的 puts 函数填满

- 程序设计过于简短,有且仅有一条 pop;ret,mov 也只有一条有效 gadget,如下,但目标是控制 rdi,通过 puts 得到 libc_base,只能通过 rsi 来间接控制,但是 rsi 又无法直接控制,经实践发现,先将 rsi 清零,然后通过 rbp 控制,注意到 magic 中是 esi,但由于没有 PIE,elf 文件相关地址都是 4 字节,可以控制,寻找到 0x400490 上放着标准输入地址,通过上述四条 gadget 配合可以控制 rdi 为 libc 相关地址,payload 如下:
|
|
|
|
|
|
|
|
-
输出缓冲区大小是
01:0008│ 0x4056a8 ◂— 0x411,加上 leak 的地址,大概循环 49 次左右,可以填满溢出 -
最后本地不能 system,参数正确,stack 对齐,执行到 system,但确实 getshell 失败,没有细调,因此选择 orw
-
这题打本地和打远程差的比较多
- 本地只需要 49 次循环即可填满,但是远程要 200 次,而且是小概率填满溢出,由于没有回显,只能一次一次尝试,同时需要使用 sleep 函数,而且循环次数不能过大,如 300 次,会出现不知名错误,导致直接程序崩掉
- orw 的话 write 泄露的数据长度需要 0x411 往上,最开始尝试只 write 0x100 长度,发现拿不到 flag,意识到后改成 0x500,只要上面能填满缓冲区得到 libc_base 一次就可以拿到 flag
- 远程 exp 和本地 exp 不同:
- 远程的脚本循环必须要 150 次往上,但是本地 150 次程序就崩溃了,同时也不需要 sleep,需要改掉循环次数
- 远程 write 必须要 0x411 往上,本地没有要求
远程 exp 如下:
|
|
明日方舟寻访模拟器
- 溢出有限,刚好可以控制一参,使用代码段中 system 方可绕过栈对齐问题
exp:
|
|
girlfriend
- 记不清了
Exp:
|
|
Nailong
- 爆破 rbp 地址
- stack 上关键数据与 rbp 的偏移固定,但是与 stack_base 偏移不固定
exp:
|
|
EZ3.0
- 异架构-mips,利用 gadget 控制 a0,system 即可
|
|
Crypto
Division
MT19937 随机,这里在选项一中全部除 1,得到 624 个随机数,将其转化为整数型后开始预测输出结果
终于当个人了
|
|

结果,XYCTF{d63a90be-a59c-4527-a115-3eba4eb63d4a}
Complex_signin
明文 m 是复数,解出它的实部和虚部就能解出 flag
设 m=a+bi,则加密式子为
其中 e=3,这是个很小很小的公钥,很不正常(bushi), 能直接手算出来
设 ,则加密式子变为
根据题目中快速幂的实现代码,可以看到复数取整数模时,实部和虚部分开分别取模
所以就可以得到一个方程组
已知 c 的实部和虚部,m 的实部和虚部的高位,两个未知数,两个式子,这其实是二元 CopperSmith
从网上搜一个二元 CopperSmith 脚本(https://unborracho.github.io/2023/04/03/coppersmith%E4%BA%8C%E5%85%83/index.html)
写脚本解出即可
|
|
XYCTF{Welcome_to_XYCTF_Now_let_us_together_play_Crypto_challenge}
Re
WARMUP
vbs 逆向,文本打开。直接 python print,打出来有点抽象,大概就是一个标准 rc4。
|
|
题目要求 md5:flag{We1c0me_t0_XYCTF_2025_reverse_ch@lleng3_by_th3_w@y_p3cd0wn’s_chall_is_r3@lly_gr3@t_&_fuN!}
XYCTF{5f9f46c147645dd1e2c8044325d4f93c}
ezVM
长度 32,func 里面是用 AVX2 指令集的汇编,就是一个比较函数,重点看 sub_403935


特殊的 vm,a1 有 got 表赋值了很多函数,程序通过偏移定位处理函数
输入改变一个字符后会影响八位密文,应该是八字节一组的加密,tea 也有可能 有固定的单字节加密逻辑 里面有一部分混淆,不用看,可以尝试对输入下读入断点看逻辑
逻辑应该在 sub_403935 里面的 sub_404F90


下断点一直跟踪到这个地方发现 rsi 赋值给 rdi(两次赋值,一次 16 个),下一步是回溯看 rsi 的值哪来的
rsi 不是你输入的 flag ?
rsi 是加密后的数据
没事,一个东西
啊我草这题怎么这么坏

dragon
bc 文件,需要先配一下 clang 编译器
![]()

这里的输入校验,逻辑只有位运算


位运算这玩意好像逆不出来,它是相邻两个两个字节异或,于是直接爆破,v5 要每次循环要重置。由于返回的时候是取反,所以直接手动把密文异或 0xFFFFFFFFFFFFFFFF 再爆破:
|
|
flag{LLVM_1s_Fun_Ri9h7?}
Moon
ida 里可以看到这个 pyd 文件要用 Python3.11.x 导入:

导入后 help 查看模块信息,发现一个验证函数一个加密函数两个值 SEED 和 TARGET_HEX,加密看名字是异或,尝试再调用一次解密,结果真出来了:

flag{but_y0u_l00k3d_up_@t_th3_mOOn}
ezobf
32 位长度,去混淆以后大概是这样

中间有三处反调试,汇编为 call rax 的地方
这个应该还是混淆过的,要在去一下
0x2C, 0x11, 0x82, 0xCC, 0xDF, 0x91
lake
动态加载

这里复制了输入

第一部分是 switch 修改 flag

密文

第二段,前一个的低五位和后一个的高三位:

该死,差一点点
赛后:脚本差两行补上了
|
|
flag{L3@rn-ng_1n_0ld_sch00b_@nd_g3x_j0y}
Misc
XGCTF

题目任务是找到 dragonkeep 的博客。
首先,在“CTFshow”中找到 XGCTF,通过搜寻,发现 LamentXU 师傅出的题:

接下来,已知这道题是一道原题,我们需要找到原来的题目,借助 AI 神力:

我们得知这道题是 2024 年 CISCN 的原题。
接下来就是找到 dragonkeep 的博客了,他的域名是 dragonkeep 加上一个字母,后缀未知,直接采取脚本爆破,遍历所有的可能性域名,进行访问,返回访问成功的域名(代表该网站存在。)
|
|
虽然跑的时间有点长,好在是出来了:


访问 dragonkeeep.top,可以发现这就是 dragonkeep 的博客。

紧接着直接找到 CISCIN 题目的这一篇文章:

然而阅读一遍并没有发现 flag
最后打开 F12,在网页的前端代码中搜寻到 flag:

进行解 base64,得到 flag:
flag{1t_I3_t3E_s@Me_ChAl1eNge_aT_a1L_P1e@se_fOrg1ve_Me}
签个到吧
首先得到文本:

很显然这是 brainfuck 语言(题目也有提示,最小的,图灵完备。。。)
有必要补充一下 brainfuck 语法:
Brainfuck 编程语言 由 8 个命令组成:

我们可以知道,[]为一个循环体,
我们查看第一行部分:
+++++++++++++++++[<++++++>-+-+-+-]>[-]>++++++++++++[<+++++++++>-+-+-+-]
首先 > 表示指针位右移,
例如 0 0 0 0 0 0 0 0 → 0 0 0 0 0 0 0 0
然后 + 使得指针当前位加 1,有几个代表加了几次,那么在[之前,我们得到的结果是:
0 17 0 0 0 0 0 0
紧接着便进入循环体了,进入的第一步 < 将指针位左移到了第一位:

然后开始增加,增加 6 次后右移动一次。
因为后面没有位的移动了,之后的“-+-+-+-”实际上等价于“-”,实际上是为了减去第二位的数字,因为在之前,第二位是用来计数循环的次数的,当要继续输出时,要删除这一位。
那么,当循环结束后,可以得到:

这是第一个循环结束后的值,第一位是 f,也就是 flag 开头的第一个字母。
那么,为什么我们使用在线工具无法解析呢?
原因其一是因为没有输出,当循环体结束后,此时的指针指向的是第二位,但是这个位置是 0,因此要输出 f,需要将指针移动到第一位上,使用“<”再使用“.”进行输出。

接下里就好办了。。。
之后,进行了一个很小的循环体:<[-]>
它的作用是将指针移动到刚才的第一位上,并且清除数据。也就是说,当 <[-]> 运行完后,我们此时的数据又变回了:
0 0 0 0 0 0 0 0
既然如此,我们需要做的就是在这个数据被清除之前让它输出来:
在每个 <[-]> 循环体之前加上 <.试试:

然而是乱码。。
显然这里犯了一个错误,代码是顺序进行的,我们在其中进行了移动位置输出后,必须把原来的位置移动回去,这才能保证之后的代码不受影响。因此,正确的应该是:<.>
我们在每个“<[-]>”之前加上 <.> 即可:
处理后的文本:
|
|
在线网站解密得到 flag:

flag{W3lC0me_t0_XYCTF_2025_Enj07_1t!}
MADer 也要当 CTFer | 未解出 |

题目是一个 mkv 后缀的视频,奇怪的地方在显示时长有 5 小时多,但真正能播放的有效时长只有 12 秒。
需要分析常见的 mkv 隐写:
这里我使用了工具 MKVToolNix 分析了该 mkv 文件:

这是一段分析该文件的 log,只需要知道总结:
- 该 MKV 文件包含一个视频轨道(H.264 编码)、两个音频轨道(AAC 和 MP3 编码)以及一个字幕轨道(ASS 格式)。
- 视频分辨率为 1920x1080,时长约为 5 小时 50 分钟。
- 字幕使用了 ASS 格式,包含详细的样式定义。
- 文件的编码工具为 mkvmerge v9.5.0,创建时间为 2025 年 3 月 3 日。
那么我们就可以用到该文件夹的 mkvinfo.exe 来分析得到:
|
|


那么之后我们便可以用到:
|
|
如下:

提取得到三个文件 video,music1,music2
1.video 文件就是那可播放的 12 秒动画
2.music1 则是一段音频但是听不到声音:

3.music2 比较特别,在记事本打开有ASS(Advanced SubStation Alpha)格式 的字幕数据

思路:可能需要从字幕数据中找(也有可能上面的都不是对的方向)困了
曼波曼波曼波
得到一个 flag.png 和 smn.txt

flag.png 扫码得到的是 fake flag
而 smn.txt 明显的特征,需要我们反转文件内容:
|
|
反转后明显符合了 base64 编码,同时字符这么多,首先想到的是转换成图片
将得到的 base64 转换成图片得到:

随波逐流发现图片文件中隐藏 zip 包,foremost 出来得到 zip 并解压,得到 manbo 文件夹:

而 secret.txt 提到解压密码:

是 XYCTF2025,解压成功得到 xixi 文件夹,里面有着和 manbo 文件夹 easy.png 一样内容的图片 EASY.png


猜测是盲水印,但是这里要注意使用 python3 的

得到图片:

即 XYCTF{easy_yin_xie_dfbfuj877}
会飞的雷克萨斯
由抖音大数据和百度地图可知
四川省内江市资中县春岚北路
但是题目需要我们找出定位爆炸点的具体位置
flag{四川省内江市资中县春岚北路中铁城市中心内}
Greedymen

查看题目,共有 3 关卡,内容差不多。
我们需要在 1 到 50/100/200 的数组中不断选择数字,一旦我们选择了某个数字,那么该数字的真因数会全部被对方选择。
我们需要在指定的轮数内通过合理的选择,最终让我们的分数大于对方。
审视问题规则:
- 玩家选择一个数字,获得该数字的分数,对手则获得该数字所有未被选过的因数的分数。
- 一旦数字被任何一方选中,其他玩家不能再选。
- 每次选择后,计数器减 1,当计数器为 0 或无法选择时,游戏结束,剩余数字归对手。
为了赢得游戏,我们需要制定一个贪心策略,每次选择当前未被选过的数中,净收益(自身得分减去对手可能获得的因数得分)最大的数。这样能确保每一步都最大化当前的优势。
代码逻辑:
- 预计算真因数:对于每个数,预先计算其真因数(除自身外的因数),方便后续快速查找。
- 贪心选择:遍历所有未被选过的数,计算每个数的净收益(当前数减去对手将获得的真因数和),选择净收益最大的数。
- 更新集合:每次选择后更新玩家和对手的集合,确保因数不会被重复计算。
- 处理剩余数:游戏结束时,未被选择的数归对手所有。
同时,如果玩家选择了数字 6,对手会得到因数 1、2、3。这些因数必须被加入已选集合,否则之后玩家可能再次选择这些因数,但根据规则,任何被选过的数字都不能再被选,不论是被谁选的。
- 使用一个集合 chosen 来记录所有已被选中的数字,包括玩家和对手的。
- 每次玩家选择一个数字 num 后,将其加入 chosen,并检查其所有真因数,将未被选的因数也加入 chosen。
- 在计算每个候选数字的净收益时,需要排除那些已经被选中的因数,只计算未被选的真因数的和。
- 确保每次选择后,计数器减 1,直到计数器为 0 或没有可选数字为止。
这样处理可以确保一旦数字被任何一方选中,就不会再被重复选择,符合题目规则。
代码如下:
|
|
最终我们得到以下三组解:
level1:
![]()
level2:
![]()
level3:

依次输入后得到 flag:

flag{Greed, is……key of the life.}
sins | 未解出 |
附件下载:
|
|
- 程序提示用户输入一个表达式,用于“洗净罪恶”。
- 第一个 assert 语句确保用户输入的表达式只包含允许的字符(数字、运算符、括号等)。如果输入包含非法字符,程序会抛出异常并提示“invalid char”。
- 第二个 assert 语句确保输入的长度小于 16 个字符。如果输入过长,程序会抛出异常并提示“too long”。
允许的字符:
|
|
用户输入的表达式需要与 i_pow 函数的结果一致
-
这个函数用于计算虚数单位 i 的幂。根据数学规则,i 的幂会周期性地循环:
- i0=1
- i1=i
- i2=−1
- i3=−i
- 然后每 4 次循环重复一次。
-
函数通过取模运算 n % 4 来判断 i 的幂,并返回相应的字符串。
那么我们需要找到符合要求的表达式:
Lament Jail | 未解出 |
是一个 pyjail 类型的题目。
源代码:
|
|
代码功能分析:
- SimpleTCP 类:实现了加密的 TCP 通信,包括:AES 加密通信,RSA 密钥交换,密码验证,大文件传输功能
- 主函数 main():监听 13337 端口,要求密码"LetsLament"进行连接,接收用户上传的 Python 代码,在沙箱环境中执行代码并返回输出
安全限制
- 密码保护:必须使用密码"LetsLament"连接
- 审计钩子:执行的代码会被添加审计钩子,限制危险操作
|
|
我们需要做的是绕过这个审计钩子,来执行我们需要的代码
目前已知的题目提示:
- 主机上运行有能够让人们完全控制主机的服务(使用套接字进行远控)
- 主机上限制了我们远程代码的执行
- 主机上存在/bin/rf(可能算后门文件),可以从某个地方直接读取 flag。
首先第一步是连接服务器,服务器使用了 加密通信(服务器使用 AES 加密(AES.MODE_ECB),并且会在连接时进行 RSA 密钥交换) 和 密码验证(服务器要求客户端发送密码(password=‘LetsLament’)
流程如下:
服务器首先发送 {“is_encrypted”: true, “has_password”: true}。
然后等待客户端:
- 发送密码(LetsLament)。
- 发送 RSA 公钥(用于交换 AES 密钥)。
如果客户端不按照流程发送数据,服务器会直接断开连接
这里使用 pwntools 进行自动化连接:
先输入一个 cat flag 试试水:
|
|
有如下回显:

提示我们存在 pyjail,需要想办法绕过
服务器端接收到客户端发送的代码后,会将其与预定义的 waf 字符串拼接:
原代码:
|
|
通过将 waf 代码与客户端代码拼接,确保客户端代码在执行时会受到 audit_checker 的限制。客户端代码无法直接执行,必须通过 audit_checker 的检查才能运行。
那么 audit_checker 是什么:
原代码如下:
|
|
如果事件中不包含 id 字段,就会抛出 RuntimeError 异常,从而阻止某些操作的执行
问卷
填写问卷即可。。
flag{TH@NK_U!WE_H0P3_Y0U_H@VE_FU7!H@PPY_H@CKING!}