حالة السباق في تطبيقات الويب

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

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

  • تحتاج إلى التأكد من أن المبلغ متاح لفاسيا للنقل.

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

  • قم بطرح المبلغ المراد تحويله من رصيد المستخدم

من الضروري تدوين رصيد المستخدم الحالي مع خصم المبلغ المحول. كان 100 ، وأصبح 100-100 = 0.

  • أضف إلى رصيد المستخدم بيتيا المبلغ الذي تم تحويله.

بيتيا ، على العكس ، كان 0 ، أصبح 0 + 100 = 100.

  • عرض رسالة إلى المستخدم بأنه جيد!

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

 (. >= _)  .=.-_ .=.+_ ()  () 

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

الآن تخيل أن خوارزمية لدينا تعمل في وقت واحد 3 مرات.

لا يزال لدى Vasya 100 نقطة في رصيده ، إلا أنه بطريقة ما التفت إلى تطبيق الويب في ثلاث سلاسل في نفس الوقت (بحد أدنى من الوقت بين الطلبات). تحقق التدفقات الثلاثة ما إذا كان المستخدم هو Petya ، وتحقق مما إذا كان لدى Vasya رصيد كافٍ للنقل. في تلك اللحظة من الزمن عندما تقوم الخوارزمية بالتحقق من الرصيد ، لا يزال يساوي 100. بمجرد اكتمال التحقق ، يتم طرح 100 من الرصيد الحالي 3 مرات وإضافة بيت.

ماذا لدينا؟ فازيا لديه رصيد سلبي في حسابه (100 - 300 = -200 نقطة). في هذه الأثناء ، لدى بيتيا 300 نقطة ، رغم أنه في الواقع ، يجب أن يكون 100 نقطة. وهذا مثال نموذجي لاستغلال حالة السباق. يمكن مقارنته بحقيقة أن العديد من الأشخاص يمرون على مسار واحد مرة واحدة. يوجد أدناه لقطة من هذا الموقف من 4lemon



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

تشغيل حالة السباق النموذجي


يدخل المتسلل إلى غرفة الشيشة ، وهو يبحث عن حانة ، وله - لديك حالة سباق! عمر جانييف

في معظم الحالات ، يتم استخدام برنامج متعدد مؤشرات الترابط كعميل لفحص / تشغيل حالة السباق. على سبيل المثال ، Burp Suite وأداة الدخيل الخاصة به. وضعوا طلب HTTP واحدًا للتكرار ، وقاموا بتثبيت العديد من الجداول وتشغيل الفيضان. مثل على سبيل المثال في هذه المقالة . أو في هذا واحد . هذه طريقة فعالة إلى حد ما ، إذا كان الخادم يسمح باستخدام سلاسل عمليات متعددة لمورده ، وكما يقولون في المقالات أعلاه ، وإذا لم ينجح ذلك ، فحاول مرة أخرى. ولكن الحقيقة هي أنه في بعض الحالات ، قد لا يكون هذا فعالا. خاصة إذا كنت تتذكر كيف تصل هذه التطبيقات إلى الخادم.

ما هو هناك على الخادم


ينشئ كل مؤشر ترابط اتصال TCP ويرسل البيانات وينتظر استجابة ويغلق الاتصال ويفتح مرة أخرى ويرسل البيانات وما إلى ذلك. للوهلة الأولى ، يتم إرسال جميع البيانات في وقت واحد ، ولكن قد لا تصل طلبات HTTP نفسها بشكل متزامن وغير متناسقة نظرًا لطبيعة طبقة النقل ، والحاجة إلى إنشاء اتصال آمن (HTTPS) وحل DNS (ليس في حالة التجشؤ) والعديد من الطبقات التجريدات التي تمرر البيانات قبل إرسالها إلى جهاز الشبكة. عندما يتعلق الأمر بالميلي ثانية ، يمكن أن يلعب هذا دورًا رئيسيًا.

خطوط الأنابيب HTTP


يمكنك استدعاء HTTP-Pipelining ، حيث يمكنك إرسال البيانات باستخدام مأخذ توصيل واحد. يمكنك أن ترى بنفسك كيف تعمل باستخدام الأداة المساعدة netcat (لديك GNU / Linux ، أليس كذلك؟).

في الواقع ، تحتاج إلى استخدام linux لعدة أسباب ، لأن هناك رصة TCP / IP أكثر حداثة ، والتي تدعمها نواة نظام التشغيل. الخادم على الأرجح أيضا على ذلك.

على سبيل المثال ، قم بتشغيل nc google.com 80 وأدخل السطور هناك

 GET / HTTP/1.1 Host: google.com GET / HTTP/1.1 Host: google.com GET / HTTP/1.1 Host: google.com 

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

ما هو هناك على الخادم


سيتلقى خادم الويب الطلبات بالتسلسل (الكلمة الأساسية) ، ومعالجة الردود حسب الأولوية. يمكن استخدام هذه الميزة للهجوم في عدة خطوات (عندما يكون ذلك ضروريًا لتنفيذ إجراءين بالتسلسل في الحد الأدنى من الوقت) أو ، على سبيل المثال ، لإبطاء الخادم في الطلب الأول من أجل زيادة نجاح الهجوم.
خدعة - يمكنك منع الخادم من معالجة طلبك عن طريق تحميل قواعد البيانات ، خاصة إذا تم استخدام INSERT / UPDATE. يمكن للطلبات الأثقل "إبطاء" حجم حملتك ، وبالتالي ، من المرجح أنك ستربح هذا السباق.

تقسيم طلب HTTP إلى قسمين


أولاً ، تذكر كيف يتم إنشاء طلب HTTP. حسنًا ، كما تعلم ، السطر الأول هو الطريقة والمسار وإصدار البروتوكول:

GET / HTTP/1.1

فيما يلي الرؤوس قبل فاصل السطر:

Host: google.com
Cookie: a=1

ولكن كيف يعرف خادم الويب أن طلب HTTP قد انتهى؟

دعونا نلقي نظرة على مثال ، أدخل nc google.com 80 ، وهناك

GET / HTTP/1.1
Host: google.com
GET / HTTP/1.1
Host: google.com
، بعد الضغط على ENTER ، لن يحدث شيء. انقر مرة أخرى - سترى الجواب.

وهذا يعني أنه لكي يقبل خادم الويب طلب HTTP ، فمن الضروري أن يكون هناك سطرين. يبدو الاستعلام الصحيح كما يلي:

GET / HTTP/1.1\r\nHost: google.com\r\n\r\n

إذا كانت هذه هي طريقة POST (لا تنسى طول المحتوى) ، فسيكون طلب HTTP الصحيح كما يلي:

POST / HTTP/1.1
Host: google.com
Content-Length: 3

a=1


أو

POST / HTTP/1.1\r\nHost: google.com\r\nContent-Length: 3\r\n\r\na=1

حاول إرسال طلب مماثل من سطر الأوامر:

 echo -ne "GET / HTTP/1.1\r\nHost: google.com\r\n\r\n" | nc google.com 80 

نتيجة لذلك ، ستتلقى ردًا ، نظرًا لأن طلب HTTP مكتمل. ولكن إذا قمت بإزالة الحرف الأخير \ n ، فلن تحصل على إجابة.

في الواقع ، تحتاج العديد من خوادم الويب فقط إلى استخدام \ n كعملية نقل ، لذلك من المهم عدم المبادلة و \ n ، وإلا فقد لا تعمل بعض الحيل.

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

هذا مهم بشكل خاص عندما يتعلق الأمر بطلب POST كبير ، على سبيل المثال ، عندما يكون تحميل الملف ضروريًا. ولكن حتى في طلب صغير ، يكون هذا منطقيًا ، حيث أن تسليم عدد قليل من البايتات أسرع بكثير من كيلوبايت المعلومات في وقت واحد.

التأخير قبل إرسال الجزء الثاني من الطلب


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



ما هو هناك على الخادم


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

كيفية التعامل معها


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

عادةً ما يتم استخدام أساليب التحكم في الهجوم التالية:


تقوم العملية بحظر الوصول إلى الكائن المؤمن في DBMS حتى يتم إلغاء حظره. يقف الآخرون والانتظار على الهامش. من الضروري العمل مع الأقفال بشكل صحيح ، وليس لمنع أي شيء غير ضروري.


المعاملات المنظمة (المتسلسلة) - تأكد من أن المعاملات سيتم تنفيذها بشكل متسلسل ، ومع ذلك ، فقد يؤثر ذلك على الأداء.


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

وبصفة عامة ، أعجبتني الفيديو لإيفان العامل الصعب حول الأقفال والمعاملات ، مفيدة للغاية.

ميزات الدورة في حالة السباق


قد تكون إحدى ميزات الجلسات أنه يتداخل بحد ذاته مع استغلال السباق. على سبيل المثال ، في PHP ، بعد session_start () ، يتم تأمين ملف جلسة ، ويحدث إلغاء قفله فقط في نهاية البرنامج النصي (إذا لم يكن هناك اتصال بـ session_write_close ). إذا تم استدعاء برنامج نصي آخر يستخدم جلسة في هذه اللحظة ، فسوف ينتظر.

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

القرب من الخادم


إذا تم استضافة الموقع الذي تريد تشغيل حالة السباق به في AWS - اصطحب السيارة في AWS. إذا كان في DigitalOcean - أعتبر هناك.

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

بعد كل شيء ، هناك فرق عند تنفيذ الأمر ping إلى الخادم 200 و 10 مللي ثانية. وإذا كنت محظوظًا ، فيمكنك أن تصل إلى نفس الخادم الفعلي ، فسيكون من الأسهل قليلاً الطيران :)

لتلخيص


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

نتيجة لهذا التحليل ، إلى جانب Michail Badin ، قمنا بتطوير أداة RacePWN

يتكون من مكونين:

  • مكتبة C librace ، التي ترسل الكثير من طلبات HTTP إلى الخادم في أقصر وقت وتستخدم معظم الميزات من المقالة

  • الأدوات المساعدة racepwn ، التي تقبل تكوين json وتوجه هذه المكتبة عمومًا

يمكن دمج RacePWN في أدوات مساعدة أخرى (على سبيل المثال ، في Burp Suite) ، أو يمكنك إنشاء واجهة ويب لإدارة الرحلات الجوية (لا يزال يتعذر عليك تشغيلها). استمتع!

ولكن في الواقع لا يزال هناك مجال للنمو ويمكنك أن تتذكر HTTP / 2 وآفاقها للهجوم. ولكن في الوقت الحالي HTTP / 2 ، فإن معظم الموارد لديها فقط طلبات بروكسي أمامية إلى HTTP / 1.1 القديم الجيد.

ربما كنت تعرف بعض التفاصيل الدقيقة؟

الأصلي

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


All Articles