Hack the Box (HTB) - Brainf*#k
Exploiting a WordPress plugin, breaching an SMTP server, and decrypting an RSA private key
Enumeration
Let’s start by running a AutoRecon scan against our target at 10.10.10.17
We see the following TCP ports open:
- 22 - SSH, (Ubuntu 4ubuntu2.1)
- 25 - SMTP
- 110 - POP3
- 143 - IMAP
- 443 - HTTPS (nginx 1.10.0 (Ubuntu))
Let’s start by checking the nginx web server on port 443
The default web page for nginx
Let’s check our feroxbuster scan
No useful directories were found
Normally these boxes operate on HTTP. Since we’re dealing with HTTPS we can inspect the SSL/TLS certification to reveal additional information on the domain
We see an email orestis@brainfuck.htb
. This will most likely be utilized somewhere on this machine, especially with all the mail services listed
We see two domains listed here, sup3rs3cr3t.brainfuck.htb
and www.brainfuck.htb
Since these domains are not accessible via public DNS we will need to add them to our /etc/hosts
file for local DNS
1
nano /etc/hosts
Now that that’s done. Let’s navigate to https://brainfuck.htb/
The first thing we see is “Just another WordPress site”. Since this is a WordPress site, we can use wpscan, which is a vulnerability scanner for WordPress websites
1
2
# This will enumerate users, passwords, and themes (u,p,t)
wpscan --url https://www.brainfuck.htb --enumerate u,p,t --disable-tls-checks --ignore-main-redirect --verbose
We had to –disble-tls-checks since the SSL certificate is self signed
Looking at the wpscan results, we see some potential important information
This wp-support-plus-responsive-ticket-sytem
plugin is outdated (version 7.1.3). Outdated plugins are common attack vectors in WordPress
Let’s check searchsploit for this vulnerable plugin
1
searchsploit wp support
Two exploits exist for this version. Let’s grab the privilege escalation one first
Looking at the script we see the following
The exploit allows unauthorized login to any account without needing a password due to a logic flaw.
The script sends a post request to admin-ajax.php
with the value of username being the compromised user & the value of email being the compromised email
The vulnerable code might look something like this
1
2
3
4
if ($user) {
wp_set_auth_cookie($user->ID, true);
wp_redirect(admin_url());
exit;
This directly sets the authentication cookie for the user ID by the username, without verifying authentication
The proper code would be as follows
1
2
3
4
if ($user && wp_check_password($password, $user->user_pass, $user->ID)) {
wp_set_auth_cookie($user->ID, true);
wp_redirect(admin_url());
exit;
Anyway, let’s edit the request to include the following information we’ve obtained earlier:
- URL =
https://brainfuck.htb/wp-admin/admin-ajax.php
- name =
admin
(obained from WP scan) - email =
orestis@brainfuck.htb
(from earlier)
I’ll also copy & paste this exploit into a file.html so we can actually execute it in our browser
Now host a local http server with python so we can run the script in our browser
1
python3 -m http.server 9001
Navigating to our local host on port 9001 we see our web server being hosted with our script
Clicking on script, we can enter our login information
Clicking on Login
will make the following post request as we discussed earlier
Now we can navigate to the home directory for this WP site and we’ll be logged in as Admin!
Looking around the site, we notice settings that lead to Easy WP SMTP
Let’s check the source code for this page
And boom, the SMTP password is kHGuERB29DNiNE
. We can now authenticate as orestis with orestis@brainfuck.htb
Let’s use the Thunderbird email client here. We’ll login to the orestis mail server and take a look around
After getting errors trying to login, I changed the username field above from the orestis@brainfuck.htb to just orestis and was able to proceed
Reading this message from our dear friend Root, we see they sent us the credentials to the secret fourm
- Username - orestis
- Passowrd - kIEnnfEKJ#9UmdO
Let’s head over to the secret forum and login
Navigating to the site, we see talk of SSH login
It looks like orestis might have an encrypted chat with the SSH key. Let’s find that chat
This appears to be a simple substitution cipher at first glance.
Noticing the Orestis - Hacking for fun and profit
signature in the unencrypted chat
- Uncrypted signature:
"Orestis - Hacking for fun and profit"
- Encrypted signature:
"Pieagnm - Jkoijeg nbw zwx mle grwsnn"
Using the Cipher Identifier (Boxentriq). I was able to ascertain the cipher method as Vigenère cipher
The main takeaway form this cipher method is that we need a key in order to crack it. Since we know some plaintext that corresponds to the ciphered (Orestis’s signature) we can create a script to decode the key
Understanding how this cipher works is important. We can create a python script to spit out the key for us
This isn’t my script but in layman’s terms the for loop determines the password by comparing both characters in the index from the plain & encrypted phrases. The weakness in this method is obviously that if you know plain text, you can decode the key. This was one of the methods used to crack the enigma machine codes in WW2
Anyway, Let’s run the script
As we can see, the key is FUCKMYBRAIN
Using our extremely elegant key name, let’s head over to Cyberchef and decode the link to the SSH key
We have a clickable link: https://brainfuck.htb/8ba5aa10e915218697d1c658cdee0bb8/orestis/id_rsa
The problem is the SSH key requires a pass code, which is unknown to us. Reading the next message, Orestis writes “No problem, I’ll brute force it :)” which leads me to believe it’s a simple password
Let’s ssh2john to convert the private SSH key into a format John can understand
1
ssh2john id_rsa > id_rsa.hash
Now use the new file against John & attempt to crack it
1
john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa.hash
We get the SSH file passcode revealed as 3poulakia!
Now we can use this pass code with our SSH key to SSH into the machine. First let’s change the permission on the key. SSH requires that prviate keys are only readable by the owner
1
chmod 600 id_rsa
Now lets’ SSH!
1
ssh -i id_rsa orestis@10.10.10.17
Enter our passkey of 3poulakia!
and wee’re in!
SSH Access
Escalation
Now is the fun part, escalating. Running sudo -l is useless as we don’t have orestis’s password
Let’s take a look around and see what we can find
Sage Script
Immediately checking our user directory, I notice this encrypt.sage
file that’s owned my us (orestis)
Doing some research, this script is written in SageMath, a software system for mathematical calculations. The script is creating an RSA public key and using it to encrypt out flag, root.txt. It then puts the contents into output.txt
. It puts the private key components needed to decrypt it in debug.txt
such as p
q
& e
. Obviously in the real world debug.txt would be hidden or destroyed as this will let us reconstruct the private key, but this is a CTF after all
Sure enough, this is the encrypted root.txt. We’ll need to perform RSA decryption to grab this root flag. First we’ll copy the encrypted password and save it to encrypted_password.txt
Next, we will need the prime Values p
q
& public exponent e
from debug.txt
which is:
1
2
3
p = 7493025776465062819629921475535241674460826792785520881387158343265274170009282504884941039852933109163193651830303308312565580445669284847225535166520307
q = 7020854527787566735458858381555452648322845008266612906844847937070333480373963284146649074252278753696897245898433245929775591091774274652021374143174079
e = 30802007917952508422792869021689193927485016332713622527025219105154254472344627284947779726280995431947454292782426313255523137610532323813714483639434257536830062768286377920010841850346837238015571464755074669373110411870331706974573498912126641409821855678581804467608824177508976254759319210955977053997
To compute the RSA private key using the values of p, q, and e we can use the following script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse, long_to_bytes
import ast
# Values from debug.txt (replace with actual values)
p = 7493025776465062819629921475535241674460826792785520881387158343265274170009282504884941039852933109163193651830303308312565580445669284847225535166520307
q = 7020854527787566735458858381555452648322845008266612906844847937070333480373963284146649074252278753696897245898433245929775591091774274652021374143174079
e = 30802007917952508422792869021689193927485016332713622527025219105154254472344627284947779726280995431947454292782426313255523137610532323813714483639434257536830062768286377920010841850346837238015571464755074669373110411870331706974573498912126641409821855678581804467608824177508976254759319210955977053997
# Compute the RSA modulus
n = p * q
# Compute the totient (phi(n))
phi_n = (p - 1) * (q - 1)
# Compute the private exponent
d = inverse(e, phi_n)
# Construct the RSA key
private_key = RSA.construct((n, e, d, p, q))
# Save the private key to a PEM file
with open('private_key.pem', 'wb') as key_file:
key_file.write(private_key.export_key())
This script (not mine) in will take the two prime numbers p and q and the public number e to create a private key which will but saved to private_key.pem
. This obviously be used to decrypt messages that were encrypted with the public key. I.E root.txt
Now that we have our private key private_key.pem
we can decrypt the message in encrypted_password.txt
We will use the follwing python script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Util.number import long_to_bytes
# Load the private key
with open('private_key.pem', 'rb') as key_file:
private_key = RSA.import_key(key_file.read())
# Load the encrypted message
with open('encrypted_password.txt', 'r') as file:
encrypted_data = file.read().strip()
c = int(encrypted_data) # Convert to integer
# Create the cipher object
cipher = PKCS1_OAEP.new(private_key)
# Decrypt the data
try:
decrypted_data = cipher.decrypt(long_to_bytes(c))
print("Decrypted Password:", decrypted_data.decode())
except Exception as e:
print(f"Decryption failed: {e}")
GG, we’ve decrypted the root flag
Summary
- Discovered ports 22, 443, 25, and 143
- SSL Certificate revealed a hidden domain leading to a WordPress site
- Exploited outdated WP plugin
- Retrieved SMTP credentials from the WordPress site and logged into the mail server
- Discovered credentials to login to secret forum
- Found SSH access details in a forum conversation
- Broke ciphers to obtain and brute-force a private key, then used it to SSH into the machine
- Reconstructed the private key using given components and decrypted the root flag
Vulnerabilities & Mitigation
Vulnerability | Mitigation |
---|---|
Outdated WordPress plugin | Regularly update plugins to their latest versions and apply security patches. |
SMTP password in cleartext left on admin site | Use secure methods for storing and transmitting credentials. Implement encryption for sensitive data. |
Transmitting password over email | Avoid sending sensitive information via email. Use secure communication channels and encryption. |
Using outdated ciphers (Vigenère cipher) to transmit private keys on public forums | Use modern encryption methods and ensure secure key exchange practices. Avoid sharing sensitive information publicly. |
Use of weak passphrases on private key | Use strong, complex passphrases for private keys and implement key management best practices. |
Remediation References
- Outdated WordPress Plugin
- Reference: WordPress Plugin Security
- SMTP Password in Cleartext Left on Admin Site
- Reference: Secure Password Storage
- Transmitting Password Over Email
- Reference: Email Security Best Practices
- Using Outdated Ciphers (Vigenère Cipher) to Transmit Private Keys on Public Forums
- Reference: Modern Encryption Practices
- Use of Weak Passphrases on Private Key
- Reference: Key Management Best Practices