Gavel
Writeup of Gavel machine

Recon
We've two open ports 80 and 22.

I checked up port 80 http and started running dirsearch.
http://gavel.htb/login.php endpoint shows a login page. So, I checked its sources, written version numbers, etc. During this time, dirsearch dumped out quite useful info
There is a .git endpoint alive in gavel.htb. So, I immediately used git-dumper to dump everything out.
The super cool thing I've found is the back-end source code of Inventory page -> inventory.php
SQL Injection
The page allows sorting the inventory using a sort parameter taken from GET/POST:
This value is then inserted directly into the SQL query as a column name:
Even though backticks are stripped, the application does not validate that $sortItem is a real, safe column. Since PDO cannot parameterize column names, the user‑controlled value becomes raw SQL inside the query. This leads to SQL Injection in the SELECT clause, allowing an attacker to inject additional expressions or subqueries by passing crafted sort values.
Building Up Payload on the inventory.php
inventory.php The first I've done is registering a new user account for myself and logged in.
Injection Point
$col is placed directly into the SELECT clause, so anything that isn’t a valid column will break the query and allow injection.
Notice that
user_idis also echoed into the query
Since user_id is used as a number, but inserted separately, you can break before the parameter with:
The backtick closes the column wrapper and lets us inject SQL.
3. Extend the SELECT clause
After closing the backtick, you append:
This turns the original expected:
SELECT `item_name` FROM inventory ...
into:
4. Comment out the rest
To prevent syntax errors from the trailing query, add:
5. Neutralize the sort parameter
sort parameterThe sort parameter becomes irrelevant, but the backend still wraps it in backticks. Using something harmless:
Final Payload
Credits to 0xanan who found the complete payload

This payload successfully dumps out all the passwords of registered users. The first hash is the admin's password. Cracked as midnight1
auctioneer:$2y$10$MNkDHV6g16FjW/lAQRpLiuQXN4MVkdMuILn0pLQlC2So9SgH5RTfS:midnight1
RCE from admin's account
1. Understanding admin panel
admin.php
You noticed that the
rulefield is editable by the admin.Rules are probably evaluated by the backend to check whether a bid is valid.
Comments in the HTML hinted at PHP code examples, e.g.
This tells you:
The backend likely executes
$ruleas PHP.Whatever you put in
ruleis evaluated server-side.
2. Confirming Where the Rule Executes
You checked other pages for signs of rule execution.
In bidding.php, each auction card shows:
The JavaScript sends these forms to:
/includes/bid_handler.php
This meant: When a bid is placed, the backend loads the rule for that auction and evaluates it.
So the flow is:
admin.php (store rule) → bid_handler.php (execute rule)
This confirmed the RCE path.
Testing RCE
To verify that the PHP code execution vulnerability actually works, I first injected a simple test payload using the admin interface. Instead of immediately spawning a reverse shell, I used a harmless command (id) to confirm code execution.
Injecting the malicious rule
Triggering the rule via a bid
Replace YOUR_SESSION and YOUR_ID parts by your own values.
since auction_id always changes in specific period of time, get your own auction_id from admin.php
change your auction_id if it says

If it's showing insufficient balance, try lowering the value of bid_amount or restart the machine.
User Flag

Step-by-Step Privilege Escalation Guide
Output of linpeas.sh
Key Findings in LinPEAS Output
A. Interesting Services Running as Root
B. Critical Discovery - Writable PHP Config
This PHP configuration file is world-readable and potentially writable. Let's check its contents and permissions.
C. Running Processes of Interest
These are root-owned scripts running continuously.
D. Critical Discovery: Gavel Utility
Found a custom binary:
Root
Payload 1
Changing the permission of /opt/gavel/.config/php/php.ini
Overwrites the PHP config file
Enables PHP engine (
engine=On)Shows errors for debugging (
display_errors=On)⚠️ Removes directory restrictions (
open_basedir=/) - PHP can now access ANY file⚠️ Enables ALL dangerous functions (
disable_functions=empty) - can run shell commands
Payload 2
Uses
system()(now enabled by Payload 1) to run shell commandsSets SUID bit on
/bin/bash(chmod u+s)Makes bash run as root for any user
After this runs:
/bin/bash -pgives you root shell
/usr/local/bin/gavel-util submit ini_overwrite.yaml
/usr/local/bin/gavel-util submit root_suid.yaml
This command submits a malicious YAML file to an auction system that will execute the embedded PHP code with elevated privileges.
The Attack Chain:
Payload 1 executes → Removes PHP security
PHP can now → Run any command, access any file
Payload 2 executes → Makes bash always run as root
You run →
/bin/bash -p→ You get root!

The End!!! Thank you!!!
Last updated