
أداة تحقق أوتوماتيكية من العيوب لـ 6 ثغرات في dnsmasq (CVE-2026-2291, 4890, 4891, 4892, 4893, 5172)
أداة صندوق أسود آلية للتحقق من 6 ثغرات في dnsmasq (مايو 2026). ترسل حزم هجوم إلى جهاز قيد الاختبار (DUT) وتُبلغ عن نجاح/فشل — بدون الحاجة إلى الوصول إلى الكود المصدري.
# قم بتعيين DNS الخاص بـ DUT إلى عنوان IP للشبكة الواسعة (WAN) للابتوب عبر الواجهة الرسومية أولاً، ثم:
sudo python3 dnsmasq_cve_verify.py --laptop <YOUR_WAN_IP> --dut <DUT_LAN_IP> --dut-pass <SSH_PASS>
# مثال:
sudo python3 dnsmasq_cve_verify.py --laptop 10.0.0.211 --dut 192.168.1.1 --dut-pass '12345Asdf@'
| CVE | CVSS | النوع | ناقل الهجوم | الميزة المتأثرة |
|---|
| CVE-2026-2291 | 9.2 | تجاوز سعة المخزن المؤقت في الكومة (Heap overflow) | عن بُعد | extract_name() — نشط دائمًا |
| CVE-2026-5172 | 7.5 | قراءة خارج الحدود / تعطل | عن بُعد | extract_addresses() — نشط دائمًا |
| CVE-2026-4890 | 7.5 | حلقة لا نهائية (DoS) | عن بُعد | تحليل خريطة بت NSEC (--dnssec) |
| CVE-2026-4891 | 5.3 | قراءة خارج الحدود في الكومة | عن بُعد | التحقق من RRSIG (--dnssec) |
| CVE-2026-4892 | 8.4 | تجاوز سعة الكومة → صلاحية الجذر | محلي/مجاور | CLID الخاص بـ DHCPv6 (--dhcp-script + DHCPv6) |
| CVE-2026-4893 | 5.3 | تجاوز التحقق | عن بُعد | فحص مصدر ECS (--add-subnet) |
السبب الجذري: union bigname يُعلن char name[MAXDNAME] ولكن الأحرف المُستَثناة يمكنها توسيع الاسم إلى 2*MAXDNAME+1 بايت، مما يسبب تجاوزًا للكومة.
طريقة الاختبار: يُرسل استعلامات DNS تحتوي على أسماء نطاقات بأحرف ذات بت عالٍ (0x80+) والتي يتم هروبها داخليًا بصيغة \DDD (4 بايت لكل بايت مدخل). إذا تعطل dnsmasq أو توقف عن الاستجابة، فهو معرض للخطر.
السلوك المُصحَّح: يرفض الأسماء الكبيرة جدًا بأدب (FORMERR/REFUSED) أو يستخدم مخزنًا مؤقتًا موسعًا.
السبب الجذري: حقل rdlen المُزَيَّف يسمح لـ extract_name() بتقديم المؤشر إلى ما بعد نهاية السجل. يؤدي نقص البايتات المتبقية إلى قيمة ضخمة → قراءة خارج الحدود ضخمة → تعطل.
طريقة الاختبار: يُرسل استجابات DNS مع سجلات CNAME حيث rdlen أصغر من الاسم المشفر الفعلي. إذا تعطل dnsmasq، فهو معرض للخطر.
السلوك المُصحَّح: يتحقق من بقاء المؤشر داخل حدود rdlen المُعلنة بعد extract_name().
السبب الجذري: تحليل خريطة بت NSEC يتقدم بمقدار p[1] بدلاً من p[1]+2 (نقص حجم رأس النافذة). مع bitmap_length=0، لا يتقدم المؤشر أبدًا → حلقة لا نهائية.
طريقة الاختبار: يُرسل سجل NSEC مزيفًا مع window=0, bitmap_length=0. إذا توقف dnsmasq عن الاستجابة لجميع الاستعلامات (يعلق، لا يتعطل)، فهو معرض للخطر. يمكن استغلاله قبل التحقق من RRSIG.
السلوك المُصحَّح: يتقدم بمقدار p[1]+2 ويتجاوز الخرائط البتية ذات الطول الصفري.
السبب الجذري: rdlen في RRSIG لم يتم التحقق منه مقابل الحجم الأدنى (18 + اسم المُوَقِّع). طول التوقيع المحسوب يقل تحت الصفر → يُعامَل كقيمة ضخمة → قراءة خارج الحدود.
طريقة الاختبار: يُرسل سجلات RRSIG مع rdlen=10 (أقل بكثير من الحد الأدنى 31+ بايت). تعطل = معرض للخطر.
السلوك المُصحَّح: يتحقق من rdlen >= fixed_fields + signer_name_length قبل حساب طول التوقيع.
السبب الجذري: CLIDs لـ DHCPv6 (حتى 65535 بايت) يتم ترميزها بصيغة ست عشرية عبر sprintf("%.2x") في daemon->packet (5131 بايت). CLID بحجم 3000 بايت → سلسلة ست عشرية بحجم 6000 بايت → تجاوز. عملية المساعد تعمل بصلاحية الجذر.
طريقة الاختبار: يُرسل SOLICIT لـ DHCPv6 مع معرّف عميل بحجم 3000 بايت. يتطلب الاتصال عبر IPv6 وتكوين --dhcp-script. تعطل المساعد = معرض للخطر.
السلوك المُصحَّح: يقتطع أو يتحقق من طول CLID قبل الترميز الست عشري.
ملاحظة: بعض الإصدارات تُجمَّع مع -DNO_DHCP6 ولا تتأثر بهذه الثغرة.
السبب الجذري: process_reply() يمرر طول سجل OPT (~23 بايت) بدلاً من طول الحزمة الكامل إلى check_source(). جميع فحوصات الحدود تفشل → الدالة تعيد دائمًا 1 (صالح).
طريقة الاختبار: يُرسل استعلامات DNS مع خيار EDNS Client Subnet يحتوي على بادئات مصدر مزيفة. إذا قام dnsmasq بإرجاع ECS دون تحقق، فهو معرض للخطر.
السلوك المُصحَّح: يمرر طول الحزمة الكامل إلى check_source()، مما يتيح فحوصات حدود مناسبة وفقًا لـ RFC 7871 القسم 9.2.
الترقية إلى dnsmasq 2.92rel2 (مُوصى بها)
dnsmasq_cve_verify.py)أداة ضمان الجودة الأساسية. تُشغَّل على الابتوب المختبر، وترسل حزم هجوم إلى DUT، وتُبلغ عن نجاح/فشل واضح لكل ثغرة CVE. لا يلزم تعديل DUT أبعد من الوصول عبر SSH للقراءة فقط لفحص الحالة.
┌─────────────────────────────────────────────────────────────────────┐
│ الابتوب المختبر │
│ │
│ واجهة LAN واجهة WAN │
│ <LAPTOP_LAN_IP> <LAPTOP_WAN_IP> │
│ │ │ │
│ │ ┌────┴──────────────┐ │
│ │ │ خادم DNS ضار │ │
│ │ │ (منفذ 53) │ │
│ │ └────┬──────────────┘ │
│ │ │ │
└────────┼───────────────────────────────┼────────────────────────────┘
│ شبكة LAN فرعية │ شبكة WAN فرعية
│ │
┌────────┼───────────────────────────────┼────────────────────────────┐
│ │ │ │
│ LAN: <DUT_LAN_IP> WAN: <DUT_WAN_IP> │
│ (بوابة LAN) (رابط WAN) │
│ │
│ DUT (راوتر Linksys) │
│ dnsmasq (أي إصدار < 2.92rel2) │
│ │
│ resolv-file=/etc/resolv.conf │
│ → nameserver <LAPTOP_WAN_IP> ← يُضبط عبر الواجهة الرسومية، يُمرر إلينا│
│ │
└─────────────────────────────────────────────────────────────────────┘
تدفق البيانات:
1. ترسل الأداة استعلام DNS إلى عنوان IP لـ LAN الخاص بـ DUT (منفذ 53)
2. لا يستطيع dnsmasq الخاص بـ DUT الحل محليًا → يُمرر upstream إلى LAPTOP_WAN_IP
3. خادمنا الضار على واجهة WAN يرد بحمولة هجوم
4. يعالج dnsmasq الخاص بـ DUT الاستجابة الضارة → تعطل/تعليق/نجاة
5. تتحقق الأداة من حالة DUT عبر SSH (للقراءة فقط)
إعداد مثال (عنوان IP الخاص بك سيختلف):
| الدور | IP (مثال) |
|---|---|
| LAN الابتوب | 192.168.1.254 |
| WAN الابتوب | 10.0.0.211 |
| LAN DUT | 192.168.1.1 |
| WAN DUT | 10.0.0.214 |
الشرط الأساسي: يجب أن يكون عنوان IP لـ WAN للابتوب و WAN لـ DUT على نفس الشبكة الفرعية، حتى يتمكن DUT من الوصول إلى الابتوب كخادم DNS upstream.
┌──────────┐ ┌───────────┐ ┌──────────────────┐ ┌──────────┐
│ إعداد │ ──► │ إطلاق │ ──► │ فحص الحالة │ ──► │ الحكم │
│ │ │ │ │ │ │ │
│ ابدأ │ │ أرسل │ │ SSH إلى DUT: │ │ نجاح: │
│ خادم DNS │ │ استعلام │ │ - pidof dnsmasq │ │ نجا │
│ ضار على │ │ DNS إلى │ │ - تغير PID؟ │ │ │
│ واجهة │ │ DUT→DUT │ │ - تعطل في dmesg؟ │ │ فشل: │
│ WAN │ │ يُمرر إلينا│ │ - /var/log/msg │ │ تعطل/ │
│ (10.0.0. │ │ → نرد │ │ │ │ تعليق │
│ 211:53) │ │ بحمولة │ │ استعلام حيوية │ │ │
│ │ │ هجوم │ │ (version.bind) │ │ │
└──────────┘ └───────────┘ └──────────────────┘ └──────────┘
ملاحظة: الأداة لا تُعدِّل إعدادات DUT. يجب على المستخدم ضبط DNS إلى 10.0.0.211 عبر الواجهة الرسومية.
paramiko (pip install paramiko)قم بتوصيل الابتوب المختبر بـ DUT باستخدام كابلين:
| منفذ الابتوب | يتصل بـ | الغرض |
|---|---|---|
| منفذ LAN | منفذ LAN الخاص بـ DUT | وصول SSH + إرسال استعلامات DNS إلى DUT |
| منفذ WAN | شبكة WAN الفرعية لـ DUT (مثل منفذ السويتش/المودم upstream) | يعمل كخادم DNS upstream |
بعد الاتصال، قم بتدوين عناوين IP للابتوب الخاص بك:
# ابحث عن عناوين IP الخاصة بك
ip addr show | grep "inet "
# مثال للمخرجات:
# inet 192.168.1.254/24 ... ← هذا هو عنوان LAN الخاص بك
# inet 10.0.0.211/24 ... ← هذا هو عنوان WAN الخاص بك (استخدمه مع --laptop)
http://192.168.1.1 أو http://myrouter.local10.0.0.211)cd /path/to/dnsmasq-cve-2026/
# تشغيل جميع اختبارات CVE الستة:
sudo python3 dnsmasq_cve_verify.py --laptop <YOUR_WAN_IP> --dut <DUT_LAN_IP> --dut-pass <SSH_PASSWORD>
# مثال:
sudo python3 dnsmasq_cve_verify.py --laptop 10.0.0.211 --dut 192.168.1.1 --dut-pass '12345Asdf@'
ستقوم الأداة بما يلي:
| المشكلة | الإصلاح |
|---|---|
| "DUT لا يُمرر الاستعلامات إلينا" | تحقق من تنفيذ الخطوة 2 بشكل صحيح. تأكد من أن عنوان WAN IP للابتوب يطابق ما أدخلته في الواجهة الرسومية. |
| "لا يمكن الاتصال بـ DUT" | تحقق من بيانات اعتماد SSH. جرب: ssh [email protected] يدويًا. |
| "لا يمكن ربط المنفذ 53" | قم بالتشغيل باستخدام sudo. أو استخدم --dns-port 5353 (يتطلب تكوينًا يدويًا لـ DUT). |
| "الإصدار: غير معروف" | قد لا يكون dnsmasq موجودًا في المسار القياسي على DUT. الأداة لا تزال تختبر بشكل صحيح. |
| CVE | النتيجة | السبب |
|---|---|---|
| CVE-2026-2291 | نجاح | DNSSEC غير مُجمَّع |
| CVE-2026-4890 | نجاح | DNSSEC غير مُجمَّع |
| CVE-2026-4891 | نجاح | DNSSEC غير مُجمَّع |
| CVE-2026-4892 | نجاح | dnsmasq لا يخدم DHCPv6 (يتم استخدام خادم DHCPv6 منفصل) |
| CVE-2026-4893 | نجاح | خطأ منطقي فقط — لا تعطل |
| CVE-2026-5172 | نجاح | نجا من الهجوم (مسار الكود المعرض غير موجود في 2.78) |
| CVE | النتيجة | السبب |
|---|---|---|
| CVE-2026-2291 | نجاح | DNSSEC غير مُجمَّع |
| CVE-2026-4890 | نجاح | DNSSEC غير مُجمَّع |
| CVE-2026-4891 | نجاح | DNSSEC غير مُجمَّع |
| CVE-2026-4892 | نجاح | DHCPv6 غير مُجمَّع |
| CVE-2026-4893 | نجاح | خطأ منطقي فقط — لا تعطل |
| CVE-2026-5172 | نجاح | نجا من متغيرات الهجوم |
جميع راوترات Linksys التي تم اختبارها غير قابلة للاستغلال عمليًا لأي من الثغرات الست في تكوينات الإصدار الإنتاجي. الميزات الخطيرة (DNSSEC، DHCPv6 عبر dnsmasq) إما غير مُجمَّعة أو غير مُهيأة. لا تزال التصحيحات مُوصى بها كحماية متعمقة.
قبل التصحيح (dnsmasq 2.78، بناء بدون DNSSEC):
| CVE | النتيجة | السبب |
|---|---|---|
| CVE-2026-2291 | نجاح | DNSSEC غير مُجمَّع — غير قابل للاستغلال |
| CVE-2026-4890 | نجاح | DNSSEC غير مُجمَّع — غير قابل للاستغلال |
| CVE-2026-4891 | نجاح | DNSSEC غير مُجمَّع — غير قابل للاستغلال |
| CVE-2026-4892 | نجاح/فشل | DHCPv6 مُجمَّع و dhcp-script نشط |
| CVE-2026-4893 | نجاح | خطأ منطقي — لا تعطل (يعتمد على الإصدار فقط) |
| CVE-2026-5172 | نجاح | مسار blockdata_expand غير موجود في 2.78 |
قبل التصحيح (dnsmasq 2.90 مع تمكين DNSSEC):
| CVE | النتيجة | السبب |
|---|---|---|
| CVE-2026-2291 | فشل | تجاوز سعة الكومة عبر أسماء مُستَثناة |
| CVE-2026-4890 | فشل | حلقة لا نهائية (تعلق) |
| CVE-2026-4891 | فشل | تعطل بسبب قراءة خارج الحدود في RRSIG |
| CVE-2026-4892 | نجاح/فشل | يعتمد على DHCPv6 + تكوين البرنامج النصي |
| CVE-2026-4893 | نجاح | خطأ منطقي — لا تعطل |
| CVE-2026-5172 | فشل | قراءة خارج الحدود عبر rdlen مزيف |
بعد التصحيح (dnsmasq 2.92rel2 أو تطبيق التصحيحات من المنبع): جميع الثغرات الست → نجاح
paramiko (pip install paramiko)| العلم | القيمة الافتراضية | الوصف |
|---|---|---|
--laptop | (إلزامي) | عنوان WAN IP للابتوب (يربط خادم DNS الضار هنا) |
--dut | 192.168.1.1 | عنوان LAN IP لـ DUT (تُرسل استعلامات SSH + DNS هنا) |
--dut-user | root | اسم مستخدم SSH لـ DUT |
--dut-pass | (يُطلب) | كلمة مرور SSH لـ DUT |
--dns-port | 53 | المنفذ لخادم DNS الضار |
--cve | جميع الـ 6 | CVE محددة للاختبار (قابلة للتكرار) |
test_dnsmasq_cve_remote.py)فحص إصدار خفيف الوزن فقط — يستعلم عن version.bind لتحديد ما إذا كان إصدار dnsmasq
أقل من الإصدار المُصحَّح. لا حاجة لـ SSH، ولا إعداد، ولا حمولات هجوم.
python3 test_dnsmasq_cve_remote.py 192.168.1.1
test_dnsmasq_cve_on_device.sh)يُشغَّل مباشرة على DUT عبر SSH/منفذ تسلسلي. يتحقق من إصدار الثنائي وخيارات التجميع.
scp test_dnsmasq_cve_on_device.sh [email protected]:/tmp/
ssh [email protected] "sh /tmp/test_dnsmasq_cve_on_device.sh"
malicious_dns_server.py)خادم هجوم مستقل للاختبار اليدوي. قم بتشغيله، ثم وجّه DNS upstream لـ DUT إليه،
ثم أطلق استعلامات إلى crash-5172.evil.test، crash-2291.evil.test، إلخ.
sudo python3 malicious_dns_server.py --port 53
# ثم على DUT: قم بتكوين upstream → هذا المضيف
# ثم أطلق: dig @192.168.1.1 crash-5172.evil.test
بعد تطبيق التصحيحات ووميض البرنامج الثابت الجديد، أعد التشغيل:
sudo python3 dnsmasq_cve_verify.py --laptop <YOUR_WAN_IP> --dut <DUT_LAN_IP> --dut-pass <SSH_PASS>
# المتوقع: جميع الـ 6 نجاح
| الأداة | Python | صلاحية الجذر | SSH | الشبكة |
|---|---|---|---|---|
dnsmasq_cve_verify.py | 3.6+ paramiko | نعم (المنفذ 53) | نعم (للقراءة فقط) | LAN + WAN إلى DUT |
test_dnsmasq_cve_remote.py | 3.6+ stdlib | لا | لا | UDP 53 إلى DUT |
test_dnsmasq_cve_on_device.sh | غير مطلوب (shell) | لا | يُشغَّل على DUT | غير مطلوب |
malicious_dns_server.py | 3.6+ stdlib | نعم (المنفذ 53) | لا | DUT يُمرر إلينا |