
عرض استغلال تعليمي لثغرة حقن SQL CVE-2014-2323 في mod_mysql_vhost الخاص بـ lighttpd، مع مختبر قائم على Docker لتحليل الثغرات وتصحيحها عمليًا.
title: Ep4 - ثغرة متعلقة بالشبكات members:
الثغرة المتعلقة:
CVE-2014-2323 [1] was assigned to SQL injection bug.
CVE-2014-2324 [2] was assigned to the path traversal bug.
تأكيد: http://download.lighttpd.net/lighttpd/security/lighttpd_sa_2014_01.txt
الخدمة المراد استغلالها هي Lighttpd. وهو خادم ويب مفتوح المصدر (رخصة BSD) مُحسَّن ليكون خفيفًا وسريعًا. ظهر كـ 'proof-of-concept' للمشكلة الشهيرة c10k (كيفية التعامل مع 10 آلاف اتصال متزامن على خادم)، واكتسب شعبية كبيرة في ذلك الوقت (2003)، ويُستخدم حاليًا في Whatsapp.com و Xkcd، وسابقًا في Youtube. وضعه في السوق مثير للاهتمام، كما نرى في الرسم البياني:

يسعى الخادم إلى التعامل مع مشكلة الاتصالات العديدة من خلال استخدام آليات غير متزامنة عبر الأحداث (kqueue في BSDs، epoll في Linux) مما يقلل الحاجة إلى خيوط متعددة، وينتج عنه بصمة ذاكرة أصغر بكثير واستخدام أفضل لوحدة المعالجة المركزية (استراتيجية تُستخدم أيضًا بواسطة خوادم Nginx، التي زاد استخدامها بشكل ملحوظ على مر السنين):

إحدى ميزات lighty هي سهولة إدارة الاستضافة الافتراضية.
هي طريقة تُستخدم لاستضافة أكثر من اسم نطاق يتم حله إلى نفس عنوان IP، مما يقلل تكاليف الاستضافة للشركات التي تقدم مواقع ويب، حيث لا حاجة لحجز خادم مخصص لكل موقع.
يمكن أن تعتمد التقنية على IP (واجهة لكل مضيف) أو على الاسم (اسم لكل مضيف، بمشاركة الواجهة) - وهي المستخدمة في هذا العرض.
Name-Based
: يستخدم 'Hostname' الذي يوفره العميل لتحديد الخدمة التي سيتم الرد بها وفقًا لذلك. تواجه هذه الطريقة صعوبتين: تعقيدات في التعامل مع الجلسات الآمنة (TLS) - يجب إجراء المصافحة قبل تمرير أي رأس يشير إلى المضيف للخادم، مما يعقّد تحديد الشهادة الصحيحة لتقديمها أثناء المصافحة. أحد الحلول لهذه المشكلة هو امتداد لـ TLS يسمى Server Name Indication (SNI) والذي يسمح بتقديم الاسم في بداية المصافحة، مما يتيح اختيار الشهادة الصحيحة. المشكلة الثانية تتعلق بمحاولة الاتصال بدون رأس Host محدد جيدًا، مما يؤدي إلى عدم تحديد الخدمة التي سيتم استخدامها.
IP-Based
: يستخدم عناوين IP منفصلة لكل تطبيق. يتم بعد ذلك تكوين خادم الويب لواجهات شبكة متعددة (مادية أو افتراضية تحت نفس الواجهة) ومن ثم الرد بشكل مطابق وفقًا لعنوان IP الوجهة.
*IP aliasing*، يسمح لنا بإنشاء واجهات افتراضية لكل خدمة.
في حالة وجود شركة كبيرة، قد يصبح إدارة هذا التعيين معقدًا اعتمادًا على عدد العملاء. يقدم Lighty دعمًا لاستخدام قاعدة بيانات لهذا الغرض كما سنوضح لاحقًا.
قبل ذلك، دعنا نرى كيفية إعداد خادم يدويًا ثم إضافة استضافة افتراضية.
إعداد خادم أساسي lighttpd سهل جدًا.只需 تثبيته وإنشاء ملف تكوين يحدد المنفذ الذي سيتم استخدامه، وكيفية الرد على طلبات معينة، وإعدادات أخرى.
يمكننا إعداد مثال لتكوين يتعامل فقط مع استقبال طلبات الملفات الثابتة (.html أو .txt):
server.document-root = "/usr/lighttpd/mysite.com/"
server.port = 80
mimetype.assign = (
".html" => "text/html",
".txt" => "text/plain"
)
تخيل الآن أننا نريد إنشاء عمل تجاري قائم على بيع المواقع ونقدم نطاقًا خاصًا للمشتري. بهدف تقليل التكاليف، نريد استخدام إنشاء vhosts لكل عميل. لنفترض أن دورة مادة الشبكات تريد شراء ثلاثة مواقع: redes.io و mac0448.io و mac5910.io. تقوم شركتنا بتسجيل النطاقات، وكلها تشير إلى IP خادمنا الوحيد ذي الواجهة الواحدة.
ملاحظة: لمحاكاة ذلك يمكننا تعديل ملف /etc/hosts:
172.17.0.2 redes.io
172.17.0.2 mac0448.io
172.17.0.2 mac5910.io
لكي نتمكن من خدمة المواقع المختلفة للعملاء من خلال حل عنوان IP واحد، يمكننا يدويًا تكوين الخادم:
server.document-root = "/usr/lighttpd/default/"
server.port = 80
mimetype.assign = (
".html" => "text/html",
".txt" => "text/plain"
)
$HTTP["host"] == "redes.io" {
server.document-root = "/usr/lighttpd/redes/"
} else $HTTP["host"] == "mac0448.io" {
server.document-root = "/usr/lighttpd/mac0448/"
} else $HTTP["host"] == "mac5910.io" {
server.document-root = "/usr/lighttpd/mac5910/"
}
لكن، كما يمكننا أن نتخيل، قد يصبح هذا مشكلة مع زيادة عدد العملاء وتقديم إعدادات مختلفة لكل موقع كما ذكرنا سابقًا.
مع الوحدة النمطية mod_mysql_vhost يمكننا توصيل خادمنا بقاعدة بيانات mysql مسؤولة عن هذا التعيين. نحدد اسم قاعدة البيانات، وكيفية العثور عليها في شبكتنا، والأمر الذي سيتم استخدامه لإجراء البحث.
server.modules = (
"mod_accesslog",
"mod_mysql_vhost"
)
mysql-vhost.db = "NOME_DO_BANCO"
mysql-vhost.user = "USUARIO"
mysql-vhost.pass = "SENHA"
(!!!!!!!!!!!!!!!)
mysql-vhost.sql = "SELECT docroot FROM domains WHERE domain='?';"
(!!!!!!!!!!!!!!!)
mysql-vhost.hostname = "HOSTNAME"
mysql-vhost.port = "PORTA"
SQL هي لغة تعريفية لإدارة قواعد البيانات العلائقية، تُستخدم (...) إلخ
TODO
TODO
تنشأ المشاكل من حقيقة أن أنظمة إدارة قواعد البيانات التي تستخدم SQL تفترض أن الأوامر المدخلة ستكون أوامر يعرفها المدير ويديرها جيدًا. هذا الافتراض ليس صحيحًا دائمًا، حيث أن الفشل في الأنظمة التي تتفاعل مع نظام قاعدة البيانات قد يظهر ثغرات، خاصة على الويب، حيث يكون التفاعل مع المستخدم كبيرًا.
تظهر المشكلة مع أوامر SQL عندما يتم بناء الأوامر باستخدام نصوص من المستخدم، سواء كان اسم مستخدم أو كلمة مرور أو أي محتوى ديناميكي آخر.
(TODO)
كيف نحل المشكلة؟ التهريب (Escaping).
في تكويننا مثلاً، لدينا ثغرة كبيرة:
mysql-vhost.sql = "SELECT docroot FROM domains WHERE domain='?';"
لأنه من المحتمل (وهذا ما كان يحدث حتى الإصدار 1.4.34) أن يتم استبدال ? بأي أمر وتنفيذه بواسطة MySQL.
لنحاكي هذا في شبكة تحتوي على 3 حاويات: خادم MySQL واحد وخادمي Lighttpd، أحدهما ضعيف والآخر مُصحَّح.
يوفر Docker طبقة تجريد فوق نظام التشغيل تسمح بالافتراضية دون الحاجة إلى نظام تشغيل آخر من خلال استخدام آليات العزل التي يوفرها النواة، مثل cgroups (عزل استخدام وحدة المعالجة المركزية، الإدخال/الإخراج، الذاكرة، واستخدام الشبكة لمجموعة من العمليات) و namespaces ()، مما يزيل كل الحمل الزائد لبدء وتشغيل آلة افتراضية. وبالتالي، هناك تحسين كبير في تخصيص الموارد (على سبيل المثال، 100 آلة افتراضية بصور 1GB ==> 100GB؛ 100 حاوية من صورة 1GB ==> ~1GB) ومشاركة المعالجة، بالإضافة إلى النواة ونظام التشغيل نفسه. يمكن أيضًا مشاركة الملفات الشائعة بين الحاويات من خلال نظام ملفات متعدد الطبقات.

تشبيه مثير للاهتمام لـ namespaces هو chroot، الذي يسمح لعملية ما برؤية دليل كجذر لنظام الملفات بالكامل، مما يغير منظورها للنظام (بدون تغيير باقي النظام). مع namespaces يمكننا إنشاء هذا المنظور المميز لجوانب أخرى من نظام التشغيل، مثل شجرة العمليات، واجهات الشبكة، نظام الملفات، IPC، وغيرها.