في 8 ديسمبر 2023، أصدرت OpenZeppelin تحذيرًا هامًا بشأن الأمان. اتضح أنه عند استخدام معيار ERC-2771 مع وظائف مثل Multicall، هناك خطر من تغيير العنوان! لقد درست هذه الثغرة بعمق وأريد أن أشارك اكتشافاتي.
قام المهاجم بتبادل 5 WETH مقابل حوالي 3,455,399,346 TIME
ثم قمت بإنشاء معلمات calldata الذكية واستدعيت [Forwarder].execute
هذه الوظيفة أطلقت multicall في عقد TIME، وتم استخدام calldata المتبقي لـ burn() - لتدمير الرموز في المجموعة!
كيف تعمل هذه؟
في هذا الهجوم تلاقت النجوم: ERC-2771 و Multicall وبيانات مُعدّة بعناية. ورقة TOKEN ترث ERC2771Context، وهنا يبدأ الجزء الأكثر إثارة!
تتيح ERC-2771 عنوانًا افتراضيًا msg.sender، مما يسمح بتفويض المعاملات لطرف ثالث. في هذه الحالة، تتم إضافة العنوان الحقيقي إلى calldata. عندما يستدعي [Forwarder] العقد، يتحقق _msgSender() من هذه البيانات ويقطع آخر 20 بايت كـ "msg.sender الحقيقي".
Multicall يحول استدعاء واحد إلى عدة استدعاءات، موفراً الغاز. إنه يقبل مصفوفة من الاستدعاءات وينفذها عبر deleGatecall().
وهنا تأتي الفخ! يقوم المهاجم بتحويل calldata بحيث تتوافق الأربعة بايت الأولى من البيانات الجديدة مع وظيفة burn()، بينما المعامل هو مبلغ كبير من الرموز. في السطر 0x20 يتم إضافة عنوان بركة السيولة TIME-ETH، الذي يصبح "المرسل المتوقع" msg.sender!
جذر المشكلة
في ERC-2771 [Forwarder] لم يكن من المخطط أبدًا أن يعمل مع multicall! أضاف المهاجم المعلمات _msgSender() إلى استدعاء multicall الخارجي. داخل دالة multicall، أضافت بعض الدوال أيضًا هذه المعلمات، مما سمح بمحاكاة الاستدعاء من أي عنوان!
مقاييس الحماية
النسخة الجديدة من OpenZeppelin Multicall الآن تحفظ طول سياق ERC-2771 وتأخذها بعين الاعتبار في كل استدعاء فرعي.
ThirdWeb ذهب أبعد من ذلك ومنع أي عقود من استدعاء multicall، مما يمنع استخدام [Forwarder].
هذه الثغرة هي مثال واضح على كيف يمكن أن يؤدي الجمع بين مكونات آمنة بشكل منفصل إلى خلق ثغرة كارثية! يجب على جميع المطورين أن يتذكروا: تحقق دائمًا من التفاعل بين المعايير المختلفة.
قد تحتوي هذه الصفحة على محتوى من جهات خارجية، يتم تقديمه لأغراض إعلامية فقط (وليس كإقرارات/ضمانات)، ولا ينبغي اعتباره موافقة على آرائه من قبل Gate، ولا بمثابة نصيحة مالية أو مهنية. انظر إلى إخلاء المسؤولية للحصول على التفاصيل.
تحليل مبدأ ضعف استبدال عنوان عشوائي في ERC2771 Multicall من SharkTeam
في 8 ديسمبر 2023، أصدرت OpenZeppelin تحذيرًا هامًا بشأن الأمان. اتضح أنه عند استخدام معيار ERC-2771 مع وظائف مثل Multicall، هناك خطر من تغيير العنوان! لقد درست هذه الثغرة بعمق وأريد أن أشارك اكتشافاتي.
تحليل الهجوم
دعونا نناقش واحدة من الهجمات:
خطة الهجوم بسيطة بشكل عبقري:
كيف تعمل هذه؟
في هذا الهجوم تلاقت النجوم: ERC-2771 و Multicall وبيانات مُعدّة بعناية. ورقة TOKEN ترث ERC2771Context، وهنا يبدأ الجزء الأكثر إثارة!
تتيح ERC-2771 عنوانًا افتراضيًا msg.sender، مما يسمح بتفويض المعاملات لطرف ثالث. في هذه الحالة، تتم إضافة العنوان الحقيقي إلى calldata. عندما يستدعي [Forwarder] العقد، يتحقق _msgSender() من هذه البيانات ويقطع آخر 20 بايت كـ "msg.sender الحقيقي".
Multicall يحول استدعاء واحد إلى عدة استدعاءات، موفراً الغاز. إنه يقبل مصفوفة من الاستدعاءات وينفذها عبر deleGatecall().
وهنا تأتي الفخ! يقوم المهاجم بتحويل calldata بحيث تتوافق الأربعة بايت الأولى من البيانات الجديدة مع وظيفة burn()، بينما المعامل هو مبلغ كبير من الرموز. في السطر 0x20 يتم إضافة عنوان بركة السيولة TIME-ETH، الذي يصبح "المرسل المتوقع" msg.sender!
جذر المشكلة
في ERC-2771 [Forwarder] لم يكن من المخطط أبدًا أن يعمل مع multicall! أضاف المهاجم المعلمات _msgSender() إلى استدعاء multicall الخارجي. داخل دالة multicall، أضافت بعض الدوال أيضًا هذه المعلمات، مما سمح بمحاكاة الاستدعاء من أي عنوان!
مقاييس الحماية
النسخة الجديدة من OpenZeppelin Multicall الآن تحفظ طول سياق ERC-2771 وتأخذها بعين الاعتبار في كل استدعاء فرعي.
ThirdWeb ذهب أبعد من ذلك ومنع أي عقود من استدعاء multicall، مما يمنع استخدام [Forwarder].
هذه الثغرة هي مثال واضح على كيف يمكن أن يؤدي الجمع بين مكونات آمنة بشكل منفصل إلى خلق ثغرة كارثية! يجب على جميع المطورين أن يتذكروا: تحقق دائمًا من التفاعل بين المعايير المختلفة.