हम में से लगभग सभी ने कुछ गणना के लिए डेटा दर्ज करने के लिए Google पत्रक या Microsoft Excel का उपयोग किया है। मान लीजिए कि आप कर्मचारियों के नाम, उनके फोन नंबर, शीर्षक और उनके द्वारा अर्जित वेतन दर्ज करना चाहते हैं।
अपने सरलतम रूप में, शीट्स या एक्सेल में कोई रिकॉर्ड या मामला इस तरह दिखेगा:
जैसा कि आप बता सकते हैं, कर्मचारी का नाम और शीर्षक दोनों में टेक्स्ट होता है जबकि फोन नंबर और वेतन में संख्याओं का क्रम होता है।
इसलिए, शब्दार्थ के दृष्टिकोण से, हम, मनुष्य के रूप में, समझते हैं कि वास्तविक दुनिया में इन क्षेत्रों का क्या अर्थ है और उनके बीच अंतर कर सकते हैं।
स्पष्ट रूप से, जबकि आपको अंतर बताने के लिए कंप्यूटर विज्ञान में डिग्री की आवश्यकता नहीं है, एक संकलक या दुभाषिया इस डेटा को कैसे संसाधित करता है?
यह वह जगह है जहां डेटा प्रकार आते हैं, और कुछ ऐसा है जो प्रोग्रामर या तो प्रोग्रामिंग भाषा के आधार पर निर्दिष्ट करने के लिए समय लेते हैं या नहीं।
दूसरे शब्दों में, कर्मचारी के नाम और शीर्षक के अंतर्गत आने वाले डेटा बिंदुओं को स्ट्रिंग्स कहा जाता है। बेशक, कोई दशमलव बिंदु न होने के कारण वेतन स्पष्ट रूप से एक पूर्णांक है। सीधे शब्दों में कहें, ये डेटा प्रकार हैं जिन्हें कोड करते समय इस तरह घोषित किया जाना चाहिए, ताकि उस डेटा प्रकार से जुड़े सही संचालन ही किए जा सकें।
इस प्रकार हम एक पूर्णांक डेटा प्रकार को सॉलिडिटी में घोषित करते हैं:
उस ने कहा, उपरोक्त स्प्रैडशीट में फ़ोन नंबर फ़ील्ड में एक डेटा बिंदु होता है जिसका उपयोग एक अद्वितीय स्ट्रिंग के रूप में किया जाएगा, लेकिन वह चर्चा किसी और दिन के लिए है। अभी के लिए, हमारा ध्यान आदिम डेटा प्रकार पर होगा, जिसके साथ हम सभी ने बुनियादी अंकगणितीय प्रदर्शन किया है।
हां, हम पूर्णांक डेटा प्रकार के बारे में बात कर रहे हैं, जो प्रमुख अंकगणितीय कार्यों के लिए महत्वपूर्ण होने के बावजूद, किसी भी गणना के लिए सीमित सीमा है।
संभवतः, वास्तविक दुनिया में पूर्णांक अतिप्रवाह का सबसे लोकप्रिय उदाहरण वाहनों पर होता है। अन्यथा ओडोमीटर के रूप में जाना जाता है, ये उपकरण आम तौर पर ट्रैक करते हैं कि वाहन ने कितने मील की यात्रा की है।
तो, छह अंकों के ओडोमीटर में 999999 के अहस्ताक्षरित पूर्णांक मान तक पहुँचने के बाद क्या होता है?
आदर्श रूप से, एक बार और मील जुड़ जाने के बाद, यह मान 1000000 तक पहुँच जाना चाहिए, है ना? लेकिन ऐसा नहीं होता है क्योंकि सातवें अंक का प्रावधान है।
इसके बजाय, मील की यात्रा का मान 000000 पर रीसेट हो जाता है, जैसा कि नीचे दिखाया गया है:
परिभाषा के अनुसार, चूंकि सातवाँ अंक उपलब्ध नहीं है, इसका परिणाम 'अतिप्रवाह' में होता है क्योंकि सटीक मान का प्रतिनिधित्व नहीं किया जाता है।
आपको तस्वीर मिलती है, है ना?
इसके विपरीत, विपरीत भी हो सकता है, भले ही यह इतना सामान्य न हो। दूसरे शब्दों में, जब रिकॉर्ड किया गया मान सीमा में उपलब्ध न्यूनतम मूल्य से कम होता है और जिसे अन्यथा 'अंडरफ्लो' के रूप में जाना जाता है।
जैसा कि हम सभी जानते हैं, कंप्यूटर मेमोरी में पूर्णांकों को उनके बाइनरी समतुल्य के रूप में संग्रहीत करेंगे। अब, सरलता के लिए, मान लें कि आप 8-बिट रजिस्टर का उपयोग कर रहे हैं।
= 2⁸*1 + 2⁷*1 + 2⁶*1 + 2⁵*1 + 2⁴*1 + 2³*1 + 2²*1 + 2¹*1 + 2⁰*1
= 256 + 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1
= 111111111
जहां प्रत्येक बिट 1 है, और जैसा कि आप बता सकते हैं, आप उस मान को संग्रहीत नहीं कर सकते जो अधिक है।
दूसरी ओर, यदि आप 8-बिट रजिस्टर में नंबर 0 को स्टोर करना चाहते हैं, तो यह इस तरह दिखेगा:
= 2⁸*0 + 2⁷*0 + 2⁶*0 + 2⁵*0 + 2⁴*0 + 2³*0 + 2²*0 + 2¹*0 + 2⁰*0
= 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
= 000000000
जहां प्रत्येक बिट 0 है, जो आपको बताएगी कि आप कम मान को स्टोर नहीं कर सकते।
दूसरे शब्दों में, ऐसे 8-बिट रजिस्टर के लिए अनुमत पूर्णांकों की सीमा 0-511 है। तो, क्या ऐसे रजिस्टर में पूर्णांक 512 या -1 को स्टोर करना संभव है?
बिल्कुल नहीं। नतीजतन, आप ओडोमीटर उदाहरण में यात्रा की गई मील के रीसेट मान के समान एक मान संग्रहीत करेंगे, लेकिन बाइनरी मानों के रूप में।
जाहिर है, ऐसी संख्या को आराम से समायोजित करने के लिए आपको कुछ और बिट्स के साथ रजिस्टरों की आवश्यकता होगी। वरना एक बार फिर ओवरफ्लो की स्थिति का जोखिम उठाएं।
हस्ताक्षरित पूर्णांकों के मामले में, हम ऋणात्मक पूर्णांकों को भी संग्रहीत करते हैं। इसलिए, जब हम एक संख्या को संग्रहीत करने का प्रयास करते हैं जो स्वीकृत सीमा से छोटी है, या शून्य से कम है, जैसा कि ऊपर दिखाया गया है, अंडरफ़्लो होता है।
फिर भी, चूंकि कोई भी गणना करने का बिंदु नियतात्मक परिणाम प्राप्त करना है, यह सबसे अच्छा कष्टप्रद हो सकता है लेकिन उनके सबसे बुरे कारण से लाखों का नुकसान होता है। विशेष रूप से, जब ये पूर्णांक ओवरफ़्लो या अंडरफ़्लो त्रुटियां स्मार्ट अनुबंधों में होती हैं।
जबकि पूर्णांक अतिप्रवाह और अंडरफ्लो लगभग दशकों से हैं, स्मार्ट अनुबंध में बग के रूप में उनके अस्तित्व ने दांव बढ़ा दिया है। जब हमलावर ऐसी त्रुटियों का उपयोग करते हैं, तो वे बड़ी मात्रा में टोकन के स्मार्ट अनुबंध को निकाल सकते हैं।
संभवतः पहली बार इस प्रकार का बग 74638 ब्लॉक के साथ हुआ था, जिसने तीन पतों के लिए अरबों बिटकॉइन बनाए। सॉफ्ट फोर्क के माध्यम से इस त्रुटि को हल करने में घंटों लगेंगे और जिसने ब्लॉक को छोड़ दिया, इस प्रकार लेन-देन को अमान्य कर दिया।
एक के लिए, 21 मिलियन बिटकॉइन मूल्य से बड़े लेनदेन को अस्वीकार कर दिया गया था। यह अतिप्रवाह लेन-देन के लिए अलग नहीं था, जैसा कि उपरोक्त तीनों खातों में इतना पैसा भेजा गया था।
हालाँकि, एथेरियम स्मार्ट कॉन्ट्रैक्ट्स ने पूर्णांक अतिप्रवाह और अंडरफ़्लो का भी अनुभव किया है, जिसमें ब्यूटीचैन भी एक प्रमुख उदाहरण है।
इस मामले में, स्मार्ट अनुबंध में कोड की एक दोषपूर्ण रेखा थी:
नतीजतन, हमलावर सैद्धांतिक रूप से असीमित मात्रा में बीईसी टोकन प्राप्त करने में सक्षम थे, जो सैद्धांतिक रूप से (2²⁵⁶) -1 के मूल्य के बराबर हो सकता है।
अब, आइए एक स्मार्ट अनुबंध का एक और उदाहरण देखें जिसमें पूर्णांक अंडरफ़्लो/ओवरफ़्लो होता है।
पहली नज़र में, दो अनुबंध हैं जो इस उदाहरण में परस्पर क्रिया करते हैं, और जो दर्शाता है कि पूर्णांक अतिप्रवाह के मामले में क्या होता है।
जैसा कि आप नीचे देख सकते हैं, TimeLock अनुबंध, आपको धन जमा करने और निकालने की अनुमति देता है, लेकिन एक अंतर के साथ: आप बाद वाले को केवल कुछ समय के बाद ही कर सकते हैं। इस मामले में, आप केवल एक सप्ताह के समय में ही अपना पैसा निकाल सकते हैं।
हालाँकि, एक बार जब आप अटैक कॉन्ट्रैक्ट में अटैक फ़ंक्शन को कॉल करते हैं, तो समय लॉक प्रभावी नहीं होता है और यही कारण है कि हमलावर शेष राशि को तुरंत वापस ले सकता है।
दूसरे शब्दों में, type(uint).max+1-timeLock.locktime(address(this)) स्टेटमेंट के साथ पूर्णांक ओवरफ्लो होने के कारण, टाइम लॉक समाप्त हो जाता है।
उदाहरण के लिए, एक बार जब आप उपरोक्त कोड का उपयोग करके दोनों स्मार्ट अनुबंधों को तैनात कर लेते हैं, तो आप नीचे दिखाए गए अनुसार TimeLock अनुबंध में जमा और निकासी कार्यों को लागू करके परीक्षण कर सकते हैं कि क्या टाइमलॉक होल्ड करता है:
जैसा कि आप देख सकते हैं, 2 ईथर की राशि का चयन करके, हमें ऊपर दिखाए गए 2 ईथर का स्मार्ट कॉन्ट्रैक्ट बैलेंस मिलता है:
विशेष रूप से, 2 ईथर का संतुलन रखने वाले विशिष्ट पते को बैलेंस फ़ंक्शन के क्षेत्र में पता जोड़कर और बैलेंस बटन पर क्लिक करके चेक किया जा सकता है:
हालाँकि, जैसा कि ऊपर उल्लेख किया गया है, आप समय लॉक होने के कारण अभी तक इन फंडों को वापस नहीं ले सकते हैं। जब आप विथड्रॉ फंक्शन को हिट करने के बाद कंसोल को देखते हैं, तो आपको लाल 'x' चिन्ह द्वारा इंगित एक त्रुटि मिलेगी। जैसा कि आप नीचे देख सकते हैं, इस त्रुटि का कारण अनुबंध द्वारा प्रदान किया गया है "लॉक समय समाप्त नहीं हुआ":
अब, आइए नीचे दिखाए गए अनुसार तैनात हमले के अनुबंध को देखें:
अब, हमले के कार्य को शुरू करने के लिए, आपको 1 ईथर या अधिक का मूल्य जमा करना होगा। इसलिए, इस उदाहरण में, हमने 2 ईथर का चयन किया है, जैसा कि नीचे दिखाया गया है:
इसके बाद 'अटैक' मारा। आप पाएंगे कि आपके द्वारा जमा किया गया 2 ईथर तुरंत वापस ले लिया जाएगा और हमले के अनुबंध में जोड़ा जाएगा जैसा कि नीचे दिए गए 2 ईथर के संतुलन से पता चलता है:
स्पष्ट रूप से, ऐसा होने की उम्मीद नहीं है क्योंकि जैसे ही आप डिपॉजिट करते हैं, लॉन्ग टाइम लॉक प्रभावी हो जाता है। निश्चित रूप से, जैसा कि हम जानते हैं कि type(uint).max+1-timeLock.locktime(address(this)) स्टेटमेंट वृद्धि लॉकटाइम फ़ंक्शन का उपयोग करके लॉक समय को कम करता है। यही कारण है कि हम ईथर बैलेंस को तुरंत वापस लेने में सक्षम हैं।
जो हमें स्पष्ट प्रश्न पर लाता है: क्या पूर्णांक अतिप्रवाह और अंडरफ़्लो भेद्यता को ठीक करने के तरीके हैं?
यह स्वीकार करते हुए कि पूर्णांक अतिप्रवाह/अंडरफ्लो भेद्यता विनाशकारी हो सकती है, इस बग के लिए कुछ सुधार किए गए हैं। आइए इन दोनों सुधारों को देखें और देखें कि वे इस तरह की त्रुटि के आसपास कैसे काम करते हैं:
Open Zeppelin, एक संगठन के रूप में, जब साइबर सुरक्षा तकनीक और सेवाओं की बात आती है, तो SafeMath लाइब्रेरी अपने स्मार्ट कॉन्ट्रैक्ट डेवलपमेंट रिपॉजिटरी का एक हिस्सा होने के साथ बहुत कुछ प्रदान करती है। इस रेपो में ऐसे अनुबंध शामिल हैं जिन्हें आपके स्मार्ट अनुबंध कोड में आयात किया जा सकता है, जिसमें SafeMath लाइब्रेरी उनमें से एक है।
आइए देखते हैं कि SafeMath.sol के भीतर कोई एक फ़ंक्शन पूर्णांक अतिप्रवाह के लिए कैसे जाँच करता है:
अब, एक बार a+b की गणना हो जाने के बाद, यह देखने के लिए जाँच करें कि क्या c<a होता है। बेशक, यह केवल पूर्णांक अतिप्रवाह के मामले में ही सही होगा।
सॉलिडिटी का कंपाइलर वर्जन 0.8.0 और ऊपर तक पहुंचने के साथ, पूर्णांक ओवरफ्लो और अंडरफ्लो के लिए चेक अब अंतर्निहित हैं। इसलिए, कोई भी इस लाइब्रेरी का उपयोग भाषा और इस लाइब्रेरी दोनों का उपयोग करते समय इस भेद्यता की जांच के लिए कर सकता है। बेशक, यदि आपके स्मार्ट अनुबंध को एक कंपाइलर संस्करण की आवश्यकता है जो 0.8.+ से कम है, तो आपको अतिप्रवाह या अंडरफ़्लो से बचने के लिए इस लाइब्रेरी का उपयोग करना होगा।
अब, जैसा कि पहले उल्लेख किया गया है, यदि आपके स्मार्ट अनुबंध के लिए, आप एक कंपाइलर संस्करण का उपयोग कर रहे हैं जो कि 0.8.0 और ऊपर है, तो इस संस्करण में ऐसी भेद्यता के लिए एक अंतर्निहित चेकर है।
वास्तव में, यह सत्यापित करने के लिए कि क्या यह ऊपर दिए गए स्मार्ट अनुबंध के साथ काम करता है, जब संकलक संस्करण को "^ 0.8.0" में बदलकर इसे फिर से तैनात किया जाता है, तो निम्न 'रिवर्ट' त्रुटि प्राप्त होती है:
बेशक, 2 ईथर का कोई डिपॉजिट नहीं किया जाता है, जो कि टाइम लॉक वैल्यू के ओवरफ्लो पर जांच के कारण होता है। नतीजतन, पहले स्थान पर कोई धनराशि जमा नहीं होने के कारण कोई निकासी संभव नहीं है।
निस्संदेह, अटैक.अटैक () फ़ंक्शन कॉल यहां काम नहीं करता है, इसलिए यह सब अच्छा है!
अगर आपको इस लंबे ब्लॉग पोस्ट से कुछ भी इकट्ठा करना चाहिए, तो वह यह है कि इस भेद्यता को अनदेखा करना, जैसा कि बीईसी हमले से हुआ, महंगा साबित हो सकता है। जैसा कि आप यह भी बता सकते हैं, यदि अनियंत्रित छोड़ दिया जाए, तो गैर-दुर्भावनापूर्ण त्रुटियों का होना आसान है। या हैकर्स के लिए इस भेद्यता का फायदा उठाना उतना ही आसान है।
जिसके बारे में बोलते हुए, और BEC हमला कैसे हुआ, इस बारे में हमारी समझ का उपयोग करते हुए, इस भेद्यता को पहचानने से आपके स्मार्ट अनुबंध लिखते समय किसी भी हमले को रोकने में मदद मिल सकती है, प्रस्ताव पर सुधारों के लिए धन्यवाद। भले ही कई अन्य स्मार्ट अनुबंध भेद्यताएं हैं जो आपको फंसाने के इंतजार में हैं।