Merkle trees में second preimage attack तब हो सकता है जब Merkle tree में किसी intermediate node को एक leaf के रूप में प्रस्तुत किया जाता है।
इस attack का नाम काफी भ्रामक (misleading) है क्योंकि यह संकेत देता है कि hashes का एक second preimage होता है। आधुनिक hash functions में एक से अधिक (computable) preimages नहीं होते हैं।
इस attack के लिए एक बेहतर नाम “node as leaf attack” या “shortened proof attack” हो सकता है।
पूर्व-आवश्यकताएं
हम मानकर चलते हैं कि पाठक Merkle trees और Merkle proofs से परिचित हैं।
Notation
हम x के hash को दर्शाने के लिए h(x) का उपयोग करते हैं। h(x + y), x और y के concatenation (जोड़) का hash है। इस लेख में, हम अपने hash function के रूप में keccak256 पर ध्यान केंद्रित करेंगे; एक विशिष्ट function को चुनने से लेख में आगे के कुछ तर्कों को स्पष्ट करने में मदद मिलेगी। हालाँकि, ध्यान रखें कि इस लेख के विचार किसी भी hash function पर लागू होंगे। हम Merkle tree की leaves को ℓ से दर्शाते हैं। ith leaf को ℓᵢ से दर्शाया जाता है।
Attack का एक उदाहरण
मान लीजिए कि हम नीचे दिए गए tree में leaf 2 (ℓ₂) के लिए एक proof बनाना चाहते हैं। leaf ℓ₂ होगा, और proof \[h(ℓ₁), h(b), h(f)\] होगा। a, b, c, …, g की values उनके child values का concatenation हैं। हम proof को स्वीकार करते हैं यदि h(g) Merkle root के बराबर हो।

proof \[h(ℓ₁), h(b), h(f)\] होगा जिसे हरे रंग में चिह्नित किया गया है। root तक का proof इस प्रकार है:
h(a) = h(h(ℓ₁) + h(ℓ₂))
h(e) = h(h(a) + h(b))
h(g) = h(h(e) + h(f))
return root == h(g)
The second preimage attack
क्या होगा यदि attacker a को एक leaf के रूप में और \[h(b), h(f)\] को proof के रूप में प्रदान करे?

contract a को एक leaf के रूप में देखेगा, जहाँ a = h(ℓ₁), h(ℓ₂)) है। यदि proof [h(b), h(f)] है, तो Merkle proof को valid (वैध) मानकर स्वीकार कर लिया जाएगा।
मूलतः, यदि एक Merkle proof valid है, तो उसका एक छोटा संस्करण (shortened version) भी valid होगा यदि हम मूल proof की पहली value को एक leaf के रूप में पास करते हैं।
इसलिए, attacker ने एक “leaf” और एक ऐसा proof प्रदान किया होगा जिसे contract स्वीकार करता है, लेकिन दी गई “leaf” मूल Merkle tree में एक leaf नहीं है!
तो हम इसे होने से कैसे रोक सकते हैं?
OpenZeppelin की चेतावनी
OpenZeppelin Merkle tree library में, हम comments में कुछ समाधानों के साथ-साथ चेतावनी (warning) देखते हैं। हम निम्नलिखित अनुभागों में उनके समाधानों की व्याख्या करते हैं।

निम्नलिखित दो अनुभाग यह स्पष्ट करते हैं कि ये दो समाधान इस समस्या को कैसे रोकते हैं।
इस attack के लिए 64 byte leaves की आवश्यकता होती है
इस attack के काम करने के लिए, attacker को intermediate node का preimage पास करना होता है, न कि उसकी hash value। इसका मतलब है कि उसे hash(a) के बजाय a को leaf के रूप में पास करना होगा। चूँकि Solidity 32 byte hashes का उपयोग करती है, इसलिए a = h(ℓ₁) + h(ℓ₂) की लंबाई 64 bytes होगी।
यदि contract इनपुट के रूप में 64 byte leaves को स्वीकार नहीं करता है, तो यह attack काम नहीं करेगा।
अर्थात्, यदि leaf के इनपुट की लंबाई 64 bytes के अलावा कुछ और है, तो h(ℓ₁) + h(ℓ₂) को एक गलत leaf value के रूप में पास करना असंभव है।
बचाव के रूप में leaf के लिए एक अलग hash का उपयोग करना
यदि हमारे एप्लिकेशन को किसी कारण से 64 byte leaves को स्वीकार करने की आवश्यकता है, तो हम leaves के लिए proof से अलग hash का उपयोग करके इस attack को रोक सकते हैं।
अर्थात्, जब leaf को पहली बार hash किया जाता है, तो हम उस hash से अलग hash का उपयोग करते हैं जिसका उपयोग हम root तक hash करने के लिए करते हैं। यह attacker को एक intermediate node को “reconstruct” करने से रोकेगा जैसे कि वह एक leaf हो। ऊपर दिए गए चित्र का उपयोग करते हुए, attacker गलत “leaf” बनाने के लिए h(a) का उपयोग कर रहा है। हालाँकि, यदि leaves को h’(a) के माध्यम से पास किया जाता है, तो intermediate value को reconstruct नहीं किया जा सकता है।
OpenZeppelin एक “different hash” के रूप में double hash का उपयोग करता है
एक अलग hash function (जैसे कि precompile के माध्यम से) का उपयोग करने के बजाय, जिसमें अधिक gas खर्च होगी, OpenZeppelin बस leaf को दो बार hash करता है। अर्थात्, h’(x) = h(h(x))।
हमने यह दिखाने के लिए हरे रंग की अंडरलाइन (green underlines) का उपयोग किया है कि underlying data से leaf node के निर्माण के लिए hash को दो बार कहाँ लिया गया है:

ध्यान दें कि library आपको दो बार hash लागू करने के लिए बाध्य नहीं करती है — वास्तव में यह आपको leaf को hash करने के लिए बिल्कुल भी बाध्य नहीं करती है! leaf को hash न करने से second preimage attack के अलावा भी अन्य attack vectors खुल सकते हैं — अंत में दी गई अभ्यास समस्या (practice problem) देखें।
निष्कर्ष
The second preimage attack इसलिए काम करता है क्योंकि हम एक valid proof का एक छोटा संस्करण (shortened version) प्रदान कर सकते हैं और Merkle root को फिर से बना सकते हैं। Merkle roots का एक preimage होता है — हालाँकि, root increments (क्रमशः) में बनाया जाता है — न कि पूरे proof को एक ही बार में hash करके। sequence में आगे के बिंदु से proof शुरू करके, हम एक वैकल्पिक इनपुट प्राप्त कर सकते हैं जो समान root उत्पन्न करता है।
इस attack से बचाव करना आसान है — बस non-leaf values को leaves के रूप में व्याख्या (interpret) करने की अनुमति न दें।
अभ्यास प्रश्न
निम्नलिखित Capture the Flag अभ्यास Merkle Proofs का अनुचित तरीके से उपयोग करता है और इसलिए इसे hack किया जा सकता है:
RareSkills Riddles: Furry Fox Friends
RareSkills के साथ और जानें
हमारे शैक्षिक प्रस्तावों (educational offerings) को देखने के लिए कृपया हमारा blockchain bootcamp देखें।
मूल रूप से 24 नवंबर, 2023 को प्रकाशित