
سكربت استغلال لإثبات المفهوم لثغرة حقن الأوامر (CVE-2026-27626) في معالجة وسيط كلمة المرور في OliveTin، مما يتيح تنفيذ التعليمات البرمجية عن بُعد عبر طلبات API مصممة خصيصًا.
تتيح OliveTin للمسؤول تعريف «إجراءات»: أوامر شل مع وسائط معلمة يمكن للمستخدمين تشغيلها من واجهة ويب أو API. قبل تضمين قيمة مقدمة من المستخدم في أمر الشل، يُفترض أن تمررها OliveTin عبر checkShellArgumentSafety(). تفحص هذه الدالة أربعة أنواع من الوسائط: string وint وbool وchoice. وتتخطى password تمامًا وتُرجع true، أي «آمنة»، دون النظر إلى القيمة إطلاقًا.
لذا إذا كان الإجراء يحتوي على وسيط من نوع password، وتم استبدال هذا الوسيط داخل سلسلة أمر شل، يمكنك وضع أي شيء فيه. فواصل منقوطة، أو backticks، أو $()، أو أي شيء. إذا كان الوسيط محاطًا بعلامات اقتباس في الأمر الأساسي (وهو نمط شائع لأشياء مثل كلمات مرور قواعد البيانات)، فإن الخروج من علامة الاقتباس كافٍ.
func checkShellArgumentSafety(argType string, value string) bool {
dangerousTypes := []string{"string", "int", "bool", "choice"}
for _, dt := range dangerousTypes {
if argType == dt {
return sanitizeInput(value)
}
}
// password type falls through here, unchecked
return true
}
يؤثر على OliveTin حتى 3000.10.0. تم إصلاحه في سلسلة 3000.11.1 (commit 0.0.0-20260222101908-4bbd2eab1532)، والتي تضيف password إلى الأنواع المفحوصة. الاستشارة: GHSA-49gm-hh7w-wfvf. درجة CVSS 9.9.
أي شيء يقع فيه وسيط من نوع password داخل سلسلة أوامر شل، وعادةً ما يكون بين علامتي اقتباس:
- title: Backup database
id: backup_db
shell: "mysqldump -u {{ db_user }} -p'{{ db_pass }}' {{ db_name }} > /tmp/backup.sql"
arguments:
- name: db_user
type: ascii_identifier
- name: db_pass
type: password
- name: db_name
type: ascii_identifier
db_pass داخل علامتي اقتباس مفردة ولا شيء يفحصه. أرسل '; id ;' كقيمة وستنفذ OliveTin الأمر id قبل أن يفشل استدعاء mysqldump غير الصالح. الفشل لا يهم؛ الأمر المحقون نُفذ بالفعل بصلاحية المستخدم الذي تعمل به OliveTin. في كثير من الإعدادات يكون هذا المستخدم هو root، لأن الأشخاص يشغلونها عبر systemd دون سطر User= ولا يفكرون في الأمر مجددًا.
لا تحتاج إلى بيانات اعتماد لأي من هذا إذا كان المثيل مضبوطًا على authRequireGuestsToLogin: false، وهو أمر شائع في النشرات الصغيرة أو للهواة.
pip install requests
python3 exploit.py -u <target> --action backup_db --arg db_pass -x "id"
إذا كان الإجراء يحتاج وسائط أخرى لكي يعمل دون أخطاء قبل تنفيذ أمرك المحقون، مررها عبر --extra-arg:
python3 exploit.py -u 10.0.0.5 --action backup_db --arg db_pass \
--extra-arg db_user=admin --extra-arg db_name=prod -x "whoami"
يرسل السكربت طلب POST إلى StartAction، وينتظر ثانيتين، ثم يستعلم ExecutionStatus ويطبع ما يعود. عادةً سترى مخرجات أمرك المحقون فوق خطأ من الأمر الشرعي الذي نُفذ بعده وفشل. هذا متوقع. الخطأ شكلي فقط؛ أمرك نُفذ بالفعل.
حدّث OliveTin إلى إصدار أحدث من 3000.10.0. إذا لم تتمكن بعد: أزل أي وسائط من نوع password من الإجراءات التي يمكن للمستخدمين غير الموثوقين الوصول إليها، وعطّل تنفيذ الزوار، وتوقف عن السماح بإدراج قيم الوسائط داخل سلاسل أوامر الشل نهائيًا إذا استطعت. مرر الأسرار عبر متغيرات البيئة أو ملف تقرؤه OliveTin من مسار ثابت بدلًا من ذلك. ولا تشغّل الخدمة بصلاحية root. لا يوجد أي سبب يجعل مشغّل المهام يملك تلك الصلاحية.
exploit.py: سكربت إثبات المفهوم (PoC)README.md: هذا الملفهذا موجود للأشخاص الذين يصححون مثيلات OliveTin الخاصة بهم، أو يكتبون قواعد كشف، أو يختبرون أنظمة مخوّلين لاختبارها. لا توجّهه إلى أي شيء لا تملكه أو ليس لديك إذن بالوصول إليه. المسؤولية تقع عليك، وليس على من كتب هذا.
| الخيار | الغرض | الافتراضي |
|---|
-u, --url | المضيف أو عنوان IP الهدف | مطلوب |
-p, --port | منفذ OliveTin | 1337 |
--action | bindingId الخاص بالإجراء المعرّض للثغرة | مطلوب |
--arg | اسم الوسيط من نوع password | مطلوب |
-x, --cmd | الأمر المراد حقنه | id |
--extra-arg | وسائط أخرى يحتاجها الإجراء بصيغة name=value، قابلة للتكرار | لا شيء |