# Nmap 7.93 scan initiated Sat Mar 18 19:43:18 2023 as: nmap -Pn -p- -A -T5 -oN scan.txt 10.10.10.17 Nmap scan report for 10.10.10.17 Host is up (0.012s latency). Not shown: 65530 filtered tcp ports (no-response) PORT STATE SERVICE VERSION 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 |_smtp-commands: brainfuck, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN 110/tcp open pop3 Dovecot pop3d |_pop3-capabilities: SASL(PLAIN) RESP-CODES PIPELINING CAPA TOP AUTH-RESP-CODE UIDL USER 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) HOP RTT ADDRESS 1 11.41 ms 10.10.14.1 2 11.48 ms 10.10.10.17 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
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
- There are two SANs:
Let's add those SANs to the
/etc/hosts file on our attack box.
sudo nano /etc/hosts
# HTB brainfuck 10.10.10.17 brainfuck.htb 10.10.10.17 www.brainfuck.htb 10.10.10.17 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
firstname.lastname@example.org — This will likely come in handy for the mail services and potential bruteforcing. Looks like here, the blog user is
email@example.com could be the admin user's email, but will enumerate some more.
This WordPress site is using a plugin called
wp-support-plus-responsive-ticket-system and is at version
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.
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:
- Email Address
I have a pretty good guess at this point about what those would be based on my enumeration.
- Username =
- Email Address =
Looking at this form from the exploit POC, it has four input points that we need to provide:
I am going to save this form to
pwn.html and serve it using a Python HTTP server.
Now, in my browser, I am going to to
POST it to the target PHP script. After that, I should be able to hit the admin panel.
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.
The stage is set. When ready, click the
Send Test Email button in the SMTP Settings interface.
Whew! We got a credential!
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.
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.
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)
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
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
Grab the SSH Private Key
I should be able to pull the SSH private key using
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.
We can use
ssh2john to create a hash file and attempt to crack it:
Nice! I should now be able to SSH into the target as
orestis using this SSH key.
ssh -i ./orestis.key firstname.lastname@example.org
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
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.
We got another credential and this time it's for the forum!
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
Click to expand
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.
OS & Kernel
Click to expand
NAME="Ubuntu" VERSION="16.04.2 LTS (Xenial Xerus)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 16.04.2 LTS" VERSION_ID="16.04" HOME_URL="http://www.ubuntu.com/" SUPPORT_URL="http://help.ubuntu.com/" BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" VERSION_CODENAME=xenial UBUNTU_CODENAME=xenial 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
Click to expand
Click to expand
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 10.10.10.17/24 brd 10.10.10.255 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
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
Click to expand
Not too many interesting processes other than `mysql`, `lxc`
Click to expand
Again, nothing too interesting with the daemons.
Click to expand
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')
<?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', ), );
After some lengthy enumeration, there appear to be two paths to privilege escalation:
- LXD group membership (which I've used on other CTFs)
I am fairly certain the intended challenge is the script file. Looking at the script, we know these things:
- The script has encrypted
- The encrypted string is in
- The script output debug info for
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.
I'm only going to add here the code that I modified:
p = 7493025776465062819629921475535241674460826792785520881387158343265274170009282504884941039852933109163193651830303308312565580445669284847225535166520307 q = 7020854527787566735458858381555452648322845008266612906844847937070333480373963284146649074252278753696897245898433245929775591091774274652021374143174079 e = 30802007917952508422792869021689193927485016332713622527025219105154254472344627284947779726280995431947454292782426313255523137610532323813714483639434257536830062768286377920010841850346837238015571464755074669373110411870331706974573498912126641409821855678581804467608824177508976254759319210955977053997 # ct is the ciphertext ct = 44641914821074071930297814589851746700593470770417111804648920018396305246956127337150936081144106405284134845851392541080862652386840869768622438038690803472550278042463029816028777378141217023336710545449512973950591755053735796799773369044083673911035030605581144977552865771395578778515514288930832915182