
CVE-2026-11837: تصعيد صلاحيات محليًا في وحدة ansible.posix authorized_key عبر chown الذي يتبع الروابط الرمزية. توثيق تقني؛ وهي شقيقة CVE-2024-9902.
authorized_key من ansible.posixتصعيد امتيازات محلي في وحدة Ansible ansible.posix.authorized_key عبر chown الذي يتبع الروابط الرمزية (وإنشاء ملفات يتبع الروابط الرمزية) على دليل ~/.ssh الخاص بالمستخدم وملف authorized_keys.
هذا تقرير فني لثغرة أبلغتُ عنها وتم تخصيص CVE-2026-11837 لها من قبل Red Hat Product Security (بصفتها CNA). تُنشر هنا كسجل فني، وليس كادعاء بالجِدة: فالمشكلة هي شقيقة CVE-2024-9902 في وحدة لم يغطِّها الإصلاح السابق.
إقرار Red Hat المنشور: «تود Red Hat أن تشكر Valentino Paulon على الإبلاغ عن هذه المشكلة.»
عندما يستخدم playbook يعمل بصلاحيات root وحدة ansible.posix.authorized_key لإدارة مفاتيح مستخدم محلي، فإن الدالة المساعدة keyfile() في الوحدة:
~/.ssh الخاص بالمستخدم وملف ~/.ssh/authorized_keys باستخدام os.chown العادي (وليس os.lchown)،open(..., "w") العادي (بدون O_NOFOLLOW).مع القيمة الافتراضية follow=False، لا تقوم الوحدة باتباع الروابط الرمزية واستبدالها ولا ترفضها؛ بل تعمل على المسار مباشرة، لذا يتبع النواة أي رابط رمزي يكون المستخدم المستهدف غير المميّز قد أعدّه مسبقًا داخل دليل ~/.ssh الخاص به. وينتج عن ذلك بدائيتان تنقلان ملكية مسار يتحكم به root إلى المستخدم غير المميّز، الذي يصعّد بعدها إلى صلاحيات root. وقد أُعيد إنتاج كلتيهما من البداية إلى النهاية ضد المجموعة عند HEAD.
الدالة keyfile() (plugins/modules/authorized_key.py)، مع القيم الافتراضية manage_dir=True وfollow=False:
if manage_dir:
if not os.path.exists(sshdir): # os.path.exists FOLLOWS symlinks
try:
os.mkdir(sshdir, int('0700', 8))
...
os.chown(sshdir, uid, gid) # UNCONDITIONAL, plain chown, follows symlink
os.chmod(sshdir, int('0700', 8)) # follows symlink
if not os.path.exists(keysfile): # follows symlink
...
f = open(keysfile, "w") # plain open(), no O_NOFOLLOW, follows symlink
...
try:
os.chown(keysfile, uid, gid) # UNCONDITIONAL, plain chown, follows symlink
os.chmod(keysfile, int('0600', 8)) # follows symlink
except OSError:
pass
يُشتق sshdir وkeysfile من دليل home الخاص بالمستخدم المستهدف في passwd (pwd.getpwnam(user).pw_dir)، وهو دليل يملكه ويتحكم به المستخدم المستهدف غير المميّز. المعامل follow (الافتراضي False) لا يختار سوى ما إذا كان سيتم استدعاء os.path.realpath() على المسار؛ وفي كلتا الحالتين لا يوجد فحص os.path.islink، ولا فتح بـO_NOFOLLOW، ولا os.lchown، ولا إلغاء ربط واستبدال رابط رمزي موجود مسبقًا. لا يتم تنفيذ أي إسقاط للامتيازات (seteuid/setfsuid)؛ كل شيء يعمل بصلاحيات root.
استدعاءا os.chown يعملان بدون شروط، خارج حرّاس if not os.path.exists(...)، لذا يُنفَّذان سواء كان الدليل/الملف موجودًا مسبقًا أم لا. وهذا ما يجعل البدائيتين موثوقتين.
تم تأكيد كلتيهما من البداية إلى النهاية على جهاز افتراضي Linux مؤقت، مع ansible.posix عند HEAD. victim مستخدم محلي غير مميّز (uid 1000). تُشغَّل الوحدة بصلاحيات root، تمامًا كما يشغّلها playbook المشغِّل. تعمل Canaries كنيّابات عن أهداف root الحساسة.
الناقل 1: رابط رمزي للدليل (chown لدليل موجود يملكه root)
victim: ln -s /root/AD_CANARY ~/.ssh (حيث /root/AD_CANARY دليل موجود يملكه root).authorized_key لـvictim./root/AD_CANARY من root:root إلى victim:victim. استدعاء os.chown(sshdir, ...) تبع الرابط الرمزي ~/.ssh وسلّم دليلًا يملكه root إلى المستخدم غير المميّز.الناقل 2: رابط رمزي معلّق لملف (إنشاء + chown لملف جديد في مسار root)
victim (ومع ~/.ssh دليل عادي): ln -s /root/AF_CANARY ~/.ssh/authorized_keys (الهدف غير موجود).authorized_key لـvictim./root/AF_CANARY، بملكية victim:victim، ووضع 0600. أنشأ open(keysfile, "w") الهدف عبر الرابط الرمزي وسلّمه os.chown(keysfile, ...).في كلتا الحالتين ينتهي الأمر بالمستخدم غير المميّز إلى امتلاك مسار يتحكم به root. توجيه الرابط إلى دليل تحت /etc (الناقل 1) أو إلى ملف جديد تحت /etc/cron.d/ أو /etc/sudoers.d/ (الناقل 2) يؤدّي إلى root عبر الخطوة اللاحقة المعتادة، حيث يعيد المستخدم، الذي أصبح الآن المالك، كتابة الهدف.
هذه شقيقة CVE-2024-9902 (دالة generate_ssh_key في وحدة user، ضمن ansible-core)، والذي عالج الفئة نفسها من اتباع الروابط الرمزية. تعيش authorized_key في مجموعة ansible.posix المنفصلة ولم تتغيّر بذلك الإصلاح؛ كان نمط chown/الإنشاء الذي يتبع الروابط الرمزية ما يزال حاضرًا دون حماية. أُبلغ عنها كالفئة المقبولة نفسها في وحدة لم يصلها الإصلاح السابق، وليس كسبب جذري جديد.
ansible.posix.authorized_key تستهدف حساب الضحية (الاستخدام الشائع لهذه الوحدة). يهيّئ المستخدم المحلي الرابط الرمزي مسبقًا داخل ~/.ssh الخاص به؛ وهو لا يشغّل playbook. هذا التفعيل يتم بواسطة المشغِّل: نموذج التفعيل نفسه الخاص بـ CVE-2024-9902، والذي قبلته Red Hat مع التخفيف «لا تشغّل ضد حسابات غير موثوقة». يُذكر الشرط المسبق صراحةً بدلًا من تقييمه كتفعيل ذاتي.os.open(keysfile, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600) واعمل على الواصف؛ وارفض (أو ألغِ الرابط واستبدل، وفق عقد docstring الخاص بـ follow=False) إذا كان sshdir أو keysfile رابطًا رمزيًا.os.chown(...) بـos.lchown، أو بـos.fchown على واصف مفتوح بأمان، وبالمثل os.fchmod بدلًا من os.chmod، بحيث لا يمكن إعادة توجيه الملكية والصلاحيات عبر رابط.chown/chmod غير المشروطَين بحيث ينطبقان فقط على مسار أنشأته الوحدة نفسها للتو بأمان، وليس على مسار موجود مسبقًا (ربما يكون رابطًا رمزيًا).| التاريخ | الحدث |
|---|---|
| 2026-06-08 | أُبلغ إلى [email protected] (مع Red Hat Product Security في CC بصفتها CNA)، كشقيقة لـ CVE-2024-9902 |
| 2026-06-10 | تم تخصيص ونشر CVE-2026-11837؛ قُبل الإشادة |
MIT. انظر LICENSE.
| CVE | CVE-2026-11837 |
| المكوّن | مجموعة ansible.posix، الملف plugins/modules/authorized_key.py، الدالة keyfile() |
| النوع | تصعيد الامتيازات (محلي). CWE-59 / CWE-61 (اتباع الروابط) مع CWE-282 (إدارة ملكية غير سليمة) |
| CVSS | 7.3 (مرتفع) |
| تاريخ النشر | 2026-06-10 |
| أبلغ عنها | Valentino Paulon |