Server-side template injection with information disclosure via user-supplied objects

3 min read Medium PortSwigger
Server-side template injection
Contents

On this page

The lab

here is how portswigger describes it

This lab is vulnerable to server-side template injection due to the way an object is being passed into the template. This vulnerability can be exploited to access sensitive data.

To solve the lab, steal and submit the framework's secret key.

You can log in to your own account using the following credentials: content-manager:C0nt3ntM4n4g3r

every lab up to now ended with us deleting carlos's file, so template injection has looked like a straight road to running commands. this one breaks that habit. the goal here is not code execution at all, it is reaching into the data the template can already see and walking out with a secret.

Not every injection is about running code#

it is easy to assume server side template injection always means remote code execution, but that is only the loudest outcome. sometimes the engine is locked down enough that you cannot spawn a shell, and sometimes you simply do not need to. templates get handed objects to render, and those objects often carry far more than the page ever shows. config, environment, framework internals, all sitting one expression away.

this lab is exactly that case. an object is passed into the template that an attacker should never have been able to reach into, and inside it lives the framework's secret key. so instead of hunting for a command execution gadget, we identify the engine, then use its own legitimate features to read data that was never meant to be on screen.

Step 1 - Log in and find the template editor#

we log in with the provided content-manager:C0nt3ntM4n4g3r credentials. this is the same shape of app as the last couple of labs, so we open any post and scroll down to the edit template button.

11111

that editor is our injection point, same as before. the difference is only in what we do once we are inside.

Step 2 - Fingerprint the engine#

we still need to know which engine we are talking to, so we reach for the same trick, hand it something it cannot parse and read the error.

we change one of the template expressions to the polyglot fuzz string and save.

SSTI
${{<%[%'"}}%\
22222

the save throws back a python traceback, and it is detailed.

HTTP
django.template.exceptions.TemplateSyntaxError: Could not parse the remainder: '<%[%'"' from '<%[%'"'
  File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 486, in parse
33333

the paths and the exception class both name django, so this is a django template running on python. now we go read the django documentation with that in mind.

Step 3 - Use a built in tag to see what the template can access#

before we can steal anything we need to know what is actually in reach of the template. django hands us a gift for that.

digging through the docs turns up a built in template tag called debug, whose whole job is to dump debugging information about the current template context. that is perfect, because it will list every object and variable the template can see, and somewhere in that dump we can look for anything sensitive.

we clear out the fuzz string and drop in the debug tag.

Djnago
{% debug %}
44444

reloading the product renders a big dump of the context, all the available variables and objects laid out for us.

55555

Step 4 - Read the secret key out of the settings object#

scanning that dump, the settings object is the one worth chasing. cross referencing it against the django docs, settings holds the application's configuration, and one of its properties is SECRET_KEY. that key is what django uses to sign sessions and tokens, so leaking it is a serious problem, which is exactly why it is the lab's target.

the nice part is we do not need any trickery to read it. settings is already in the template context, so we just ask for the property directly. we remove the debug tag and enter a plain expression.

Django
{{settings.SECRET_KEY}}
66666

saving the template renders the value, and the framework's secret key is printed straight onto the page. 77777

all that is left is to hand it in. we click submit solution and paste the key. 88888

with this, the lab is solved!