
ورشة عمل CodeQL تغطي CVE-2021-21380
في هذه الورشة سنستخدم التفكير النحوي والدلالي لإيجاد حقن SQL في مكون التقييم الخاص بمنصة XWiki الموثقة في CVE-2021-21380
يرجى إكمال هذا القبل بدء الورشة، إن أمكن.
ثبّت Visual Studio Code.
لا تحتاج إلى تثبيت واجهة سطر الأوامر CodeQL: ستتولى الإضافة ذلك نيابة عنك.
استنسخ هذا المستودع:
git clone https://github.com/advanced-security/codeql-workshop-cve-2021-21380.git
xwiki-platform-CVE-2021-21380.zip في عرض المستكشف واختر الأمر CodeQL: Set Current Database.Cmd/Ctrl+Shift+P)، ابحث عن الأمر CodeQL: Install Pack Dependencies وشغّله.github في المربع لتصفية القائمة.cve-2021-21380-exercises و cve-2021-21380-exercises-tests و cve-2021-21380-solutions و cve-2021-21380-solutions-tests.الورشة مقسمة إلى عدة تمارين تقدم دعم لغة QL لجافا وتنتهي باستعلام نهائي لإيجاد حقن SQL المعروف. في هذه التمارين ستتعلم:
في هذه الورشة سنبحث عن ثغرات حقن SQL المعروفة في مكون واجهة برمجة تطبيقات التقييمات في منصة XWiki. يمكن أن تحدث هذه الثغرات في التطبيقات عندما تصل معلومات يتحكم فيها مستخدم خارجي إلى كود التطبيق الذي ينشئ استعلام SQL بشكل غير آمن وينفذه.
حقن SQL المعروف الذي نناقشه في هذه الورشة مُراجَع في GHSA-79rg-7mv3-jrr5 في قاعدة بيانات استشارات GitHub. لإيجاد حقن SQL والمتغيرات المحتملة، سنتعامل مع المشكلات الفرعية التالية:
في التمارين القليلة الأولى سنفكر في المعلومات النحوية، باستخدام شجرة النحو المجرد (AST)، لتحديد:
ابحث عن جميع الطرق التي تحمل الاسم getAverageRating ونوعها المُصرِّح في البرنامج بإكمال الاستعلام exercise1.ql
java فئة Method لتحليل الطرق في البرنامج.Method المسندات الأعضاء getName و hasName لتحليل اسم الطريقة.Method العضو getDeclaringType لتحليل النوع الذي يُصرِّح بالطريقة.يمكن إيجاد الحل في الاستعلام exercise1.ql
يعيد حل التمرين 1 قائمة من الطرق. بعضها مُعرَّف في واجهة تسمى RatingsManager وبعضها مُعرَّف في الصنفين AbstractRatingsManager و RatingsScriptService.
من المعلومات التي يُعيدها الاستعلام و توثيق مكونات XWiki يمكننا استنتاج أن:
Role، وتنفيذ موضح بـ Component.ScriptService يُجعل متاحًا لصفحات الويكي من خلال البرمجة النصية.ابحث عن جميع الأصناف الموضحة بالتعليق التوضيحي Component بإكمال الاستعلام exercise2.ql.
لاحظ أن الاسم المؤهل بالكامل لنوع التعليق التوضيحي هو org.xwiki.component.annotation.Component.
this في /المسند المميز/.Class طريقة getAnAnnotation للحصول على التعليقات التوضيحية المرتبطة.Annotation المسند العضو getType لتحليل نوعه.Type المسندين الأعضاء getName و hasName لتحليل اسم النوع.RefType، التي تمثل الأصناف والواجهات، المسندين الأعضاء getQualifiedName و hasQualifiedName لتحليل الاسم المؤهل بالكامل لنوع المرجع.يمكن إيجاد الحل في الاستعلام exercise2.ql
ابحث عن جميع المكونات التي تنفذ واجهة ScriptService بإكمال الاستعلام excercise3.ql
Class المسند العضو getASuperType لتحليل الأنواع العليا للصنف، أي الأنواع التي يمتدها (extends) أو ينفذها (implements).يمكن إيجاد الحل في الاستعلام exercise3.ql
في هذه المرحلة حددنا نحويًا الطرق التي يمكن للمستخدم استدعاؤها والتي سنعتبر معاملاتها مصادر للبيانات غير الموثوقة في وقت لاحق من الورشة.
في التمرين التالي سنحقق ونتعرف على المصابين المحتملين. من نتائج التمرين 1 يمكننا استنتاج أن أحد التطبيقات يستدعي الطريقة getAverageRatingFromQuery. باستخدام استعلام مماثل يمكننا إيجاد أنواع المُصرِّحين لـ getAverageRatingFromQuery مما يسمح لنا بتحديد أن التطبيق في الصنف AbstractRatingsManager يُنشئ عبارة SQL التي تُمرر إلى الطريقة search.
الطريقة search مطبقة في تبعية وبالتالي فإن تطبيقها غير متوفر. في التمارين التالية سنستخدم معلومات النوع المتاحة لتحديد استدعاء الطريقة search هذا ونوعها المُصرِّح.
ابحث عن جميع استدعاءات الطرق للطريقة search وحدد نوعها المُصرِّح بإكمال الاستعلام exercise4.ql
MethodCall الوسائل لتحليل استدعاءات الطرق.MethodAcccess المسند العضو getMethod لتحليل هدف استدعاء الطريقة.يمكن إيجاد الحل في الاستعلام exercise4.ql
ابحث عن جميع استدعاءات الطرق للطرق المُصرَّحة من قبل واجهة XWikiStorageInterface (بالاسم المؤهل com.xpn.xwiki.store.XWikiStoreInterface) بإكمال الاستعلام exercise5.ql
يمكن استخدام الكلمة المفتاحية instanceof لبيان أن قيمة تنتمي إلى مجموعة القيم التي يمثلها نوع ما.
على سبيل المثال، لتحديد جميع الاستدعاءات لطرق الواجهات:
import java
from MethodCall ma
where ma.getMethod.getDeclaringType() instanceof Interface
select ma
يمكن إيجاد الحل في الاستعلام exercise5.ql
في هذه المرحلة وصفنا نحويًا المصادر والمصابين المحتملين باستخدام QL. لتحديد ما إذا كانت المعلومات تتدفق بين هذه النقاط في البرنامج سنقوم بتحليل البرنامج دلاليًا باستخدام تتبع التلوث. توفر المكتبات القياسية للغات التي ندعمها آليتين لتدفق البيانات:
DataFlow تدفق المعلومات مع الحفاظ على القيمة.TaintTracking تدفق المعلومات حتى إذا تم تعديل القيم.الأخيرة هي محل الاهتمام، لأنه في ثغرات الحقن مثل حقن SQL من الشائع أن تصبح البيانات غير الموثوقة جزءًا من عبارة أكبر يتم التعامل معها.
في هذه الورشة سنعيد استخدام تكوين تتبع تلوث حقن SQL موجود ونوسعه بمصادرنا ومصابينا النموذجية لإيجاد حقن SQL. لفهم كيف يمكننا توسيع التكوين، نبدأ بالنظر إلى تعريف التكوين أدناه.
class QueryInjectionFlowConfig extends TaintTracking::Configuration {
QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or
node.getType() instanceof BoxedType or
node.getType() instanceof NumberType
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
any(AdditionalQueryInjectionTaintStep s).step(node1, node2)
}
}
يستخدم كل من المسندين isSource و isSink اللذين تستخدمهما التهيئة لتحديد مواقع البرنامج تلك الكلمة المفتاحية instanceof التي رأيناها من قبل. كل من الفئتين RemoteFlowSource و QueryInjectionSink هما فئتين abstract.
هذا نمط شائع ستواجهه في المكتبات القياسية ويسمح لنا هذا النمط بتوسيع مجموعة القيم التي تمثلها فئتا RemoteFlowSource و QueryInjectionSink.
فئة QL تمتد فئة abstract class لا تُحسّن مجموعة القيم التي يمثلها الصنف الأب، بل تضيف القيم التي يمثلها الصنف الفرعي إلى الصنف الأب.
في التمارين التالية سنقوم بتنفيذ هذه الأصناف الفرعية ونبني استعلامنا النهائي.
وسّع مجموعة قيم RemoteFlowSource بمعاملات الطرق العامة للأصناف المكونة التي تم تحديدها في التمرين 3 بإكمال الاستعلام exercise6.ql.
يمكن استخدام الكلمة المفتاحية instanceof لبيان أن قيمة تنتمي إلى مجموعة القيم التي يمثلها نوع ما.
على سبيل المثال، لتحديد جميع الاستدعاءات لطرق الواجهات:
import java
from MethodCall ma
where ma.getMethod.getDeclaringType() instanceof Interface
select ma
يمكن إيجاد الحل في الاستعلام exercise6.ql
وسّع مجموعة قيم QueryInjectionSink بوسائط استدعاءات طرق واجهة التخزين التي تم تحديدها في التمرين 5 بإكمال الاستعلام exercise7.ql
تسمح صيغة exists بإدخال متغيرات مؤقتة يمكن التحليل عنها في نطاق exists.
المثال التالي يستخدم تعبير exists لتقليل مجموعة الطرق إلى الطرق التي تم استدعاؤها.
from Method m
where m.hasName("foo") and exists(MethodCall ma | ma.getMethod() = m)
select m
توفر فئة MethodCall المسند العضو getQualifer لتحليل المُؤهِّل للوصول إلى الطريقة.
يمكن إيجاد الحل في الاستعلام exercise7.ql
اجمع حلولك من التمرين السابق في حل نهائي بإكمال الاستعلام exercise8.ql.
يمكن إيجاد الحل في الاستعلام exercise8.ql
XWikiStoreInterface. وسّع المصاب ليشمل الاستخدامات المباشرة لتطبيق الواجهة. توفر فئة Class المسند العضو extendsOrImplements وتوفر فئة Method المسند العضو overridesOrInstantiates التي قد تساعد.