【比赛】CTFSHOW-2026元旦跨年欢乐赛-CS2026
- 一次乱七八糟的(指我做的)比赛复盘,有些能力之外就暂时不复盘了
- 官方wp指路:https://ctf-show.feishu.cn/wiki/RZQ8whrVMib7xnkTerec5axOno2
- 点击跳转ak大佬wp预览
热身签到
分类:CTF部分 | 分值:100
题目描述
元旦时,我二舅姥爷给我出的密码题
54515552545455515456547055555566545654495548554855575370515051485150515453705555545755525456537054515551515051485150515450495568 |
- 我的解法
- 注意$1后面有空格
- zs1994:
每两位 1 组分隔, 发现每个两位数都落在 48~70 的区间
例如: 54 51 55 52 …
正好是 ASCII 里的可打印字符范围
- 官方:
#!/usr/bin/env python3 |
- 其实感觉cyberchef能解决的也不咋用存脚本(?
HappySong
- 手打
- 我只能说以后碰到这种题目就把这个脚本扔ai当参考了。。除非后面深造编程可以学一下
- 官方脚本:
#!/usr/bin/env python3 |
Happy2026
分类:CTF部分 | 分值:100
题目描述
奇怪的2026
|
绕过 if 条件判断,利用 include 函数执行任意代码。
$year == 2026 && $year !== 2026 && is_numeric($year) |
这里利用了 PHP 的类型比较特性:
$year == 2026:这是一个弱类型比较。如果$year是字符串'2026',PHP 会将其转换为数字进行比较,结果为true。$year !== 2026:这是一个强类型比较(全等比较)。它要求值和类型都相等。如果$year是字符串'2026',而右边是整数2026,类型不同,结果为true(即不全等)。is_numeric($year):检测变量是否为数字或数字字符串。字符串'2026'满足此条件。
结论:我们需要传入 year=2026(字符串形式),即可同时满足这三个条件。
满足条件后,代码执行:
include $happy[$new[$year]]; |
这里涉及到数组的嵌套引用。我们已知 $year 的值为 '2026',所以代码实际上执行的是:
include $happy[$new['2026']]; |
我们需要通过 GET 参数构造 $new 和 $happy 数组:
- 我们需要构造
$new数组,使得$new['2026']有一个具体的值,假设为'0'。即?new[2026]=0。 - 此时代码变为
include $happy['0'];。 - 我们需要构造
$happy数组,使得$happy['0']包含我们要执行的恶意 Payload。即?happy[0]=Payload。
include 函数通常用于包含文件,但配合 PHP 伪协议(Wrapper),我们可以执行任意代码。
常用的 Payload 形式是利用 data:// 协议:
data://text/plain,<?php system('命令'); ?> |
将这个 Payload 赋值给 $happy['0'],最终构成的执行语句就是:
include "data://text/plain,<?php system('命令'); ?>"; |
这会直接执行 PHP 代码。
- ai
- 在 PHP 伪协议
data://的用法中,text和plain分别代表了数据的 MIME 类型(MIME Type)。- text:表明该资源是文本性质的,而不是图像、视频或二进制程序。
- 子类表示数据的具体格式,
plain表明它是纯文本。
- 如果是
text/html,浏览器会将其解析为网页。- 如果是
text/plain,则视为没有任何格式标签的普通文字。- 这个构造中,虽然我们写入的是 PHP 代码,但为了让 PHP 解释器能够通过伪协议顺利读取这些“字符”,我们通常声明它为纯文本。
- 当 PHP 的文件包含函数(如
include()或require())处理这个协议时,它会:发现是data://,无视 MIME 类型的限制,直接提取逗号,之后的内容当作 PHP 脚本进行解析并执行- 常见的变体:为了绕过 WAF(防火墙)对关键词的拦截
| 形式 | 结构 |
|---|---|
| 明文形式 | data://text/plain,<?php phpinfo();?> |
| Base64形式 | data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+ |
注意:使用此类 Payload 的前提是服务器配置中
allow_url_fopen和allow_url_include均已开启(均为 On)。
综上所述,我们需要通过 GET 请求传递以下参数:
year=2026new[2026]=0happy[0]=data://text/plain,<?php system('cat flag.php'); ?>
?year=2026&new[2026]=0&happy[0]=data://text/plain,<?php system('ls -al'); ?> |
- ai
你在 Hackbar 中执行 cat flag.php 看不到回显,是因为 flag.php 里的内容是 PHP 代码(如 <?php $flag=… )。浏览器会把它当成无效的 HTML 标签隐藏起来,或者 PHP 会尝试执行它而不是显示它。
在 Payload 中使用 Base64 编码来读取文件内容,这样浏览器就能显示编码后的字符串了。
修改后的 Payload:
?year=2026&new[2026]=0&happy[0]=data://text/plain,<?php system('cat flag.php | base64'); ?> |
ctfshow{b775436b-81ba-4295-a317-3bbdf7544dfb}
- 官方:
import requests |
- 复现遇到证书问题:
response = requests.get(url=url+payload, verify=False)- 加上
verify=False就好了
- 嘶好奇怪官方的加了base64编码不仅回显了还是正常显示而不是base64显示
- 其实是我自己瞎改改坏了要写在``里面啊不然就是和base64按位与输出了
更适配的方法
- 大佬:
/?year=2026&new[2026]=a&happy[a]=php://filter/read=convert.base64-encode/resource=flag.php |
| 特性 | 写法 A: php://filter |
写法 B: data:// |
|---|---|---|
| 核心原理 | 将已有的文件内容“流经”过滤器处理 | 将用户输入的字符串当作 PHP 代码执行 |
| 利用场景 | 读取服务器上 存在 的文件源码 | 直接执行 任意系统命令 |
| Payload 示例 | .../resource=flag.php |
...,<?php system('ls'); ?> |
| 依赖配置 | 无特殊要求 (默认开启) | 需 allow_url_include = On |
- 所以这个方法更适配该题目
happyEmoji
分类:CTF部分 | 分值:300
题目描述
这天小狐狸和一个很好看的姑娘成了好朋友,他很开心。于是他用她发给他的表情写了一段话,分享给更多的朋友,现在大家都开心了。 1. 每一串是一个字母 2. 有眼睛就能做
- 官方脚本:
import PIL.Image as Image , numpy as np ,libnum,base64 |
SafePIN
分类:CTF部分 | 分值:200
题目描述
绝对安全的身份认证系统
- 官方脚本改了下(解决证书问题
#!/usr/bin/env python3 |
- 。。。真没招了我是菜狗
SafeLock
分类:CTF部分 | 分值:200
题目描述
绝对安全的智能锁,没有卡片开不了的
- BOOT 锁联网上线
- 开始初始化
- 使用出厂密钥和默认salt为123456 设置管理员卡
- 使用一次后就过期
- SALT更新为随机8位数字
- 主要攻击线路:
- 拉闸->迫使锁用电池->每次验证掉5%的电->电池掉光电->锁完全进入离线状态->恢复供电->开始初始化salt为123456->给自己刷管理员卡->开门禁系统
#!/usr/bin/env python3 |
- 看不懂啊抓包抓了半天也看不懂怎么分析的。。。
SafePassword
分类:CTF部分 | 分值:100
题目描述
- 根据情报,J国近年来对我国进行了持续的渗透攻击,我方技术人员经过溯源,发现某个可疑网址。 2. 该网址疑似为J国的情报组织任务分配中心,但是我方并没有拿到登陆口令,无法继续深入。 3. 已经确认嫌疑账号用户名为jcenter,此人2025年加入该组织,登陆口令未知。
$accessKey = $_POST['access_key'] ?? ''; |
这里使用了
==进行比较。在 PHP 中,如果一个字符串和一个整数进行比较,字符串会被尝试转换为数字。如果md5($accessKey)计算出的哈希值字符串以数字开头,PHP 会提取开头的数字部分与$expected进行比较。
function getExpectedHash($channelKey) |
function buildExpectedHash($channelKey): string |
关键逻辑链:
- 如果我们传入的
channel_key长度 大于等于 64,buildExpectedHash会进入else分支,抛出LENGTH_ERROR。 - 该异常立即被同一个函数内的
catch块捕获。 catch块抛出一个新的异常,错误码为VERIFY_FAILED。- 根据 [index.php:13](file:///a:/traeworkingplace/index.php#L13),
const VERIFY_FAILED = 2025;。
接着,异常回到 getExpectedHash 的 catch 块,调用 pickErrorCode:
function pickErrorCode(Throwable $e): int |
结论:
只要 channel_key 的长度超过 64 个字符,getExpectedHash($channelKey) 就会返回整数 2025。
3. 漏洞利用 (Exploit)
此时验证逻辑变为:
if (md5($accessKey) == 2025) { ... } |
因此,我们需要爆破一个字符串,其 MD5 值满足正则 ^2025[a-f]...。
import hashlib |
访问密钥nhll
保留码长度超过 64 位的字符,用于触发后端的长度异常:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
- 保留码 输入超长字符串,迫使服务器抛出异常并返回固定的错误码 2025 。
- 访问密钥 输入 434048 ,其 MD5 值以 2025 开头,利用 PHP 的弱类型比较( == )使验证成功。
ctfshow{9e20d8bc-58b4-4957-b204-d31db1ace052}
AWDP攻击题目
- 暂时只看我比赛尝试过的
SafeViewer
分类:AWDP攻击题目 | 分值:100
题目描述
SafeViewer SafeRender SafeAdmin 共同使用本题的环境
这3个题目的flag前面 都会有明显的说明 是哪个题目的flag
环境变量中flag是占位,和题目无关
原理:
利用了后端服务 render 存在的 Directory Traversal (目录遍历) 漏洞。
漏洞点位于 app.py 的 _safe_join 函数,它没有正确过滤路径中的 ../,导致攻击者可以访问服务器上的任意文件。
* 该接口对应后端 app.py 中的 internal_file 函数。
- 构造 Payload
- 我们想要读取后端源代码
/app/app.py。 - 正常请求:
path=/app(如果允许) 或path=templates。 - 恶意请求:利用
../跳转到根目录,再访问/app/app.py。 - URL:
https://<URL>/api/v1/artifacts?path=/app&filename=app.py - 注意:这里其实直接使用了绝对路径
/app,因为_safe_join只是简单拼接,如果path以/开头
- 我们想要读取后端源代码
https://566f348e-d5f6-4f91-b986-2992c57abbcc.challenge.ctf.show/api/v1/artifacts?path=/app&filename=app.py |
SafeCar
分类:AWDP攻击题目 | 分值:300
题目描述
追踪JCenter,送他回老家。
- 没做出来
AWDP防御题目
- AWDP防御题目代码实力不够比赛全ai的就只看看思路了(好歹会给ai多点提示词bushi
- 我勒个就一个看得懂,后面基础上来了再学吧呜呜呜
SafeCalc
- 代码审计
|
关键改动点:
eval("\$out=($expr);");→safe_calc($expr)safe_calc():字符白名单过滤 + 词法分析 + RPN 求值- 错误统一走
fail()输出 JSON,保证前端交互不崩
- ai解法分析:
|
- 话说这种其实可以存脚本【取代eval函数接受post参数】






















