[护网杯 2018]easy_tornado
给了三个txt,flag.txt给出了flag文件,welcome.txt提示了render,hints.txt给出了摘要算法md5(cookie_secret+md5(filename))。并且观察url可以发现提交了两个参数分别为一个filename和一个filehash。既然这里给出了摘要算法,应该就是提交的filehash值算法。
这里要计算filehash值就要获取cookie_secret,根据welcome提示,应该是render模板注入(ssti),通过ssti获取cookie_secret再计算出filehash读取flag文件获取flag。注入点在一个错误提示中,当提交的filehash不正确时就会跳转到一个错误消息的url,其中有一个参数为msg,修改这个参数发现提交的值显示在页面中。提交msg={{1}}回显为1,尝试提交{{1+1}}发现被过滤了,但是{{2^2}}回显为0,说明确实存在ssti。但是如何获取cookie_secret还是不知道,看了一下wp发现时利用handler.settings进行读取,但是都没有说明为什么这样读取。我们利用这个变量可以获取到cookie_secret然后使用hints.txt中给出的算法即可计算出filehash读取flag文件。
Tornado templates support control statements and expressions. Control statements are surrounded by
{%
and%}
, e.g.{% if len(items) > 2 %}
. Expressions are surrounded by{{
and}}
, e.g.{{ items[0] }}
.
Python中从服务端模板注入到沙盒逃逸的源码探索 (一)一文对为什么利用handler.settings获取cookie_secret做出了部分解释,该文放出了部分tornado源码,我们可以在一下代码中看到有一个将self赋值给handler的操作
def get_template_namespace(self):
namespace = dict(
handler=self,
request=self.request,
current_user=self.current_user,
locale=self.locale,
_=self.locale.translate,
pgettext=self.locale.pgettext,
static_url=self.static_url,
xsrf_form_html=self.xsrf_form_html,
reverse_url=self.reverse_url
)
namespace.update(self.ui)
return namespace
这是RequestHandler类中的一个方法,也就是说这里将RequestHandler类本身赋值给了handler,因此handler.settings实际上就是RequestHandler.settings(self.settings),这一点在tornado文档中也有说明。
- Expressions can be any Python expression, including function calls. Template code is executed in a namespace that includes the following objects and functions. (Note that this list applies to templates rendered using
RequestHandler.render
andrender_string
. If you’re using thetornado.template
module directly outside of aRequestHandler
many of these entries are not present).escape
: alias fortornado.escape.xhtml_escape
xhtml_escape
: alias fortornado.escape.xhtml_escape
url_escape
: alias fortornado.escape.url_escape
json_encode
: alias fortornado.escape.json_encode
squeeze
: alias fortornado.escape.squeeze
linkify
: alias fortornado.escape.linkify
datetime
: the Pythondatetime
modulehandler
: the currentRequestHandler
objectrequest
: alias forhandler.request
current_user
: alias forhandler.current_user
locale
: alias forhandler.locale
_
: alias forhandler.locale.translate
static_url
: alias forhandler.static_url
xsrf_form_html
: alias forhandler.xsrf_form_html
reverse_url
: alias forApplication.reverse_url
- All entries from the
ui_methods
andui_modules
Application
settings- Any keyword arguments passed to
render
orrender_string
tornado提供了一些变量可以在模板中访问,因此我们可以利用handler来访问settings。
Tornado小记 -- 模板中的Handler一文对RequestHandler.settings做出了解释,RequestHandler.settings实际上是指向了self.application.settings,在tornado文档中也能看到这个说明。
RequestHandler.settings
An alias for
self.application.settings
.
在[tornado文档](https://www.tornadoweb.org/en/stable/guide/security.html#User authentication)此处能够看到
class MainHandler(BaseHandler):
@tornado.web.authenticated
def get(self):
name = tornado.escape.xhtml_escape(self.current_user)
self.write("Hello, " + name)
settings = {
"cookie_secret": "__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
"login_url": "/login",
}
application = tornado.web.Application([
(r"/", MainHandler),
(r"/login", LoginHandler),
], **settings)
在这里我们可以看到在cookie_secret是存在settings中的,settings又作为参数传入了Application构造函数,因此可以通过self.application.settings获取到cookie_secret。
既然这里最终是访问到self.application.settings获取cookie_secret,并且需要利用tornado提供的handler来访问,那么我们不仅可以通过handler.settings来获取,也可以使用handler.application.settings,这样实际上也是访问到self.application.settings。