Contents
  1. 1. [护网杯 2018]easy_tornado

[护网杯 2018]easy_tornado

tornado模板注入。

[护网杯 2018]easy_tornado

打开题目

分别打开三个文件查看

flag.txt flag in /fllllllllllllag

Welcome.txt render

Hints.txt md5(cookie_secret+md5(filename))

百度一下render

tornado render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页,如果用户对render内容可控,不仅可以注入XSS代码,而且还可以通过{{}}`进行传递变量和执行简单的表达式。 由此可知:render是一个类似模板的东西,可以使用不同的参数来访问网页。Render是存在模板注入的。 hint.txt,给我们了一个计算公式:md5(cookie_secret+md5(filename)) 看来需要按照这个公式计算出对应正确的filehash,并且按照这种格式访问url,就可以得到flag。 那么问题来了,文件名知道,md5函数可以调用,这个cookie_secret怎么得到呢?这时候注意到我们还有一个线索没有使用:render,模板注入! 尝试直接把文件名改成fllllllllllllag,报错了。 ![](https://ae01.alicdn.com/kf/U0a8a3f428efb417c9056174aea3384abH.jpg) 看这个错误页面还有一个参数呢!把参数值随便修改一下,发现显示出来的内容也会随之变化: ![](https://ae01.alicdn.com/kf/U11df5b0f2bac44108646145f7e1e3326p.jpg) 可见页面返回的由msg的值决定,修改msg的值形成注入,我们可以由此获得环境变量 ![](https://ae01.alicdn.com/kf/U6a979d46532f43b389913ec2461fe6b7u.jpg) 由此得到cookie_secret 所以只需要计算出/fllllllllllllag的md5值即可

1
2
3
4
5
6
7
8
9
import hashlib
hash = hashlib.md5()
filename='/fllllllllllllag'
cookie_secret="29da21c4-2598-41f6-9c7b-462160a552f8"
hash.update(filename.encode('utf-8'))
s1=hash.hexdigest()
hash = hashlib.md5()
hash.update((cookie_secret+s1).encode('utf-8'))
print(hash.hexdigest())
![](https://ae01.alicdn.com/kf/U64c9e5ac40c04ef49d39f68a192c6062K.jpg) flag{f9b6276b-49ff-4b84-a58f-20e84d9fe362} 学习 **原理** tornado render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页,如果用户对render内容可控,不仅可以注入XSS代码,而且还可以通过`{{}}进行传递变量和执行简单的表达式。
简单的理解例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
class LoginHandler(BaseHandler):
def get(self):
'''
当用户访登录的时候我们就得给他写cookie了,但是这里没有写在哪里写了呢?
在哪里呢?之前写的Handler都是继承的RequestHandler,这次继承的是BaseHandler是自己写的Handler
继承自己的类,在类了加扩展initialize! 在这里我们可以在这里做获取用户cookie或者写cookie都可以在这里做
'''
'''
我们知道LoginHandler对象就是self,我们可不可以self.set_cookie()可不可以self.get_cookie()
'''
\# self.set_cookie()
\# self.get_cookie()
self.render('login.html', **{'status': ''})
def login(request):
\#获取用户输入
login_form = AccountForm.LoginForm(request.POST)
if request.method == 'POST':
\#判断用户输入是否合法
if login_form.is_valid():#如果用户输入是合法的
username = request.POST.get('username')
password = request.POST.get('password')
if models.UserInfo.objects.get(username=username) and models.UserInfo.objects.get(username=username).password == password:
request.session['auth_user'] = username
return redirect('/index/')
else:
return render(request,'account/login.html',{'model': login_form,'backend_autherror':'用户名或密码错误'})
else:
error_msg = login_form.errors.as_data()
return render(request,'account/login.html',{'model': login_form,'errors':error_msg})
\# 如果登录成功,写入session,跳转index
return render(request, 'account/login.html', {'model': login_form}

由上面可知:render是一个类似模板的东西,可以使用不同的参数来访问网页
在tornado模板中,存在一些可以访问的快速对象,例如
{{ escape(handler.settings["cookie"]) }}

这两个{{}}`和这个字典对象也许大家就看出来了,没错就是这个handler.settings对象 handler 指向RequestHandler 而RequestHandler.settings又指向self.application.settings 所有handler.settings就指向RequestHandler.application.settings了! 大概就是说,这里面就是我们一下环境变量,我们正是从这里获取的cookie_secret 看题目的错误页面 ![](https://ae01.alicdn.com/kf/U0a8a3f428efb417c9056174aea3384abH.jpg) 可见页面返回的由msg的值决定,修改msg的值形成注入,获得环境变量 `?msg={{handler.settings}} (见上面灰色高显部分)
页面回显环境变量
{'autoreload': True, 'compiled_template_cache': False, 'cookie_secret': 'M)Z.>}{O]lYIp(oW7$dc132uDaK<C%wqj@PA![VtR#geh9UHsbnL_+mT5N~J84*r'}
得到cookie_secret

Contents
  1. 1. [护网杯 2018]easy_tornado