دليل المراجعة التلقائية للعقود الذكية. الجزء 2: انزلق

محلل: انزلق
الوصف: إطار تحليل ثابت مفتوح المصدر لـ Solidity
githib: https://github.com/trailofbits/slither


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


يمكن أن يعمل Slither كوحدة نمطية من python ويزود المبرمج بواجهة للتدقيق وفقًا لخطته الخاصة. مثال بسيط وتوضيحي لما يمكن أن ينزلق يمكن رؤيته هنا .


سنعود إلى سيناريوهات التحليل في نهاية المقالة ، ولكن في الوقت الحالي ، قم بتشغيل Slither:


git clone https://github.com/trailofbits/slither.git cd slither docker build -t slither . 

ومحاولة تحليل عقدنا.


نذهب إلى الدليل من خلال constructor-eth-booking ونحاول الركض من منصة الإرساء:


 $ docker run -v $(pwd)/contracts:/slither/contracts slither contracts/flattened.sol 

حصلنا على الخطأ "يتطلب ملف المصدر إصدار برنامج التحويل البرمجي المختلف" ، والآن نحن بحاجة إلى وضع إصدار solc=0.4.20 في عامل solc=0.4.20 . للقيام بذلك ، نقوم بتصحيح ملف Dockerfile of Slither نفسه ، كما هو موضح في القسم 2 في المقدمة ، أي في مكان ما في نهاية Dockerfile نضيف السطر:


 COPY --from=ethereum/solc:0.4.20 /usr/bin/solc /usr/bin 

، اعيد بناء الصورة، ركض، هتافات، كل شيء يجمع.


نرى الإخراج ، محذرين من "pragma" مختلفة وحول أسماء المتغيرات غير الصحيحة مثل Parameter '_price' of Booking.Booking (flattened.sol#73) is not in mixedCase . يقدم المحللون الكثير من التحذيرات ، لكننا نبحث عن أخطاء حقيقية ، ولن ننتبه إلى التافه. نقوم بتصفية جميع الرسائل حول mixedCase ، والآن لا يتعلق الأمر بما يلي:


 $ docker run -v $(pwd)/contracts:/slither/contracts slither contracts/flattened.sol 2>&1 | fgrep -v 'mixedCase' 

يفتقد المبرمجون الحقيقيون كل شيء باللون الأخضر ، وينظرون إلى كل شيء باللون الأحمر ، وهنا ما عثر عليه Slither في العقد إلى جانب إيجابيات كاذبة:


 Booking.refundWithoutCancellationFee (flattened.sol#243-250) sends eth to arbirary user Dangerous calls: - client.transfer(address(this).balance) (flattened.sol#249) Reference: https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#functions-that-send-ether-to-arbitrary-destinations INFO:Detectors: Booking.refundWithCancellationFee (flattened.sol#252-259) sends eth to arbirary user Dangerous calls: - owner.transfer(m_cancellationFee) (flattened.sol#257) - client.transfer(address(this).balance) (flattened.sol#258) Reference: https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#functions-that-send-ether-to-arbitrary-destinations 

الآن انظر إلى ما هو الخطأ في هذه الوظيفة في العقد:


  /************************** PRIVATE **********************/ function refundWithoutCancellationFee() private { address client = m_client; m_client = address(0); changeState(State.OFFER); client.transfer(address(this).balance); } function refundWithCancellationFee() private { address client = m_client; m_client = address(0); changeState(State.CANCELED); owner.transfer(m_cancellationFee); client.transfer(address(this).balance); } 

في هذه الحالة ، على سبيل المثال ، يتم استدعاء الدالة refundWithoutCancellationFee() مثل هذا:


  function rejectPayment() external onlyOwner onlyState(State.PAID) { refundWithoutCancellationFee(); } function refund() external onlyClient onlyState(State.PAID) { refundWithoutCancellationFee(); } 

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


لقد قمت بالتحقق جيدًا من أن Slither كان يعتني بأي بث ، ونقل هيئة الوظيفة مباشرةً إلى ما سبق "ترفضPayment ()" و "refund ()" ، اختفى التحذير ، أي أدرك انزلق الآن البث لا يتم إرسالها دون التحقق من العنوان. بداية رائعة!


الآن ، دعونا نتحقق من كيفية قيام Slither بمراقبة تهيئة المتغيرات ، لذلك نعلق على تهيئة اثنين:


 - m_fileHash = _fileHash; + // m_fileHash = _fileHash; - m_price = _price; + // m_price = _price; 

الأول ليس مهمًا للغاية ، من حيث الثقوب ، باستثناء إهدار الموارد ، لأنه لا يتم استخدام m_fileHash في أي مكان ، بل يتم تخزينه ببساطة على blockchain عند إنشاء عقد. ولكن يتم استخدام m_price ، ويقسم Slither بشكل صحيح أنه لم تتم تهيئة m_price في أي مكان ، على الرغم من استخدامه:


 Booking.m_price (flattened.sol#128) is never initialized. It is used in: - fallback (flattened.sol#144-156) 

حسنًا ، هذه خدعة بسيطة ، كما هو متوقع ، كل شيء سار على ما يرام.


سنقوم الآن بإضافة إعادة التوجيه المحببة إلى الجميع في العقد: سنقوم بتغيير حالة العقد بعد مكالمة خارجية. نجري التغييرات التالية:


  function refundWithoutCancellationFee() private { address client = m_client; - m_client = address(0); - changeState(State.OFFER); - client.transfer(address(this).balance); + client.call.value(address(this).balance)(); + m_client = address(0); + changeState(State.OFFER); } 

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


نتيجة البحث عن إعادة الدخول:


 Reentrancy in Booking.refundWithoutCancellationFee (flattened.sol#243-253): External calls: - client.call.value(address(this).balance)() (flattened.sol#245) State variables written after the call(s): - m_client (flattened.sol#246) 

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


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


الآن ، سأجري تغييرات تظهر تمامًا تفاصيل عمل أجهزة التحليل الثابتة:


 - client.transfer(address(this).balance + for (uint i=0; i < 1; i++) { + client.transfer(address(this).balance - 999999999999999999); + } 

والنتيجة:


 Booking.refundWithoutCancellationFee has external calls inside a loop: - client.transfer(address(this).balance - 999999999999999999) (flattened.sol#252) Reference: https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description/_edit#calls-inside-a-loop 

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


وعدنا أن نذكر إمكانية كتابة البرامج النصية الخاصة بنا للاختبار ، وإخراج أي معلومات مثيرة للاهتمام حول العقد باستخدام مفتاح - --print . من وجهة النظر هذه ، يعد Slither أداة رائعة لـ CI. يعرف مطورو نظام التعاقد الكبير أسماء المتغيرات الحرجة للسلامة: الأرصدة وأحجام العمولات والأعلام ، ويمكنهم كتابة نص برمجي للاختبار يحظر أي تغييرات في الكود ، على سبيل المثال ، الكتابة فوق متغير مهم ، أو تغيير متغيرات الحالة بعد مكالمة خارجية ، و تحليلها الذي يمكن التنبؤ به للغاية هو أداة رائعة للاستخدام في السنانير.
مهمة Slither هي إنقاذك من الأخطاء الغبية ، والعثور على أنماط خطيرة معروفة وتحذير المطور. في هذا الإصدار ، يعد هذا أداة جيدة لمطور مبتدئ على Solidity ، حيث يطالبك على الفور بكتابة التعليمات البرمجية في Solidity بشكل صحيح.


ملخص


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


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


في المقالة التالية ، سنتعامل مع محلل Mythril ، ولكن هنا جدول محتويات المقالات الجاهزة أو المخطط للكتابة:


الجزء 1. مقدمة. تجميع ، تسطيح ، إصدارات من الصلابة
الجزء 2. انزلق (هذه المادة)
الجزء 3. الأسطورة
الجزء 4. Manticore (في عملية الكتابة)
الجزء 5. Echidna (في عملية الكتابة)

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


All Articles