文章总结: 本文详尽解析了NewstarCTF2025第三周Web赛题,涵盖五道典型题目。涉及知识点包括Git与DS_Store信息泄露利用、PHP伪协议结合双重URL编码绕过过滤、SSRF漏洞利用本地文件读取、文件上传配合短标签与通配符绕过实现RCE,以及FlaskSSTI沙箱逃逸调用特定函数。文章通过复现解题步骤,展示了信息搜集、绕过技巧及模板注入的实战应用,适合CTF选手学习Web安全攻防技巧。
综合评分: 90
文章分类: CTF,WEB安全,实战经验
NewstarCTF2025-Week3-Web全解_wp
原创
M0t0y
M0t0y
moonbeautSec
2026年3月15日 07:37
北京
快来打基础,高质题目
WEB
小E的秘密计划
解题过程
打开环境,题目提示备份信息,尝试常用的信息泄露没有找到
扫一下目录看一下
发现一个www.zip文件,访问下载下来
image-20251019223010506
发现 public-555edc76-9621-4997-86b9-01483a50293e/.git/:这是一个 Git 版本库目录,通常包含完整的项目提交历史、可能的历史文件
login.php:潜在的登录入口文件,可能含有 flag 或密码逻辑。
index.html:网站主页。
这个文件夹下有.git文件,可能存在git泄露
image-20251019223542952
login也提示了说在git里找找
有 3 个主要提交(hash 与提交信息):
1389b4798a80... — 初始化
5f8ecc03aee0... — 新增提示
5fef682d7ece... — 删除提示
有一次分支操作/临时提交(日志里有一条 测试,这个branch会删),该提交的对象仍在 .git 中但不在 HEAD(也就是某些文件存在于被删除的分支 / 历史中)
按历史对象查到了一个被删除但仍在对象库的 user.php。
用命令 git rev-list --all``git log --pretty=fuller -p – git ls-tree -r <tree> – git cat-file -p <blob>
定位到包含 user.php 的提交(来自 reflog 中的历史 commit):
历史中的一个临时 commit:353b98f7c2fe77a5a426bf73576f5113820c4669(提交信息含“测试,这个branch会删”)
该 commit 的 tree 列表显示: index.html login.php user.php
恢复到手的 user.php 内容(已从 git blob 抽取) user.php 的内容如下(原样):
php <?php function getUserData() {
return [
'username' => 'admin',
'password' => 'f75cc3eb-21e0-4713-9c30-998a8edb13de'
]; }
向这个login.php页面发一个POST请求,得到sercet页面
访问这个页面
没有flag,想到题目中说的MAC电脑自动生成的文件,之前有了解过DS_Stroe泄露
这里扫站看一下,发现果然是DS_Store
将这个文件下载下来
用工具查看一下这个文件
得到下一个路径,访问得到flag
flag
flag{af141c39-be4a-477d-a36a-9a7709dcb7a3}
ez-chain
解题过程
image-20251019224938802
后端对路径做了字符串过滤(filter 函数),但只过滤了一层**; **如果经过两次 URL 编码,再配合 php:// 伪协议,就能绕过并读取文件内容
题目还会对返回结果进行base64解码,对我们传入的参数做一次URL解码,然后检查
image-20251019225024958
所以用filter协议,不能用base64编码返回结果,url解码检查这里可以再编码一次解决
构造payload
?file=php://filter/read=string.rot13/resource=/flag
进行两次URL编码
得到rot13编码的flag,解码得到flag
flag
flag{7cb3f42a-99c9-49ba-960b-ae984ab30187}
mygo!!!
解题过程
打开解题环境,点击flag没有反应
打开开发者工具看一下网络
发现这里访问的调用是利用里proxy协议来读取的本地的文件
这里尝试读取一下本地的文件,读flag.php得到以下内容
这个页面用GET方法获取一个soyorin的参数,这里利用参数用file协议读取flag
4
mirror_gate
解题过程
打开题目页面,查看源码可以发现提示信息
客户端有一些前端限制(MAX_FILE_SIZE = 5MB、accept="*/*"、前端 JS 控制提交按钮等)。
HTML 最底部注释:<!-- flag is in flag.php --> 与 <!-- HINT: c29tZXRoaW5nX2lzX2luXy91cGxvYWRzLw== -->
这条 Base64 解码后是:something_is_in_/uploads/。
页面不允许很多的东西上传
用yakit抓包尝试伪造一句话木马为gif上传失败
这里rce应该是不行的,结合两条提示信息,这里应该是上传文件来读取flag.php文件
这里还会对文件内容做检查
不允许出现命令和关键信息
这里用tac以及通配符来绕过
<?=`tac /fl*`?>
构造文件修改后缀为webp上传
成功上传访问这个文件成功读取到flag
who’ssti
解题过程
阅读下给的源码
是一个 Flask + Jinja2 SSTI(服务器端模板注入)的 题,考点是如何在被限制的环境下通过 SSTI 调用 Python 内置函数以触发特定函数调用
看题目需要被调用的五个函数
随机目标函数列表 题目中定义了:
func_List = ["get_close_matches", "dedent", "fmean",
"listdir", "search", "randint", "load", "sum",
"findall", "mean", "choice"]
need_List = random.sample(func_List, 5)
need_List = dict.fromkeys(need_List, 0)
即每次启动后,
need_List 会随机包含 5 个函数名(例如 ["listdir", "choice", "search", "sum", "findall"])。 程序会在 trace_calls 时检测: python if func_name in need_List: need_List[func_name] = 1 当 所有函数都被调用过一次 时: python if all(need_List.values()): BoleanFlag = True 即可获得 flag
代码中: python submit = request.form.get('submit') if submit: sys.settrace(trace_calls) print(render_template_string(submit)) sys.settrace(None)
用户输入的 submit 直接进入 render_template_string(submit),即 未经过滤的模板字符串渲染
利用 Jinja2 SSTI 调用 Python 函数 在 Jinja2 中,你可以通过对象链访问到 Python 内置函数,
{{ ''.__class__.__mro__[1].__subclasses__() }}
但这里不需要执行命令,只要调用特定函数即可。
{{ lipsum.__globals__.__builtins__.__import__('random').choice([1,2,3]) }}
{{ lipsum.__globals__.__builtins__.__import__('textwrap').dedent('x') }}
{{ lipsum.__globals__.__builtins__.__import__('statistics').mean([1,2,3]) }}
{{ lipsum.__globals__.__builtins__.__import__('json').loads('\"x\"') }}
{{ lipsum.__globals__.__builtins__.__import__('re').search('a','aaa') }}
成功利用五个函数的ssti后,直接返回flag
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:moonbeautSec M0t0y
M0t0y《NewstarCTF2025-Week3-Web全解_wp》