تقرير الحادثة الذي نشرته Scroll الليلة أكثر إثارة بكثير من عبارة «لم يُستغلّ».
ذهبتُ إلى المنشور الأصلي في المنتدى (11/11 14:24 UTC). المشكلة كانت في عقد التحقق من bundle proof على الشبكة الرئيسية، ZkEvmVerifierPostFeynman (0x7966…B254). كان يركّب المدخلات يدويًا، ويستخدم raw staticcall لاستدعاء مدقّق Halo2 في OpenVM 2.0، بينما كانت البايتات الأربع الأولى من الاستدعاء مأخوذة مباشرةً من proof الذي قدّمه المُرسِل. وبالمصادفة، كان في OpenVM 2.0 دالّة verify ذات نوع محدد، وselector الخاص بها هو 0x24270d54. فإذا بدأت proof بهذه البايتات الأربع، لم تنتقل إلى fallback، بل دخلت هذه الدالّة، التي تقرأ المدخلات العامة من موضع يتحكم فيه المستدعي. والنتيجة: كان بالإمكان استخدام إثبات صحيح قديم للتصديق على جذر حالة وجذر سحوبات جديدين. وبكلام أبسط، كان من الممكن نظريًا تأكيد جذر سحوبات مختلق من العدم، لتصبح أموال الجسر هدفًا.
المفارقة هنا أن هذا العقد نُشر عند ترقية OpenVM v2.0 في 22 سبتمبر، وكان أحد دوافع الترقية المعلنة إصلاح التنبيه الأمني الخاص بـ v1.7.0، وفيه بند بعنوان «OpenVmHalo2Verifier self-call can bypass proof verification»، وكان أيضًا تجاوزًا في طبقة wrapper الخاصة بالمدقّق. وصُنّفت تلك الترقية على أنها ترقية صيانة، فأُعلن عنها فقط من دون تصويت. أُصلح ثغرة في طبقة wrapper، لكن العقد الجديد الذي حلّ محلّه فتح ثغرة أخرى في الطبقة نفسها، وظلّ معرّضًا لها 49 يومًا (من 9/22 إلى 11/10).
لماذا لم تقع مشكلة؟ يذكر التقرير بنفسه أن الاستغلال كان يتطلب دور prover مُصرّحًا به، أو تفعيل وضع الدفعات القسرية، الذي لا يُتاح إلا بعد مرور 7 أيام من دون تأكيد نهائي. وخلال فترة وجود العقد المعيب على الإنترنت، كانت عمليات التأكيد النهائي الـ748 كلها تستند إلى proofs سليمة، ولم يُفعّل الوضع القسري مطلقًا.
إذًا، ما حمى النظام فعليًا خلال هذه الأيام الـ49 لم يكن رياضيات ZK، بل حقيقة أن «prover الخاصة بـ Scroll وحدها تستطيع تقديم proofs». عادةً ما ينتقد الناس مركزية prover في L2، لكن المركزية هذه المرة هي التي أغلقت الباب في وجه الهجوم. والأكثر إيلامًا أن ننظر إلى الأمر من الجهة الأخرى: حجرة الهروب التي صُممت لمقاومة الرقابة، والمخصصة لفترة السبعة أيام، تتحول بمجرد تفعيلها إلى مدخل هجوم متاح لأي شخص.
تقييمي للإفصاح نفسه إيجابي. أبلغ الباحث الأمني الأخلاقي ZHOUCHUNGONG عن المشكلة في 11/3، وسُجّل عقد الإصلاح في 11/10. ونُشرت العناوين الجديدة وطلب الدمج الخاص بالإصلاح ومعاملة التسجيل كلها، مع خطوات تمكّن أي شخص من التحقق بنفسه؛ وهذا أفضل مما تفعله مشاريع كثيرة. لكن عبارة «ما دامت لديك validity proof، فلا حاجة إلى الوثوق بالمشغّل» دحضها هذه المرة تقرير المشروع نفسه. ومن يملك أصولًا على L2، فلا يسأل فقط إن كان النظام يستخدم ZK، بل عليه أن يسأل من يشغّل prover، وكم مرة يتغير عقد التحقق، وهل يجري تصويت وتدقيق عند تغييره. لم يذكر التقرير مقدار المكافأة، ولا ما إذا كان العقد الجديد قد خضع لتدقيق خارجي، لذلك لن أخمّن.
#Scroll #إيثيريومL2
ذهبتُ إلى المنشور الأصلي في المنتدى (11/11 14:24 UTC). المشكلة كانت في عقد التحقق من bundle proof على الشبكة الرئيسية، ZkEvmVerifierPostFeynman (0x7966…B254). كان يركّب المدخلات يدويًا، ويستخدم raw staticcall لاستدعاء مدقّق Halo2 في OpenVM 2.0، بينما كانت البايتات الأربع الأولى من الاستدعاء مأخوذة مباشرةً من proof الذي قدّمه المُرسِل. وبالمصادفة، كان في OpenVM 2.0 دالّة verify ذات نوع محدد، وselector الخاص بها هو 0x24270d54. فإذا بدأت proof بهذه البايتات الأربع، لم تنتقل إلى fallback، بل دخلت هذه الدالّة، التي تقرأ المدخلات العامة من موضع يتحكم فيه المستدعي. والنتيجة: كان بالإمكان استخدام إثبات صحيح قديم للتصديق على جذر حالة وجذر سحوبات جديدين. وبكلام أبسط، كان من الممكن نظريًا تأكيد جذر سحوبات مختلق من العدم، لتصبح أموال الجسر هدفًا.
المفارقة هنا أن هذا العقد نُشر عند ترقية OpenVM v2.0 في 22 سبتمبر، وكان أحد دوافع الترقية المعلنة إصلاح التنبيه الأمني الخاص بـ v1.7.0، وفيه بند بعنوان «OpenVmHalo2Verifier self-call can bypass proof verification»، وكان أيضًا تجاوزًا في طبقة wrapper الخاصة بالمدقّق. وصُنّفت تلك الترقية على أنها ترقية صيانة، فأُعلن عنها فقط من دون تصويت. أُصلح ثغرة في طبقة wrapper، لكن العقد الجديد الذي حلّ محلّه فتح ثغرة أخرى في الطبقة نفسها، وظلّ معرّضًا لها 49 يومًا (من 9/22 إلى 11/10).
لماذا لم تقع مشكلة؟ يذكر التقرير بنفسه أن الاستغلال كان يتطلب دور prover مُصرّحًا به، أو تفعيل وضع الدفعات القسرية، الذي لا يُتاح إلا بعد مرور 7 أيام من دون تأكيد نهائي. وخلال فترة وجود العقد المعيب على الإنترنت، كانت عمليات التأكيد النهائي الـ748 كلها تستند إلى proofs سليمة، ولم يُفعّل الوضع القسري مطلقًا.
إذًا، ما حمى النظام فعليًا خلال هذه الأيام الـ49 لم يكن رياضيات ZK، بل حقيقة أن «prover الخاصة بـ Scroll وحدها تستطيع تقديم proofs». عادةً ما ينتقد الناس مركزية prover في L2، لكن المركزية هذه المرة هي التي أغلقت الباب في وجه الهجوم. والأكثر إيلامًا أن ننظر إلى الأمر من الجهة الأخرى: حجرة الهروب التي صُممت لمقاومة الرقابة، والمخصصة لفترة السبعة أيام، تتحول بمجرد تفعيلها إلى مدخل هجوم متاح لأي شخص.
تقييمي للإفصاح نفسه إيجابي. أبلغ الباحث الأمني الأخلاقي ZHOUCHUNGONG عن المشكلة في 11/3، وسُجّل عقد الإصلاح في 11/10. ونُشرت العناوين الجديدة وطلب الدمج الخاص بالإصلاح ومعاملة التسجيل كلها، مع خطوات تمكّن أي شخص من التحقق بنفسه؛ وهذا أفضل مما تفعله مشاريع كثيرة. لكن عبارة «ما دامت لديك validity proof، فلا حاجة إلى الوثوق بالمشغّل» دحضها هذه المرة تقرير المشروع نفسه. ومن يملك أصولًا على L2، فلا يسأل فقط إن كان النظام يستخدم ZK، بل عليه أن يسأل من يشغّل prover، وكم مرة يتغير عقد التحقق، وهل يجري تصويت وتدقيق عند تغييره. لم يذكر التقرير مقدار المكافأة، ولا ما إذا كان العقد الجديد قد خضع لتدقيق خارجي، لذلك لن أخمّن.
#Scroll #إيثيريومL2