Welcome to another Hack the Box walkthrough. In this blog post, I have demonstrated how I owned the Gavel machine on Hack the Box. Hack The Box is a cybersecurity platform that helps you bridge knowledge gaps and prepares you for cyber security jobs.
About the Machine
Gavel is a Medium-difficulty Linux challenge that focuses on chaining multiple realistic vulnerabilities in a custom auction web application. Players move from authenticated web exploitation to credential abuse, gain administrative access, and leverage unsafe server-side rule processing to achieve remote code execution. The challenge then shifts into post-exploitation, where analysis of a custom backend utility and a flawed YAML-based submission mechanism allows privilege escalation to root. Gavel rewards careful enumeration, understanding of application logic, and precise exploitation timing, making it a well-rounded challenge for web and Linux privilege escalation enthusiasts.
The first step in owning the Gavel machine like I have always done in my previous writeups is to connect my Kali Linux terminal with Hack the Box server. To establish this connection, I ran the following command in the terminal:
Once the connection between my Kali Linux terminal and Hack the Box server has been successfully established, I started the Gavel machine and I was assigned an IP address (10.10.11.97).
Initial Reconnaissance
To begin reconnaissance, I first mapped the target IP to a local hostname for convenience. This allows easier interaction with virtual hosts during enumeration:
With the hostname in place, I performed a comprehensive Nmap scan to identify open services, service versions, and potential misconfigurations:
The scan confirmed that the host was reachable and running a Linux-based operating system. Only two TCP ports were exposed, which already hinted at a deliberately minimal attack surface.
Service Enumeration
Port 22 (SSH) was open and running OpenSSH 8.9p1 on Ubuntu. At this stage, there was no immediate indication of weak credentials or misconfiguration, so SSH was noted as a potential post-exploitation access point rather than an initial entry vector.
Port 80 (HTTP) revealed a much more interesting target. The server was running Apache 2.4.52 and hosted a web application titled “Gavel Auction”, suggesting an auction-style platform. This immediately became the primary focus for further enumeration.
While probing the web service, Nmap’s http-git script uncovered a critical misconfiguration:
The presence of a publicly accessible .git directory strongly indicated that the site’s Git repository had been accidentally deployed to production. Even more revealing, the repository contained configuration files and commit history, with the last commit message set to .., suggesting incomplete or careless repository hygiene.
This finding was a major red flag and a classic CTF foothold - exposed Git repositories often leak source code, credentials, hardcoded secrets, or forgotten endpoints, all of which can be leveraged to move forward.
Web Application Discovery
With the hostname properly mapped, I navigated to the target in my browser. Visiting the IP address redirected me to http://gavel.htb, confirming that the application relies on name-based virtual hosting.
The landing page revealed a fully themed auction platform called Gavel 2.0, complete with custom branding and flavor text. On the left-hand navigation menu, two options stood out: Login and Register. This indicated that the application supports authenticated user accounts and that at least part of its functionality is gated behind authentication.
Clicking on Register redirected me to gavel.htb/register.php, where I was presented with a standard account creation form requesting:
- A username
- A password
- Password confirmation
The registration process appeared unrestricted, allowing anyone to create an account without prior approval. This is a common pattern in CTF web challenges and often serves as the intended entry point into the application’s internal functionality.
At this stage, the attack surface became clearer:
- The application is dynamic and user-driven
- Authentication logic is present
- PHP is being used server-side
- Additional functionality is likely exposed once logged in
With a valid account easily obtainable, the next logical step was to register a user and explore the authenticated portions of the application, while keeping an eye out for logic flaws, privilege escalation paths, or vulnerabilities hidden behind the login wall.
Authenticated Application Analysis
After successfully registering and logging into the application, additional functionality became available via the left-hand navigation menu. Two new options appeared: Inventory and Bidding, confirming that user-specific state and session handling were in place.
Visiting the Inventory page showed that my newly created account did not own any items yet.
However, I was automatically credited with a balance of 50,000 bidding coins, likely intended to allow immediate participation in the auction system. This confirmed that the application maintains server-side tracking of both user inventory and virtual currency.
Next, I navigated to the Bidding section, which redirected me to gavel.htb/bidding.php. This page hosted the core functionality of the platform: a live auction system with multiple items actively up for sale.
Each auction listing displayed:
- A starting price and current bid
- A bid input field
- The current highest bidder
- A visible countdown timer indicating how much time remained before the auction closed
The presence of real-time countdowns and bid validation rules suggested that the application enforces bidding logic dynamically, likely through a combination of backend checks and client-side constraints. Additionally, the warning banner made it clear that bids are binding and non-refundable, and that overlapping or losing bids still result in coins being deducted.
From a security perspective, this immediately raised several points of interest:
- Time-based logic often introduces race conditions
- Bid validation rules may be enforced inconsistently between client and server
- Virtual currency handling is a common target for logic flaws and trust issues
At this stage, the auction system appeared to be the heart of the application and a likely candidate for exploitation. With user-controlled input, countdown-driven behavior, and financial-style logic in play, the next step was to closely inspect how bids are submitted and validated, both in the browser and at the HTTP request level.
Web Content Enumeration
To identify hidden endpoints and backend functionality not exposed through the UI, I performed directory and file enumeration using ffuf, targeting common filenames and PHP endpoints:
The scan revealed several expected application routes such as login.php, register.php, inventory.php, and admin.php. Notably, both inventory.php and admin.php returned 302 redirects, indicating access controls and potential role-based restrictions worth testing later.
The most critical finding was the exposure of the .git directory. Multiple Git internals including .git/HEAD, .git/config, .git/index, and .git/logs/ -were directly accessible over HTTP, confirming that the application’s source code repository had been deployed to production.
This misconfiguration provided a clear attack path: rather than relying on black-box testing alone, I could reconstruct the full source code locally and analyze the application logic directly.
With the Git repository exposed, the next step was to dump its contents and review the code for authentication flaws, business logic issues, and privilege escalation opportunities.
Dumping the Exposed Git Repository
Since the .git directory was accessible over HTTP, I used git-dumper to reconstruct the full repository locally:
The tool first validated access to critical Git files such as .git/HEAD and .git/config, confirming the repository was readable. It then recursively fetched Git internals including logs, refs, and, most importantly, the contents of the objects/ directory.
The large volume of successful 200 responses indicates that all required Git objects were retrievable, allowing the repository to be fully reconstructed without errors. This effectively gave me a local copy of the application’s source code as it existed on the server.
With the repository dumped, I could now inspect commits, configuration files, and application logic directly - removing the guesswork from further exploitation and enabling precise identification of vulnerabilities such as hardcoded credentials, authentication flaws, or insecure admin functionality.
SQL Injection in inventory.php
While reviewing authenticated functionality, I noticed that the Inventory page accepted a user_id parameter directly in the URL. Suspecting insufficient input sanitization, I manually tested the parameter for SQL injection by injecting a crafted payload directly into the browser by visiting the following URL in my browser:
By abusing the user_id parameter and leveraging a UNION-style injection with GROUP_CONCAT, I was able to force the backend query to return data from the users table instead of legitimate inventory entries.
As a result, the application rendered the output directly inside the inventory panel, leaking a concatenated list of usernames and password hashes:
The $2y$10$ prefix confirmed that the passwords were stored using bcrypt, indicating proper hashing but poor query handling. Despite the hashing, obtaining credential material for multiple privileged users - most notably admin and auctioneer - was a major escalation point.
This confirmed a server-side SQL injection vulnerability in inventory.php, allowing authenticated users to dump sensitive database contents. With valid usernames and bcrypt hashes now exposed, the next step was to attempt offline password cracking and reuse recovered credentials to gain higher-privileged access.
Cracking the Leaked Credentials
From the SQL injection in inventory.php, I obtained several bcrypt password hashes, including one belonging to the auctioneer user. Since this account appeared to be more privileged than a standard user, I targeted it first.
I saved the hash to a file and attempted offline cracking using John the Ripper with the rockyou.txt wordlist:
John successfully identified the hash as bcrypt and began brute-forcing it using multiple threads. Within seconds, the password was cracked:
Despite bcrypt being a strong hashing algorithm, the password itself was weak and present in a common wordlist. This provided valid credentials for a higher-privileged account without triggering any server-side defenses.
With the auctioneer username and password now known, the next step was to authenticate as this user and assess what additional access or functionality this role provided, potentially including administrative features or system-level escalation paths.
Administrative Access and Code Execution Vector
Using the cracked credentials auctioneer:midnight1, I successfully authenticated to the web application at http://gavel.htb. Upon login, the interface confirmed that the auctioneer account held administrative privileges, including an abnormally large balance of 999,999,999 coins, effectively removing any financial restrictions within the auction system.
With administrative access unlocked, a new Admin Panel entry appeared in the navigation menu. Inside this panel, I identified a Rules section used to define dynamic logic for auction lots. These rules are applied server-side and influence how bids are validated and processed in real time.
Earlier source code review revealed a critical design flaw: rule evaluation is implemented using runkit_function_add(), allowing rules to be dynamically created as PHP functions. This means that any rule entered by an administrator is executed directly as PHP code on the server.
At the time of access, three auction items were actively running with countdown timers. The application periodically recalculates rules for all active lots, which provides a reliable execution trigger. By injecting malicious PHP code into a custom rule, I could guarantee execution as soon as the next rule evaluation cycle occurred.
Rule Injection → Remote Code Execution
With administrative access secured, the real attack surface finally came into play. Everything up to this point was setup - now it was time to turn control into execution.
Since auction rules are evaluated server-side using runkit_function_add(), injecting a reverse shell into a rule would result in direct PHP code execution. Before doing that, I prepared a listener on my attack machine to catch the callback:
Because all sensitive actions are authenticated, I needed to impersonate the admin session outside the browser. The application relies on PHP’s default session handling, so I extracted the active session token (PHPSESSID) directly from the browser’s DevTools under Storage → Cookies.
This session cookie would be reused in all subsequent curl requests to maintain administrator privileges.
Identifying an Active Auction Target
Rule execution only happens when an auction lot updates, so I needed the ID of a currently active auction. By requesting the bidding page with the admin session cookie and parsing the response, I extracted the hidden auction_id values directly from the HTML.
This revealed three active auctions, each with a running timer - perfect execution triggers.
I placed a bid of 70,000 on an item and got a toast notification "Bid placed successfully"
It is inportant to note the amount bidded on the item as this will come handy when trying to trigger the payload and send a POST request to the bid handler.
Payload Injection
Back in the Admin Panel, I edited the rule for one of the active lots and injected a simple PHP reverse shell payload:
With the payload in place, the final step was to force rule evaluation. This happens whenever a bid is placed, so I manually triggered it by submitting a bid via the internal bid handler endpoint using curl, again passing the admin session cookie.
The next step is to trigger the rule execution to get a reverse shell.
Triggering Rule Execution → Reverse Shell
With the malicious rule already in place, the final step was to trigger its execution. Since rule evaluation happens whenever a bid is processed, all that was left was to force an update on an active auction.
Before doing so, I prepared a netcat listener on my attack machine to catch the incoming connection:
Because the bid handler is protected, I needed to act as an authenticated administrator. The application uses PHP’s default session handling, so I extracted the active session identifier (PHPSESSID) from the browser via DevTools → Storage → Cookies. This session token allows me to replay authenticated actions outside the browser by passing it in the Cookie header.
With the session cookie in hand, I manually triggered rule execution by submitting a bid directly to the internal bid handler endpoint:
The server confirmed the bid was accepted and seconds later, my listener received a callback.
Shell Access and User Compromise
The reverse shell connected back as www-data@gavel. I immediately upgraded it to a fully interactive TTY by running:
Using the previous cracked credentials, I switched to the auctioneer user locally and authenticated with the password (midnight1) thereby granting me shell as auctioneer. From there, accessing the home directory revealed the user flag:
Hurray!!! I got my user flag
Local Enumeration and Privilege Escalation Surface
After landing as the auctioneer user, I shifted focus to local enumeration. One directory immediately stood out during filesystem inspection: /opt/gavel/.
This path contains a custom binary (gaveld), a YAML configuration file, and a submission/ directory - all owned by root. The presence of a dedicated application directory under /opt strongly suggests a locally developed service rather than a standard system package. Combined with the executable permissions on gaveld, this hinted at a background daemon or scheduled process running with elevated privileges.
To understand how this service might be interacted with, I expanded the search to common binary locations. In /usr/local/bin/, I discovered another custom executable named gavel-util by running:
Unlike typical system binaries, this tool is owned by root but assigned to a non-standard group (gavel-seller), indicating it is likely intended to be executed by specific non-root users.
At this stage, the attack surface became clear: a root-owned daemon (gaveld) paired with a user-accessible helper utility (gavel-util) and writable or user-influenced configuration artifacts. This combination is a classic setup for privilege escalation especially if gavel-util interacts with gaveld, processes YAML input, or writes into locations later consumed by the daemon.
With promising targets identified, the next step was to analyze how gavel-util operates and whether its interaction with the root service could be abused to gain elevated privileges.
Abusing gavel-util to Escalate Privileges
During local enumeration, I identified a custom helper binary, gavel-util, which is designed to submit new auction items for processing by the root-owned gaveld service. Since submissions are provided as YAML files and later processed automatically, this immediately stood out as a promising privilege escalation vector.
To test how much control I had over the submission logic, I first crafted a benign-looking auction item (fix_ini.yaml). The goal of this submission was not privilege escalation yet, but to manipulate the PHP runtime configuration used by the backend. The embedded rule overwrites the PHP configuration file under /opt/gavel/.config/php/php.ini, explicitly enabling error display and disabling all execution restrictions such as open_basedir and disable_functions. This confirmed that rule contents are executed with elevated privileges and can freely write to root-owned paths.
After submitting the file with gavel-util submit, the item was queued for processing in the next auction cycle, meaning the rule would eventually be executed by the privileged service.
With execution confirmed, I moved on to the final payload. I created a second submission (rootshell.yaml) whose rule executes a simple but effective escalation technique: copying /bin/bash to a controlled location and marking it SUID. Since this operation is performed by the root service, the resulting binary would execute with root privileges regardless of the invoking user.
Once again, the YAML file was submitted via gavel-util, ensuring it would be picked up and processed automatically.
Privilege Escalation → Root Access
After waiting for the auction processor to handle the submitted payload, I checked for the presence of the SUID binary created earlier.
The file /opt/gavel/rootbash now existed and, more importantly, was owned by root with the SUID bit set, confirming that the rule had executed successfully under elevated privileges.
Executing the binary with the -p flag preserved root privileges, immediately dropping me into a root shell. A quick identity check confirmed full administrative access to the system.
With root access achieved, I navigated to the root user’s home directory and retrieved the final flag:
Hurray! I got the root flag. With that the machine was officially pwned.
If you enjoy reading my walkthrough, do not forget to like, comment, and subscribe to my YouTube channel and also connect with me on LinkedIn. Also, don't forget to turn on post notification on my YouTube channel and Medium to get notification as soon as I write.
Subscribe to my YouTube channel and Follow me on: LinkedIn | Medium | Twitter | Boltech Twitter | Buy Me a Coffee
Keywords:
Gavel Hack the Box Writeup
Gavel has been Pwned
Gavel Hack the Box Machine Writeup
Gavel Machine | HackTheBox
Gavel Hack the Box Walkthrough
Hack the Box (HTB) machines walkthrough series
Gavel Hack the Box Machine Walkthrough
Gavel HTB Writeup
pwned Gavel Machine from Hack The Box
Gavel HTB Walkthrough
Gavel HTB Machine Walkthrough
Gavel HTB Machine Writeup
Gavel Hack the Box HTB Machine Walkthrough Writeup
Gavel HTB Solution
Gavel Hack the Box Solution
Gavel Hack the Box Complete Walkthrough
Gavel Hack the Box Complete Writeup
Gavel Hack the Box Complete Solution
Gavel htb write up
HackTheBox Gavel Writeup
HTB Gavel Writeup
HackTheBox Gavel Writeup
HackTheBox - Gavel (Writeup)
HTB Writeups - Gavel
HackTheBox Gavel Writeup
Gavel | HTB Writeup | Linux
gavel htb
HTB - Gavel Writeup
Owned Gavel from Hack The Box
Hack The Box - HTB Gavel Writeup
HTB Gavel Detailed Writeup English
HackTheBox | Gavel HackTheBox · HackTheBox | Gavel
Gavel HTB Writeup | HacktheBox | Season 9
HTB Writeup - Gavel
Write-ups Category Posts | Hack The Box Blog
Gavel - Hack the Box - Walkthrough
Gavel - HTB - Walkthrough
Gavel - Hack the Box - Writeup
HTB Season 9 Episode 11 | Gavel Medium | Tips & Review
Hack The Box
HackTheBox - Gavel
I just pwned Gavel on Hack The Box
HTB-Gavel-Writeup
HackTheBox: Gavel Writeup - From Web to Root
Gavel HTB Seasons Machine
HTB : GAVEL [MEDIUM] - Season 9 | GACHA Series
Mastering Gavel: Beginner's Guide from HackTheBox
Gavel HTB Writeup - Linux Medium































0 Comments