"مرحبا ، Checkmarx!" كيفية كتابة طلب Checkmarx SAST والعثور على نقاط الضعف باردة



مرحبا يا هبر!

في المقالة أريد أن أتحدث عن تجربتنا في إنشاء استفساراتي في Checkmarx SAST.

عندما تتعرف على هذا المحلل لأول مرة ، قد تترك انطباعًا أنه بالإضافة إلى البحث عن خوارزميات تشفير / تجزئة ضعيفة وكومة من الإيجابيات الخاطئة ، فإنها لا تُرجع أي شيء آخر. ولكن عندما يتم تهيئتها بشكل صحيح ، فهي أداة قوية للغاية يمكنها البحث عن أخطاء خطيرة.

سوف نفهم تعقيدات لغة الاستعلام Checkmarx SAST ونكتب استفساريين للبحث عن حقن SQL ومراجع Insecure Direct Object.


دخول


بعد بحث طويل عن أي أدلة أو مقالات حول Checkmarx ، أصبح من الواضح لي أنه إلى جانب الوثائق الرسمية ، لم تكن هناك معلومات مفيدة كافية. والوثائق الرسمية لا تقول أن كل شيء أصبح واضحا ومفهوما للغاية. على سبيل المثال ، لم أتمكن من العثور على أفضل الممارسات ، وكيفية تنظيم استعلامات التجاوز بشكل صحيح ، وكيفية كتابة استعلام "للدمى" ، وما إلى ذلك. نعم ، هناك وثائق حول وظائف CMx Query Language ، ولكن إليك كيفية دمج هذه الوظائف في استعلام واحد ، الوثائق ليست مكتوبة.

ربما يرتبط نقص المقالات والأدلة من مجتمع Checkmarx بالتكلفة العالية للأداة ونتيجة لذلك ، جمهور صغير. أو ربما فقط عدد قليل من الناس يهتمون بالصقل ويستخدمون الحل كما هو ، خارج الصندوق.

في تجربتي ، أرى أن SAST يُستخدم أكثر للامتثال للإجراءات المتعلقة بالمتطلبات المختلفة من جانب العملاء بدلاً من البحث عن الأخطاء الحقيقية. مع هذا النهج ، كنتيجة ، في أحسن الأحوال ، لدينا عدد صغير نسبيًا من "نقاط الضعف" ، والتي تُعرف تلقائيًا تقريبًا باسم "غير قابلة للاستغلال" (لأنها موجودة في 99.9٪ من الحالات).

تجدر الإشارة إلى أن Checkmarx أنفسهم يحاولون تحديث استعلاماتهم حتى يقدموا أفضل النتائج من الصندوق. ولكن تم تصميم استعلامات لغة استعلام CMx وفقًا "للحالة العامة". البحث الأولي عن الرموز يستند الاسم. على سبيل المثال ، يفترض CMx SAST أن جميع الاستعلامات إلى قاعدة البيانات ستبدو كما يلي: * createQuery * أو * createSQLQuery *. ولكن إذا تم استخدام التطوير الداخلي للعمل مع قاعدة البيانات ، وطريقة الاستعلام عن قاعدة البيانات تسمى بشكل مختلف ، على سبيل المثال * driveMyQuery * ، فسيتم تخطي جميع أساليب SQL. على سبيل المثال ، يستخدم عملائنا ORM مخصص لـ SQL DB. في هذه الحالة ، تخطت استعلامات CMx خارج المربع جميع عمليات حقن SQL.

الاختصارات والتعاريف


CMx - Checkmarx SAST.
CMxQL - Checkmarx SAST لغة الاستعلام
الرمز - سلسلة ذات قيمة معينة هي نتيجة عمل المحلل اللغوي (والذي يسمى أيضًا الرمز المميز )

تطبيق الاختبار


لكتابة مقال ، قمت برسم بعض رموز Java ، وهو تطبيق اختبار صغير. هذا الرمز هو نسخة تقريبية لجزء صغير من النظام الحقيقي. على الرغم من أن رمز تطبيق الاختبار لا يختلف بشكل عام عن أي كود آخر للواجهة الخلفية HTTP. ستكون الأقسام الرئيسية لرمز تطبيق الاختبار مرئية في لقطات الشاشة.

تطبيق الاختبار لديه الهيكل التالي


فئة WebRouter لمعالجة طلبات HTTP الواردة ؛ 4 طرق لمعالجة عناوين URL في الداخل:
  • / getTransaction - يقبل معرّف المعاملة عند الإدخال وإرجاع المعلومات الموجودة عليه ، يأخذ id المعرف كسلسلة ، ويمرره إلى getTransactionInfo (transactionId) => getTransactionInfo (transactionoinId) - يجعل المعاملة متسلسلة إلى استعلام SQL (بمعنى ، يتم الحصول على حقن SQL) ؛
  • / getSecureTransaction - يقبل معرّف المعاملة كمدخلات وإرجاع المعلومات الموجودة عليها ، يأخذها id كسلسلة ويمررها getTransactionInfoSecured () => getTransactionInfoSecured (transactionoinId) - يقوم أولاً بإلقاء المعاملة stringId بالكتابة طويلة ، ثم يسلسلها إلى استعلام SQL (في هذا إذا لم يتم استغلال الحقن) ؛
  • / getSettings - يقبل userId و mailId كمدخل - ويصدر إعدادات صندوق البريد. لا يتحقق من أن معرف البريد ينتمي إلى المستخدم ؛
  • / getSecureSettings - يقبل أيضًا userId و mailId إلى الإدخال ويعرض إعدادات صندوق البريد. ولكن يتحقق أن علبة البريد ينتمي إلى المستخدم.


CMx: معلومات عامة وتعريفات أساسية


قبل البدء في تطوير الاستعلامات


يتم تنفيذ الاستعلام في برنامج منفصل CxAuditor. في CxAuditor ، تحتاج إلى مسح جميع الشفرات (إنشاء مشروع محلي) ، والتي سنكتب الاستعلامات من أجلها. بعد ذلك ، يمكنك كتابة وتشغيل استعلامات جديدة. مع وجود قاعدة رمز كبيرة ، يمكن أن يستغرق المسح الرئيسي ساعات من الغيغابايت من الذاكرة. بعد ذلك ، لن يتم تنفيذ كل طلب بسرعة كافية. هذا غير مناسب تمامًا للتنمية.

لذلك ، يمكنك أن تأخذ مجموعة صغيرة من الملفات من المشروع ، من الناحية المثالية مع وجود خطأ في الكود مقدمًا من النوع الذي نكتب به طلبًا (أو وضع الخلل هناك يدويًا) وفحص مجموعة الملفات هذه فقط. ليس من الضروري الالتزام بهيكل ملف المشروع. أي إذا كان لديك حزمة Java A و B ، وكانت الفئات الموجودة في الحزمة B تستخدم الفئات وطرق الحزمة A ، يمكنك وضع كل هذا في دليل واحد ، وسيظل CMx يفهم العلاقات وسيبني سلاسل الاتصال بين الملفات بشكل صحيح (جيد ، أو تقريبًا دائمًا ما يكون صحيحًا ، على الرغم من أن الأخطاء بالكاد مرتبطة بهيكل ملف المشروع).

التعاريف الأساسية


CxList


نوع البيانات الرئيسي في CMx. ستكون نتيجة جميع وظائف CMxQL تقريبًا CxList . هذا هو الكثير من العناصر مع خصائص معينة. سيتم النظر في الخصائص الأكثر فائدة للتطوير أدناه.

يؤدي


CMxQL له نتيجة متغير مضمنة. سيتم عرض المجموعة التي تحتوي على متغير النتيجة ، بعد تنفيذ الاستعلام بالكامل كنتيجة.

بمعنى أن العملية النهائية لأي استعلام يجب أن تكون نتيجة السلسلة = WHATEVER ، على سبيل المثال:
result = All.FindByName("anyname"); 

تدفق ورمز عنصر


تنقسم معظم وظائف CMxQL حسب نوع القيم التي يتم إرجاعها إلى 2 ، تلك التي تُرجع "عناصر التعليمات البرمجية" وتلك التي تُرجع التدفق. في كلتا الحالتين ، تكون النتيجة قائمة CxList . لكن محتواه سيكون مختلفًا قليلاً عن عناصر التدفق والكود.
  • رمز عنصر - رمز - على سبيل المثال ، متغير ، استدعاء الأسلوب ، الواجب ، إلخ.
  • تدفق - العلاقة بين الرموز المعطاة.


الكل و "الفرعي" الكل


يمكن تنفيذ كل وظيفة من وظائف CMxQL إما على مجموعة الكل (تحتوي على جميع الرموز المميزة للرمز الذي تم مسحه ضوئيًا بالكامل ، وقد شاهدنا بالفعل مثالًا بالنتيجة ) أو على مجموعة CxList ، والتي تم الحصول عليها بدورها كنتيجة لبعض العمليات في الاستعلام ، على سبيل المثال ، الاستعلام:
 CxList newList = CxList.New(); 

سيقوم بإنشاء مجموعة فارغة ، والتي يمكننا عندها ملء العناصر باستخدام طريقة Add () ، ثم البحث بالفعل عن طريق عناصر المجموعة الجديدة:
 CxList newFind = newList.FindByName("narrowedScope"); 

خصائص العناصر التي تم العثور عليها


كل عنصر من عناصر مجموعة CxList له عدة خصائص. عند تحليل النتائج لكتابة الاستعلامات ، فإن الأكثر فائدة هي:

  • SourceFile - اسم الملف الذي يحتوي على هذا العنصر ؛
  • مصدر الخط - رقم السطر مع الرمز ؛
  • اسم المصدر - اسم الرمز المميز. أي ما يعادل الرمز المميز ، أي إذا كان المتغير يسمى var1 ، ثم اسم المصدر = var1 ؛
  • نوع المصدر - نوع الرمز المميز. على سبيل المثال ، إذا كانت عبارة عن سلسلة ، فستكون StringLiteral ، إذا تم استدعاء الطريقة ، ثم MethodInvokeExpr ، وغيرها الكثير ؛
  • ملف الوجهة
  • خط الوجهة
  • اسم الوجهة
  • نوع الوجهة.


سيكون المصدر والوجهة مختلفين إذا كانت عناصر مجموعة النتائج هي Flow ، والعكس صحيح سوف يتطابقان إذا كانت النتيجة هي عناصر الكود.

ابدأ في إنشاء استعلامات


يمكن تقسيم جميع وظائف CMxQL إلى عدة أنواع. هنا ، في رأيي ، يمكن للمرء ملاحظة العيب الرئيسي لوثائق CMxQL ، يتم وصف جميع الوظائف في قفص الاتهام ببساطة حسب الترتيب الأبجدي ، في حين أنه سيكون أكثر ملاءمة لهيكلها وفقا للوظيفة وبعد ذلك فقط حسب الترتيب الأبجدي.

  • وظائف البحث - جميع وظائف CMxQL تقريبًا باسم FindBy * و GetBy * ؛
  • وظائف العمليات على المجموعات هي الجمع والطرح والتقاطع والتكرار على العناصر ، إلخ.
  • وظائف التحليل - هذه هي أساسا * InfluencedBy * * InfluencingOn * وظائف.


المبدأ الأساسي للاستعلامات هو تناوب هذه الأنواع من الوظائف. أولاً ، باستخدام وظائف البحث ، نختار فقط الرموز المميزة التي تهمنا بخصائص معينة. باستخدام العمليات على المجموعات ، يمكننا دمج مجموعات مختلفة مع خصائص الرمز المميز المختلفة في واحدة ، أو العكس ، طرح الأخرى من واحدة. ثم ، باستخدام وظائف التحليل ، نقوم ببناء Code Flow ونحاول أن نفهم ما إذا كانت نقاط الضعف المحتملة تعتمد على المعلمات في نقاط الدخول.

يعتمد اختيار المكان الذي تبدأ منه عملية البحث ، وبشكل عام مسار البحث بالكامل ، على الكود المحدد ، وبشكل أكثر دقة ، حتى على "النص". في بعض الحالات ، يكون من المناسب البحث عن استفسارات المستخدم من نقطة الإدخال ، وفي بعض الحالات يكون من الملائم البدء من "النهاية" أو حتى من الوسط. كل هذا يتوقف على كود معين وتحتاج إلى التعامل مع كل مستودع على حدة.

مثال: بحث حقن SQL


خطة البحث ، بين قوسين أشرت إلى اسم المجموعات (المتغيرات في الاستعلام):

  1. تحديد الاستثناءات - الرموز المميزة التي يمكن طرحها على الفور من نطاقات البحث ( exclusionList ) ؛
  2. تحديد موقع عمليات التعقيم / الفحص الأمني ​​( التعقيم ) ؛
  3. العثور على جميع الأماكن ذات المستوى المنخفض مع تنفيذ الاستعلام في قاعدة البيانات ( runSuperSecureSQLQuery ) ؛
  4. العثور على جميع المعلمات من أساليب تسمى runSuperSecureSQLQuery ( runSSSQParams ) ؛
  5. البحث عن نقاط الإدخال (الطرق الرئيسية والمعلمات الخاصة بها) لأماكن تنفيذ الاستعلام في قاعدة البيانات ( entryPointsParameters ) ؛
  6. ابحث عن تبعيات معلمات runSSSQParams على entryPoints ، بينما فقط تلك الأماكن التي لا يوجد فيها مطهر لتعقيم المدخلات.


نتيجة لذلك ، حصلنا على أساليب منخفضة المستوى مع استعلامات SQL ، حيث معلمات استعلام SQL:

  • تعتمد على معايير الأسلوب ؛
  • يتم قبول المعلمات سلاسل.
  • المعلمات متسلسلة للطلب.

لن نتحقق مما إذا كنا نستطيع التحكم في هذه المعلمات ، مثل نعتقد أن هناك آلية لتعيين المتغيرات في استعلام وهناك نوع معين من الأرقام للأرقام ، ويعتبر تسلسل السلسلة دائمًا خطيرًا. حتى لو لم يكن هناك سيطرة على الخط الآن ، فقد يظهر جيدًا في الإصدار الجديد.

SQLi: الخطوة 1. تحديد الاستثناءات


في حالات الاستثناء ، تحتاج إلى إضافة هذه الفئات أو الملفات حيث يمكن أن تتطابق أسماء الرمز المميز مع تلك التي تبحث عنها ، لأن ستؤدي هذه الرموز المميزة إلى إدخالات غير صالحة.

على سبيل المثال ، تسمى طريقة الوصول إلى قاعدة البيانات runSuperSecureSQLquery . نحن نفترض أن طريقة runSuperSecureSQLquery بالداخل يتم تنفيذها بأمان. ومهمتنا هي العثور على أماكن ليس فيها استخدام الطريقة نفسها بأمان. بالنسبة لحقن SQL ، لن تكون أماكن تسلسل المعلمات التي يتحكم فيها المستخدم أماكن آمنة. والأمان - أماكن لتعيين المعلمات في بنية ORM أو ، على سبيل المثال ، للمعلمات العددية ، وهذا هو يلقي نوع من المقابلة. لا نحتاج إلى مسح جميع الشفرات التي تقع "أعمق" من runSuperSecureSQLquery ، مما يعني أنه من الأفضل استبعادها لتجنب اكتشافات غير مجدية.

للبحث عن هذه الاستثناءات ، من الملائم استخدام وظائف CMxQL:
  • FindByFileName () - سيجد مجموعة الرموز المميزة في ملف معين ؛
  • سوف GetByClass () - العثور على مجموعة من كافة الرموز المميزة في الفئة بالاسم المحدد.


بالنسبة لتطبيق الاختبار ، فإن هذا الاستثناء هو فئة الجلسة التي تحتوي على تطبيق أسلوب runSuperSecureSQLquery .
مثال على طلب لاستثناء التعليمات البرمجية في فئة الجلسة (طريقة GetByClass () ستحقق من الرموز المميزة التي تم تمريرها إلى الإدخال بنوع CMx من ClassDecl وستصدر الكثير من الرموز المميزة لهذه الفئة)

 CxList exclusionList = All.GetByClass(All.FindByName("*Session*")); result = exclusionList; 


أو طريقة أخرى هي رمي التعليمات البرمجية في ملف Session.java بأكمله:

 CxList exclusionList = All.FindByFileName("*Session.java"); result = exclusionList; 


العلامة النجمية قبل الاسم مهمة ، لأن اسم الملف يتضمن المسار بالكامل.
الآن لدينا العديد من الرموز التي يمكن طرحها في الخطوات التالية من نطاق البحث.

نتيجة البحث عن الرموز داخل فئة الجلسة :



SQLi: الخطوة 2. تحديد أماكن التعقيم


هناك طريقتان API في تطبيق الاختبار (انظر وصفًا موجزًا ​​لتطبيق الاختبار). يتمثل الاختلاف بين طريقتي API في أن getTransactionInfo () يسلسل المعلمة TransactionId في استعلام SQL ، ويقوم getTransactionInfoSecured () أولاً بتحويل TransactionId إلى Long ، ثم تمريره كسلسلة. يتم تضمين مشكلة عدم الحصانة (تسلسل المعلمة) في كلا الأسلوبين. ولكن بفضل cast to Long في getTransactionInfoSecured () ، فإن الطريقة الأخيرة ليست عرضة للحقن ، لأننا عندما نحاول اجتياز حقنة (سلسلة) نحصل على استثناء Java.

في هذا المثال ، سوف نعتبر فريق Cast "Long" موقع الصرف الصحي. للعثور على هذه الرموز:

 CxList sanitization = All.FindByName("*Long*"); result = sanitization; 


مثال النتيجة:



تم تضمين النتيجة مع الرموز المميزة مع YP type Long و getValueAsLong ، والتي تقوم داخليًا بتحويل القيمة إلى النوع Long . تحتاج إلى مراجعة النتيجة بعناية للتأكد من عدم وجود شيء لا لزوم له.

SQLi: الخطوة 3. العثور على جميع الأماكن ذات المستوى المنخفض مع تنفيذ الاستعلام في قاعدة البيانات


سيجد الاستعلام التالي جميع الأماكن باستخدام الرمز المميز runSuperSecureSQLQuery (والذي يستخدم للوصول إلى قاعدة البيانات):

 result = All.FindByName("*runSuperSecureSQLQuery*") 

نتائج البحث حسب الاسم المميز runSuperSecureSQLQuery:


علاوة على ذلك ، بالنسبة للأماكن التي تسمى هذه الطريقة (فئة الفوترة ) ، سيتم العثور على الرموز المميزة لاستدعاء الطريقة فقط (النوع MethodInvokeExpr ) ، وبالنسبة إلى مكان إعلان الطريقة (فئة الجلسة ) ، سيتم العثور على جميع الرموز المميزة - المتغيرات أيضًا.

نقوم بتصفية الرموز المميزة للاتصال فقط:

 CxList runSuperSecureSQLQuery = All.FindByName("*runSuperSecureSQLQuery*").FindByType(typeof(MethodInvokeExpr)); result = runSuperSecureSQLQuery; 

النتيجة:


نتيجةً لذلك ، حصلنا على 7 أماكن ، 4 منها هي المكالمات المطلوبة إلى طريقة runSuperSecureSQLQuery () (فئات الفوترة والمستخدم ). 2 - يستدعي الأسلوب الداخلي runSuperSecureSQLQuery () داخل فئة الجلسة ، والأخرى هي طريقة الإضافة ، وهي نوع من الغرابة في بحث CMxQL. دعنا نقول فقط أنني لم أكن أتوقع أن تكون في القائمة =) الرموز في فئة الجلسة ، كما اكتشفنا في الخطوة 1 ، ليست مثيرة للاهتمام بالنسبة لنا ، لذلك سنقوم ببساطة بطرحها من النتيجة:

 CxList runSuperSecureSQLQuery = All.FindByName("*runSuperSecureSQLQuery*").FindByType(typeof(MethodInvokeExpr)); result = runSuperSecureSQLQuery - exclusionList; 

نحصل على قائمة صالحة للمكالمات بالطريقة المطلوبة:



لاحظ وظائف FindByType () و typeof () في الاستعلام السابق. إذا كنا نريد البحث حسب نوع CMx ، أي حسب خاصية CxList "نوع المصدر" - فإننا نستخدم typeof (نوع المصدر) . إذا كنا نريد إجراء بحث حسب نوع البيانات ، فسنحتاج إلى تمرير المعلمة كسلسلة. على سبيل المثال:

 result = All.FindByType("String"); 

سوف تجد جميع الرموز جافا مع نوع سلسلة.

SQLi: الخطوة 4. العثور على جميع المعلمات من runSuperSecureSQLQuery دعا الأساليب


للبحث عن معلمات الطريقة ، يتم استخدام الدالة CMxQL GetParameters () :

 CxList runSSSQParams = All.GetParameters(runSuperSecureSQLQuery); result = runSSSQParams; 

النتيجة:



SQLi: الخطوة 5. ابحث عن نقاط إدخال مواقع تنفيذ الاستعلام في قاعدة البيانات


للقيام بذلك ، أولاً نحصل على أسماء الأساليب الأصل ، والتي هي داخلها المكالمات إلى قاعدة بيانات runSuperSecureSQLQuery ، ثم نحصل على معلماتها. للبحث عن الرموز الرئيسية ، يتم استخدام الدالة CMxQL GetAncOfType () :

 CxList entryPoints = runSuperSecureSQLQuery.GetAncOfType(typeof(MethodDecl)); result = entryPoints; 


في هذا الاستعلام ، لمجموعة runSuperSecureSQLQuery ، قم بإرجاع كافة الرموز المميزة الأصلية من النوع MethodDecl - هذه هي الطريقة السابقة في مكدس الاستدعاءات:



للبحث عن معلمات الطريقة ، نستخدم أيضًا GetParameters () :

 CxList entryPointsParameters = All.GetParameters(entryPoints).FindByType("String"); 


سيقوم الاستعلام بإرجاع معلمات مجموعة فرعية من pointPoints بنوع Java String:



SQLi: الخطوة 6. ابحث عن تبعيات معلمات runSSQParams على entryPointsParameters ، بينما تلك الأماكن التي لا يوجد فيها إدخال إدخال التعقيم فقط


في هذه الخطوة ، نستخدم وظائف التحليل. تستخدم الوظائف التالية لتحليل كود التدفق:

  • InfluencedBy ()
  • المؤثرات ByNandNotSanitized ()
  • التأثير على ()
  • التأثير على UnNotSanitized ()
  • NotInfluencedBy ()
  • NotInfluencingOn ()


للعثور على معلمات طلب Flow of runSSSQParams اعتمادًا على معلمات الأسلوب الأصل entryPointsParameters واستبعاد الرموز المميزة للصرف الصحي:

 CxList dataInflOnTable = runSSSQParams.InfluencedByAndNotSanitized(entryPointsParameters, sanitization); 


ومع ذلك ، لست متأكدًا مما إذا كانت وظائف * AndNotSanitized بداخلها تقوم ببعض السحر ، ويبدو الأمر أشبه بالطريقة التي تطرح بها المجموعة المطهرة من نتيجتها . هذا هو ، إذا كنت تفعل:

 CxList dataInflOnTable = runSSSQParams.InfluencedBy(entryPointsParameters) - sanitization; 


اتضح نفس الشيء. على الرغم من أنني ربما لم أجد خيارًا عندما لا تزال هناك اختلافات.

تمنحك نتيجة الاستعلام تدفقًا تم إنشاؤه بشكل صحيح:



حصلت على تدفق مع حقن SQL المحتملة. كما يتبين من لقطة الشاشة ، عاد Checkmarx 3 Flow. التدفق في لقطة الشاشة هو الأقصر ، فهو يبدأ وينتهي في ملف واحد وطريقة واحدة. تدفق التالي يترك بالفعل في فئة الدورة. إيلاء الاهتمام لمصدر / الوجهة. وآخر واحد هو طريقة أخرى في فئة الجلسة. سوف يبدو التدفق داخل الجلسة كما يلي:



لتحديد تدفق واحد ، يتم استخدام طريقة ReduceFlow (CxList.ReduceFlowType flowType) ، حيث يمكن أن يكون flowType:

  • CxList.ReduceFlowType.ReduceBigFlow - حدد أقصر التدفق
  • CxList.ReduceFlowType.ReduceSmallFlow - حدد أطول تدفق


SQLi: الاستعلام النهائي للعثور على حقن SQL


 // 1.   CxList exclusionList = All.GetByClass(All.FindByName("*Session*")); // 2.    CxList sanitization = All.FindByName("*Long*"); // 3.    runSuperSecureSQLQuery() CxList runSuperSecureSQLQuery = All.FindByName("*runSuperSecureSQLQuery*").FindByType(typeof(MethodInvokeExpr)); runSuperSecureSQLQuery -= exclusionList; // 4.     runSuperSecureSQLQuery() CxList runSSSQParams = All.GetParameters(runSuperSecureSQLQuery); // 5.   ,     runSuperSecureSQLQuery() CxList entryPoints = runSuperSecureSQLQuery.GetAncOfType(typeof(MethodDecl)); CxList entryPointsParameters = All.GetParameters(entryPoints).FindByType("String"); // 6.       (runSuperSecureSQLQuery)     CxList dataInflOnTable = runSSSQParams.InfluencedByAndNotSanitized(entryPointsParameters, sanitization); // 7.   result = dataInflOnTable.ReduceFlow(CxList.ReduceFlowType.ReduceBigFlow); 


مثال 2: البحث عن مراجع كائن مباشر غير آمن


في هذا الطلب ، سوف نبحث عن جميع الأماكن التي يحدث فيها العمل مع الكائنات دون التحقق من مالك الكائن. في هذه الحالة ، يمكن استخدام أسماء مختلفة لمعلمات HTTP الخاصة بـ mailid (نفترض أن هذا هو Legacy) ، ويمكن أن يحدث التحقق نفسه في مراحل مختلفة: في مكان ما مباشرةً عند نقطة دخول HTTP API ، في مكان ما قبل طلب قاعدة البيانات ، وأحيانًا في الأساليب المتوسطة.

خطة البحث
  1. تحديد الاستثناءات ( استثناء )
  2. تحديد أماكن لفحص الترخيص ( idorSanitizer ) ؛
  3. البحث عن نقاط الدخول - أماكن للمعالجة الأولية لطلبات HTTP ( webRemoteMethods ) ؛
  4. فقط بواسطة الرموز المميزة لنقطة الإدخال للعثور على موقع استخراج معلمة HTTP mailid ( علبة البريد ) ؛
  5. البحث عن جميع المكالمات من webRemoteMethods إلى أساليب الوسيطة ومعلمات هذه المكالمات ( middlewareMethods ) ؛
  6. البحث عن أساليب الوسيطة التي تعتمد على mailid ( apiPotentialIDOR ) ؛
  7. البحث عن جميع الأماكن التي يتم فيها تحديد أساليب الوسيطة ( middlewareDecl ) ؛
  8. انتقل من خلال جميع apiPotentialIDOR وحدد فقط تلك الوسيطة decl التي لا يوجد فيها تحقق من صاحب الكائن mailid .


المعرف: الخطوة 1. تحديد الاستثناءات


في هذه الحالة ، استبعد جميع الرموز المميزة في ملف محدد:

 CxList exclusionList = All.FindByFileName("*WebMethodContext.java"); result = exclusionList; 

يحتوي WebMethodContext.java على تطبيق أساليب مثل getMailboxId و getUserId ، وكذلك السلسلة "mailid". نظرًا لأن اسم الرموز سيتزامن مع الرموز التي نحتاجها للبحث عن الثغرات الأمنية ، فسيصدر هذا الملف نتائج خاطئة.

المعرف: الخطوة 2. حدد موقع تدقيقات التخويل


في تطبيق الاختبار ، يتم استخدام طريقة validateMailbox () لتحديد ما إذا كان الكائن المطلوب ينتمي إلى المستخدم:

 CxList idorSanitizer = All.FindByName("*validateMailbox*"); result = idorSanitizer; 

النتيجة:



المعرف: الخطوة 3. ابحث عن نقاط الإدخال لطلبات HTTP API المخصصة


لدى معالجات طلب HTTP تعليق توضيحي خاص يسهل العثور عليه. في حالتي ، هذا هو "WebRemote" ؛ يتم استخدام الدالة CMxQL FindByCustomAttribute () للبحث عن التعليقات التوضيحية. بالنسبة لـ FindByCustomAttribute () ، تقوم دالة البحث الخاصة بالرمز الأصل GetAncOfType () بإرجاع الطريقة تحت التعليق التوضيحي:

 CxList webRemoteMethods = All.FindByCustomAttribute("WebRemote") .GetAncOfType(typeof(MethodDecl)); result = webRemoteMethods; 


طلب النتيجة:



IDOR: الخطوة 4. باستخدام الرموز المميزة لنقطة الإدخال فقط ، ابحث عن مواقع استخراج HTTP للمعلمة mailid


للعثور على الرموز ذات الصلة بمعالجة المعلمة HTTP mailid:

 CxList getMailboxId = All.FindByName("\"mailboxId\"") + All.FindByName("\"mid\"") + All.FindByName("\"boxid\""); result = getMailboxId; 

أضفنا 3 مجموعات مع 3 خطوط مختلفة ، ل وفقًا للأسطورة ، قد يختلف اسم المعلمة HTTP في أجزاء مختلفة من النظام.

سيجد الاستعلام جميع الأماكن التي يُكتب فيها mailid / mid / boxid كسلسلة (في علامات اقتباس مزدوجة). ولكن هذا الاستعلام سيعود الكثير من الاكتشافات ، المعارف التقليدية. يمكن العثور على مثل هذه السلسلة ليس فقط في الأماكن التي يتم فيها استخراج معلمات HTTP. إذا واصلنا العمل مع هذه المجموعة ، فسنحصل على عدد كبير من الاكتشافات الخاطئة.

لذلك ، سوف نبحث فقط عن الرموز المميزة لنقاط الدخول ( webRemoteMethods ). للعثور على جميع الرموز المميزة التابعة ، يتم استخدام الدالة CMBQL GetByAncs () :

 result = All.GetByAncs(webRemoteMethods); 

سيقوم الطلب بإرجاع كافة الرموز المميزة التي تنتمي إلى الطرق المشروحة كـ WebRemote . بالفعل في هذه المرحلة ، يمكننا تصفية الرموز المميزة لتلك الطرق التي يتم فيها التحقق من مالك الكائن. لذلك ، نعيد كتابة الاستعلام السابق للبحث عن الرموز المميزة للطفل بحيث يتم تحديد الرموز المميزة الفرعية لطرق WebRemote فقط ، حيث لا يوجد فحص أمان لمالك الكائن. للقيام بذلك ، استخدم حلقة مع الشرط:

 //          CxList entry_point_tokens = All.NewCxList(); //      webRemoteMethods foreach (CxList method in webRemoteMethods) { //        CxList method_tokens = All.GetByAncs(method); // ,       ,    owner if (method_tokens.FindByName(idorSanitizer).Count > 0) { //  ,     , ,     } else { //  ,         entry_point_tokens.Add(method_tokens); } } 

الآن يمكننا إجراء تحديد أكثر دقة باستخدام معلمات HTTP mailid :

 CxList getMailboxHTTPParams = entry_point_tokens.FindByName("\"mailboxid\"") + entry_point_tokens.FindByName("\"mid\"") + entry_point_tokens.FindByName("\"boxid\""); result = getMailboxHTTPParams; 

لكننا لسنا مهتمين بالأماكن التي يتم فيها استرداد معلمات HTTP ، ولكن في المتغيرات التي تم تعيين قيم معلمات HTTP بها في النهاية. لأنه أكثر موثوقية للبحث عن التدفق بدقة بواسطة الرموز المميزة للمتغيرات.

سوف تجد الدالة CMxQL FindByInitialization () أماكن التهيئة المتغيرة للرموز المميزة المحددة:

 CxList mailboxidInit = entry_point_tokens.FindByInitialization(getMailboxHTTPParams); result = mailboxidInit; 

النتيجة:



IDOR: الخطوة 5. البحث عن جميع المكالمات من webRemoteMethods إلى أساليب الوسيطة ومعلمات هذه المكالمات


بواسطة الوسيطة ، أعني رمزًا أعمق من طرق معالجة طلبات HTTP API ، أي أعمق من نقاط إدخال طلبات المستخدم. على سبيل المثال ، في لقطة الشاشة أعلاه ، هذه هي طرق لفئة المستخدم ، ومكالمات إلى user.getSettings () و user.getSecureSettings () :

 CxList middlewareMethods = All.FindByShortName("user").GetRightmostMember(); CxList middlewareMethodsParams = entry_point_tokens.GetParameters(middlewareMethods); result = middlewareMethodsParams; 

أولاً ، نختار جميع الرموز المميزة مع اسم المستخدم ، ثم نستخدم GetRightmostMember () نختار الرموز المميزة للاتصال بالبرنامج الوسيط. إرجاع GetRightmostMember () في سلسلة استدعاءات الأسلوب في أقصى اليمين. ثم نشتق معلمات الطريقة التي تم العثور عليها باستخدام GetParameters () .

النتيجة:



المعرف: الخطوة 6. البحث عن أساليب الوسيطة التي تعتمد على علبة البريد


يستخدم تحليل التدفق طرق * InfluencedBy * و * InfluncingOn * . الفرق بينهما واضح بالاسم.

على سبيل المثال:

 All.InfluencedBy(getMailboxHTTPParams) 

سوف تمر عبر مجموعة الكل وستجد جميع الرموز التي تعتمد على getMailboxHTTPParams .

نفس الشيء يمكن كتابته بطريقة أخرى:

 getMailboxHTTPParams.InfluencingOn(All) 


للبحث عن الرموز التي تعتمد على علبة البريد :

 CxList apiPotentialIDOR = entry_point_tokens.InfluencedByAndNotSanitized(mailboxidInit, idorSanitizer); result = apiPotentialIDOR; 

النتيجة:



IDOR: الخطوة 7. البحث عن جميع الأماكن لتحديد أساليب الوسيطة


دعنا نعثر على تعريفات جميع الطرق الوسيطة التي يمكن استخدامها في الأماكن التي تتم فيها معالجة طلبات المستخدم. للقيام بذلك ، نسلط الضوء على الخاصية المشتركة الخاصة بهم ، على سبيل المثال ، في كل هذه الطرق يوجد إنشاء كائن request () ، يكون إنشاء الكائن من نوع CMx ObjectCreateExpr :

 CxList requests = (All - exclusionList).FindByType(typeof(ObjectCreateExpr)).FindByName("*Request*"); CxList middlewareDecl = requests.GetAncOfType(typeof(MethodDecl)); result = middlewareDecl; 


(الكل - exclusionList) - يمكنك القيام بهذا الطرح من المجموعات ، ثم استدعاء وظيفة CMxQL المطلوبة من النتيجة. تحتوي الطلبات الآن على جميع الرموز المميزة مع اسم الطلب ونوع المطابقة لإنشاء الكائن.

بعد ذلك ، باستخدام GetAncOfType () المألوف ، نجد الرمز المميز للنوع MethodDecl .

النتيجة:



IDOR: الخطوة 8. انتقل من خلال جميع apiPotentialIDOR وحدد فقط تلك الوسيطة decl التي لا يوجد فيها تحقق من مالك الكائن mailid


في الجزء الأخير من الطلب ، سنحدد أيًا من أساليب الوسيطة التي يتم استدعاؤها مباشرةً من أساليب نقطة الدخول ولا نتحقق من هوية صندوق البريد الذي ينتمي إليه . ثم ادمج التدفق لإجراء تحليل أكثر ملاءمة للنتائج.

الميزات الجديدة التي لم نستخدمها بعد:
GetCxListByPath () - هذه الوظيفة مطلوبة للتكرار عبر Flow ، إذا لم يتم استخدامها ، فسيضغط CMx Flow في Code Element (في عقدة التدفق الأولى)
Concatenate * () - عدد من الوظائف اللازمة لدمج عدة تدفق في واحد
FindByParameters () - ابحث عن طريقة برمز معلمة محدد
GetName () - سيعود سلسلة باسم رمزي ، إذا كان هناك أكثر من عنصر في CxList ، فسوف يُرجع الأول. يتم استخدام الطريقة فقط عند التكرار على عناصر مجموعة.

الجزء الأخير من الطلب:

 //    CxList vulns = All.NewCxList(); //   Flow  apiPotentialIDOR foreach(CxList cxFlow in apiPotentialIDOR.GetCxListByPath()) { //    Flow CxList endNode = cxFlow.GetStartAndEndNodes(CxList.GetStartEndNodesType.EndNodesOnly); //       flow (mailboxid) CxList method_call = entry_point_tokens.FindByParameters(endNode); //     CxList method_decl = middlewareDecl.FindByShortName(method_call.GetName()); //     if (method_decl.Count > 0) { //       CxList _all = (All - exclusionList).GetByAncs(method_decl); //       if (_all.FindByName(idorSanitizer).Count > 0) { //  ,       cxLog.WriteDebugMessage("find sanitized in method: " + method_call.GetName()); //  ,   Flow     vulns } else { //     Flow       vulns.Add(cxFlow.ConcatenatePath(method_call).ConcatenatePath(method_decl)); cxLog.WriteDebugMessage("find NOT sanitized in method: " + method_call.GetName()); } } } 


النتيجة:



CocatenatePath , . Code Element Flow

IDOR: IDOR


 // 1.   CxList exclusionList = All.FindByFileName("*WebMethodContext.java"); // 2.     CxList idorSanitizer = All.FindByName("*validateMailbox*"); // 3.    –    HTTP  CxList webRemoteMethods = All.FindByCustomAttribute("WebRemote").GetAncOfType(typeof(MethodDecl)); // 4.         HTTP  mailboxid //     CxList entry_point_tokens = All.NewCxList(); foreach (CxList method in webRemoteMethods) { CxList method_tokens = All.GetByAncs(method); if (method_tokens.FindByName(idorSanitizer).Count > 0) { } else { entry_point_tokens.Add(method_tokens); } } //    HTTP    -  CxList getMailboxHTTPParams = entry_point_tokens.FindByName("\"mailboxId\"") + entry_point_tokens.FindByName("\"mid\"") + entry_point_tokens.FindByName("\"boxid\""); CxList mailboxidInit = entry_point_tokens.FindByInitialization(getMailboxHTTPParams); // 5.      middleware     CxList middlewareMethods = All.FindByShortName("user").GetRightmostMember(); CxList middlewareMethodsParams = entry_point_tokens.GetParameters(middlewareMethods); // 6.  middleware ,     mailboxid CxList apiPotentialIDOR = entry_point_tokens.InfluencedByAndNotSanitized(mailboxidInit, idorSanitizer); // 7.      middleware      CxList requests = (All - exclusionList).FindByType(typeof(ObjectCreateExpr)).FindByName("*Request*"); CxList middlewareDecl = requests.GetAncOfType(typeof(MethodDecl)); // 8.    apiPotentialIDOR     middlewareDecl,      CxList vulns = All.NewCxList(); foreach(CxList cxFlow in apiPotentialIDOR.GetCxListByPath()) { CxList endNode = cxFlow.GetStartAndEndNodes(CxList.GetStartEndNodesType.EndNodesOnly); CxList method_call = entry_point_tokens.FindByParameters(endNode); CxList method_decl = middlewareDecl.FindByShortName(method_call.GetName()); if (method_decl.Count > 0) { CxList _all = (All - exclusionList).GetByAncs(method_decl); if (_all.FindByName(idorSanitizer).Count > 0) { cxLog.WriteDebugMessage("find sanitized in method: " + method_call.GetName()); } else { vulns.Add(cxFlow.ConcatenatePath(method_call).ConcatenatePath(method_decl)); cxLog.WriteDebugMessage("find NOT sanitized in method: " + method_call.GetName()); } } } result = vulns; 


استنتاج


Checkmarx , . , , , .. Flow ( ). , , «» .

false positive, :
  • , ( ).
  • , ( ). , «Privacy Violation», , , Web UI. , .. UI . TLS XSS .
  • - , (, ). , XXE , , - , .
  • false positive, , CMxQL FindBy/GetBy. , ( SQL).
  • false positives, , , , , CMx, . , LDAP , . c LDAP- , , .


how-to «hello world» , Checkmarx.

Source: https://habr.com/ru/post/ar477742/


All Articles