Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
SoliditySecurity — Solidity Security | Kitploit
उपकरण/GitHubGitHub/al1ex/soliditysecurity
Vulnerability AnalysisCode AnalysisLearning & EducationCurated Resources
GitHubal1ex/soliditysecurity

SoliditySecurity

Solidity Security

रिपॉजिटरी देखें
355 साल पहलेअभी तक समीक्षित नहीं

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

यह क्या है

यह पोस्ट एक अपेक्षाकृत गहन और अद्यतन परिचयात्मक पोस्ट होने का प्रयास करती है, जिसमें Solidity डेवलपर्स द्वारा की गई पिछली गलतियों का विवरण दिया गया है, ताकि भविष्य के डेवलपर्स इतिहास को दोहराने से बच सकें।

विषय सूची

1. री-एंट्रेंसी

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: The DAO

2. अंकगणितीय ओवर/अंडरफ्लो

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया के उदाहरण: PoWHC और बैच ट्रांसफर ओवरफ्लो (CVE-2018-10299)

3. अप्रत्याशित Ether

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया के उदाहरण: अज्ञात

4. Delegatecall

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया के उदाहरण: Parity Multisig Wallet (दूसरा हैक)

5. डिफ़ॉल्ट विज़िबिलिटीज़

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: Parity MultiSig Wallet (पहला हैक)

6. एन्ट्रॉपी भ्रम

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: PRNG कॉन्ट्रैक्ट्स

7. बाहरी कॉन्ट्रैक्ट संदर्भ

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: री-एंट्रेंसी हनी पॉट

8. शॉर्ट एड्रेस/पैरामीटर हमला

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: अज्ञात

9. बिना जाँचे गए CALL रिटर्न मान

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया के उदाहरण: Etherpot और King of the Ether

10. रेस कंडीशन / फ्रंट रनिंग

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया के उदाहरण: ERC20 और Bancor

11. डिनायल ऑफ सर्विस (DOS)

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: GovernMental

12. ब्लॉक टाइमस्टैम्प हेरफेर

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: GovernMental

13. कंस्ट्रक्टर्स सावधानी से

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: Rubixi

14. अप्रारंभित स्टोरेज पॉइंटर्स

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया के उदाहरण: हनी पॉट्स: OpenAddressLottery और CryptoRoulette

15. फ्लोटिंग पॉइंट्स और संख्यात्मक परिशुद्धता

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: Ethstick

16. tx.origin प्रमाणीकरण

  • कमज़ोरी
  • निवारक तकनीकें
  • वास्तविक दुनिया का उदाहरण: अज्ञात

Ethereum की विचित्रताएँ

  • कुंजीहीन Ether
  • वन-टाइम एड्रेस
  • एकल ट्रांज़ैक्शन एयरड्रॉप

दिलचस्प क्रिप्टो-संबंधित हैक्स/बग्स की सूची

संदर्भ / आगे पढ़ने की सूची

  • Ethereum Wiki - सुरक्षा
  • Solidity Docs - सुरक्षा संबंधी विचार
  • Consensus - Ethereum स्मार्ट कॉन्ट्रैक्ट सर्वोत्तम अभ्यास
  • Ethereum सुरक्षा कमज़ोरियों, हैक्स और उनके समाधानों का इतिहास
  • विकेंद्रीकृत एप्लिकेशन सुरक्षा परियोजना (DASP) 2018 का टॉप 10
  • Ethereum स्मार्ट कॉन्ट्रैक्ट्स पर हमलों का एक सर्वेक्षण
  • Ethereum स्मार्ट कॉन्ट्रैक्ट सुरक्षा
  • Underhanded Solidity प्रतियोगिता से सीखे गए सबक

1. री-एंट्रेंसी

Ethereum स्मार्ट कॉन्ट्रैक्ट्स की एक विशेषता अन्य बाहरी कॉन्ट्रैक्ट्स के कोड को कॉल करने और उपयोग करने की क्षमता है। कॉन्ट्रैक्ट्स आमतौर पर ether को भी संभालते हैं, और इस तरह अक्सर विभिन्न बाहरी उपयोगकर्ता एड्रेसों पर ether भेजते हैं। बाहरी कॉन्ट्रैक्ट्स को कॉल करने, या किसी एड्रेस पर ether भेजने के लिए कॉन्ट्रैक्ट द्वारा एक बाहरी कॉल किया जाना आवश्यक है। इन बाहरी कॉल्स को हमलावरों द्वारा हाईजैक किया जा सकता है, जिससे वे कॉन्ट्रैक्ट को आगे का कोड निष्पादित करने के लिए मजबूर करते हैं (अर्थात फॉलबैक फ़ंक्शन के माध्यम से) , जिसमें स्वयं के भीतर वापस कॉल करना शामिल है। इस प्रकार कोड निष्पादन कॉन्ट्रैक्ट में "पुनः-प्रवेश" करता है। इस प्रकार के हमलों का उपयोग कुख्यात DAO हैक में किया गया था।

री-एंट्रेंसी हमलों पर अधिक पढ़ने के लिए, देखें स्मार्ट कॉन्ट्रैक्ट्स पर री-एंट्रेंसी हमला और Consensus - Ethereum स्मार्ट कॉन्ट्रैक्ट सर्वोत्तम अभ्यास.

कमज़ोरी

यह हमला तब हो सकता है जब कोई कॉन्ट्रैक्ट किसी अज्ञात एड्रेस पर ether भेजता है। एक हमलावर किसी बाहरी एड्रेस पर सावधानीपूर्वक एक ऐसा कॉन्ट्रैक्ट बना सकता है जिसमें फॉलबैक फ़ंक्शन में दुर्भावनापूर्ण कोड हो। इस प्रकार, जब कोई कॉन्ट्रैक्ट इस एड्रेस पर ether भेजता है, तो यह दुर्भावनापूर्ण कोड को लागू करेगा। आमतौर पर दुर्भावनापूर्ण कोड कमज़ोर कॉन्ट्रैक्ट पर एक फ़ंक्शन निष्पादित करता है, जो डेवलपर द्वारा अपेक्षित नहीं किए गए ऑपरेशन करता है। "री-एंट्रेंसी" नाम इस तथ्य से आया है कि बाहरी दुर्भावनापूर्ण कॉन्ट्रैक्ट कमज़ोर कॉन्ट्रैक्ट पर एक फ़ंक्शन को वापस कॉल करता है और कमज़ोर कॉन्ट्रैक्ट पर एक मनमाने स्थान पर कोड निष्पादन में "पुनः-प्रवेश" करता है।

इसे स्पष्ट करने के लिए, सरल कमज़ोर कॉन्ट्रैक्ट पर विचार करें, जो एक Ethereum तिजोरी के रूप में कार्य करता है जो जमाकर्ताओं को प्रति सप्ताह केवल 1 ether निकालने की अनुमति देता है।

EtherStore.sol:```solidity contract EtherStore {

root@kitploit:~
uint256 public withdrawalLimit = 1 ether;
mapping(address => uint256) public lastWithdrawTime;
mapping(address => uint256) public balances;

function depositFunds() public payable {
    balances[msg.sender] += msg.value;
}

function withdrawFunds (uint256 _weiToWithdraw) public {
    require(balances[msg.sender] >= _weiToWithdraw);
    // limit the withdrawal
    require(_weiToWithdraw <= withdrawalLimit);
    // limit the time allowed to withdraw
    require(now >= lastWithdrawTime[msg.sender] + 1 weeks);
    require(msg.sender.call.value(_weiToWithdraw)());
    balances[msg.sender] -= _weiToWithdraw;
    lastWithdrawTime[msg.sender] = now;
}

}

root@kitploit:~
यह कॉन्ट्रैक्ट दो सार्वजनिक फ़ंक्शन रखता है। `depositFunds()` और `withdrawFunds()`। `depositFunds()` फ़ंक्शन केवल भेजने वाले के बैलेंस को बढ़ाता है। `withdrawFunds()` फ़ंक्शन भेजने वाले को निकालने के लिए wei की राशि निर्दिष्ट करने की अनुमति देता है। यह केवल तभी सफल होगा जब निकालने के लिए अनुरोधित राशि 1 ether से कम हो और पिछले सप्ताह में कोई निकासी न हुई हो। या ऐसा है?...

संवेदनशीलता \[17\] पंक्ति पर आती है जहाँ हम उपयोगकर्ता को उनकी अनुरोधित ether की राशि भेजते हैं। एक दुर्भावनापूर्ण हमलावर पर विचार करें जो निम्नलिखित कॉन्ट्रैक्ट बनाता है,

Attack.sol:```solidity
import "EtherStore.sol";

contract Attack {
  EtherStore public etherStore;

  // initialise the etherStore variable with the contract address
  constructor(address _etherStoreAddress) {
      etherStore = EtherStore(_etherStoreAddress);
  }

  function pwnEtherStore() public payable {
      // attack to the nearest ether
      require(msg.value >= 1 ether);
      // send eth to the depositFunds() function
      etherStore.depositFunds.value(1 ether)();
      // start the magic
      etherStore.withdrawFunds(1 ether);
  }

  function collectEther() public {
      msg.sender.transfer(this.balance);
  }

  // fallback function - where the magic happens
  function () payable {
      if (etherStore.balance > 1 ether) {
          etherStore.withdrawFunds(1 ether);
      }
  }
}

आइए देखें कि यह दुर्भावनापूर्ण अनुबंध हमारे EtherStore अनुबंध का फायदा कैसे उठा सकता है। हमलावर उपरोक्त अनुबंध (मान लीजिए पते 0x0...123 पर) को कंस्ट्रक्टर पैरामीटर के रूप में EtherStore के अनुबंध पते के साथ बनाएगा। यह सार्वजनिक चर etherStore को आरंभित करेगा और उस अनुबंध की ओर इंगित करेगा जिस पर हम हमला करना चाहते हैं।

इसके बाद हमलावर pwnEtherStore() फ़ंक्शन को कुछ मात्रा में ether (1 या अधिक) के साथ कॉल करेगा, मान लीजिए इस उदाहरण के लिए 1 ether। इस उदाहरण में हम मानते हैं कि कई अन्य उपयोगकर्ताओं ने इस अनुबंध में ether जमा किया है, जिससे इसका वर्तमान बैलेंस 10 ether है। फिर निम्नलिखित घटनाएँ होंगी:

  1. Attack.sol - लाइन [15] - EtherStore अनुबंध का depositFunds() फ़ंक्शन 1 ether के msg.value (और बहुत अधिक gas) के साथ कॉल किया जाएगा। प्रेषक (msg.sender) हमारा दुर्भावनापूर्ण अनुबंध (0x0...123) होगा। इस प्रकार, balances[0x0..123] = 1 ether।

  2. Attack.sol - लाइन [17] - फिर दुर्भावनापूर्ण अनुबंध EtherStore अनुबंध के withdrawFunds() फ़ंक्शन को 1 ether के पैरामीटर के साथ कॉल करेगा। यह सभी आवश्यकताओं को पूरा करेगा (EtherStore अनुबंध की लाइनें [12]-[16]), क्योंकि हमने कोई पिछली निकासी नहीं की है।

  3. EtherStore.sol - लाइन [17] - फिर अनुबंध दुर्भावनापूर्ण अनुबंध को 1 ether वापस भेजेगा।

अंतिम परिणाम यह है कि हमलावर ने EtherStore अनुबंध से सारा (1 को छोड़कर) ether एक ही लेन-देन के साथ तुरंत निकाल लिया है।

निवारक तकनीकें

स्मार्ट अनुबंधों में संभावित re-entrancy कमजोरियों से बचने में मदद करने के लिए कई सामान्य तकनीकें हैं। पहली है (जब भी संभव हो) बाहरी अनुबंधों को ether भेजते समय अंतर्निहित transfer() फ़ंक्शन का उपयोग करना। transfer फ़ंक्शन बाहरी कॉल के साथ केवल 2300 gas भेजता है, जो गंतव्य पते/अनुबंध के लिए किसी अन्य अनुबंध को कॉल करने (अर्थात भेजने वाले अनुबंध में पुनः प्रवेश करने) के लिए पर्याप्त नहीं है।

दूसरी तकनीक यह सुनिश्चित करना है कि स्टेट वेरिएबल्स को बदलने वाला सारा तर्क अनुबंध से ether भेजे जाने (या किसी बाहरी कॉल) से पहले हो। EtherStore उदाहरण में, EtherStore.sol की लाइनें [18] और [19] को लाइन [17] से पहले रखा जाना चाहिए। यह अच्छा अभ्यास है कि अज्ञात पतों पर बाहरी कॉल करने वाले किसी भी कोड को किसी स्थानीयकृत फ़ंक्शन या कोड निष्पादन का अंतिम ऑपरेशन बनाया जाए। इसे checks-effects-interactions पैटर्न के रूप में जाना जाता है।

तीसरी तकनीक है mutex का परिचय देना। अर्थात्, एक स्टेट वेरिएबल जोड़ना जो कोड निष्पादन के दौरान अनुबंध को लॉक कर देता है, जिससे reentrancy कॉलें रुक जाती हैं।

इन सभी तकनीकों को (तीनों आवश्यक नहीं हैं, लेकिन प्रदर्शन के उद्देश्य से ऐसा किया गया है) EtherStore.sol पर लागू करने से re-entrancy-मुक्त अनुबंध प्राप्त होता है:```solidity contract EtherStore {

root@kitploit:~
// initialise the mutex
bool reEntrancyMutex = false;
uint256 public withdrawalLimit = 1 ether;
mapping(address => uint256) public lastWithdrawTime;
mapping(address => uint256) public balances;

function depositFunds() public payable {
    balances[msg.sender] += msg.value;
}

function withdrawFunds (uint256 _weiToWithdraw) public {
    require(!reEntrancyMutex);
    require(balances[msg.sender] >= _weiToWithdraw);
    // limit the withdrawal
    require(_weiToWithdraw <= withdrawalLimit);
    // limit the time allowed to withdraw
    require(now >= lastWithdrawTime[msg.sender] + 1 weeks);
    balances[msg.sender] -= _weiToWithdraw;
    lastWithdrawTime[msg.sender] = now;
    // set the reEntrancy mutex before the external call
    reEntrancyMutex = true;
    msg.sender.transfer(_weiToWithdraw);
    // release the mutex after the external call
    reEntrancyMutex = false;
}

}

root@kitploit:~
<h3 id="re-example">वास्तविक दुनिया का उदाहरण: The DAO</h3>

[The DAO](https://en.wikipedia.org/wiki/The_DAO_(organization)) (विकेंद्रीकृत स्वायत्त संगठन) एथेरियम के प्रारंभिक विकास में हुए प्रमुख हैकों में से एक था। उस समय, कॉन्ट्रैक्ट के पास 150 मिलियन अमेरिकी डॉलर से अधिक थे। री-एंट्रेंसी ने इस हमले में प्रमुख भूमिका निभाई, जो अंततः हार्ड-फोर्क का कारण बना जिसने एथेरियम क्लासिक (ETC) का निर्माण किया। DAO शोषण के अच्छे विश्लेषण के लिए, [Phil Daian की पोस्ट](http://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/) देखें।

<h2 id="ouflow"><span id="SP-2">2. अंकगणितीय ओवर/अंडर फ्लो</span></h2>

एथेरियम वर्चुअल मशीन (EVM) पूर्णांकों के लिए निश्चित-आकार के डेटा प्रकार निर्दिष्ट करती है। इसका मतलब है कि एक पूर्णांक चर केवल संख्याओं की एक निश्चित सीमा को दर्शा सकता है। उदाहरण के लिए, एक `uint8` केवल \[0,255\] की सीमा में संख्याएँ संग्रहीत कर सकता है। `uint8` में `256` संग्रहीत करने का प्रयास करने पर परिणाम `0` होगा। यदि सावधानी न बरती जाए, तो Solidity में चरों का शोषण किया जा सकता है यदि उपयोगकर्ता इनपुट की जाँच न की जाए और ऐसी गणनाएँ की जाएँ जिनके परिणामस्वरूप संख्याएँ उन्हें संग्रहीत करने वाले डेटा प्रकार की सीमा से बाहर होती हैं।

अंकगणितीय ओवर/अंडर फ्लो पर अधिक पढ़ने के लिए, [अपने स्मार्ट कॉन्ट्रैक्ट्स को कैसे सुरक्षित करें](https://medium.com/loom-network/how-to-secure-your-smart-contracts-6-solidity-vulnerabilities-and-how-to-avoid-them-part-1-c33048d4d17d), [एथेरियम स्मार्ट कॉन्ट्रैक्ट सर्वोत्तम अभ्यास](https://consensys.github.io/smart-contract-best-practices/known_attacks/#integer-overflow-and-underflow) और [एथेरियम, Solidity और पूर्णांक ओवरफ्लो: 1970 की तरह ब्लॉकचेन प्रोग्रामिंग](https://randomoracle.wordpress.com/2018/04/27/ethereum-solidity-and-integer-overflows-programming-blockchains-like-1970/) देखें।

<h3 id="ou-vuln">भेद्यता</h3>

ओवर/अंडर फ्लो तब होता है जब कोई ऑपरेशन किया जाता है जिसमें एक निश्चित आकार के चर को उस चर के डेटा प्रकार की सीमा के बाहर की संख्या (या डेटा का टुकड़ा) संग्रहीत करने की आवश्यकता होती है।

उदाहरण के लिए, एक `uint8` (8 बिट का अहस्ताक्षरित पूर्णांक, यानी केवल धनात्मक) चर जो अपने मान के रूप में `0` संग्रहीत करता है, उसमें से `1` घटाने पर परिणाम `255` होगा। यह एक अंडरफ्लो है। हमने `uint8` की सीमा से नीचे एक संख्या निर्धारित की है, परिणाम *चक्कर लगा देता है* और `uint8` द्वारा संग्रहीत की जा सकने वाली सबसे बड़ी संख्या देता है। इसी प्रकार, एक `uint8` में `2^8=256` जोड़ने पर चर अपरिवर्तित रहेगा क्योंकि हमने `uint` की पूरी लंबाई के चारों ओर चक्कर लगा लिया है (गणितज्ञों के लिए, यह एक त्रिकोणमितीय फलन के कोण में $2\pi$ जोड़ने के समान है, $\sin(x) = \sin(x+2\pi)$)। डेटा प्रकार की सीमा से बड़ी संख्याएँ जोड़ना ओवरफ्लो कहलाता है। स्पष्टता के लिए, वर्तमान में शून्य मान वाले एक `uint8` में `257` जोड़ने पर परिणाम `1` होगा। कभी-कभी निश्चित प्रकार के चरों को चक्रीय मानना शिक्षाप्रद होता है, जहाँ हम सबसे बड़ी संभावित संग्रहीत संख्या से ऊपर संख्याएँ जोड़ने पर फिर से शून्य से शुरू करते हैं, और शून्य के लिए इसका विपरीत (जहाँ 0 से घटाने पर हम सबसे बड़ी संख्या से उल्टी गिनती शुरू करते हैं, और जितना अधिक घटाते हैं उतनी ही नीचे आते जाते हैं)।

इस प्रकार की संख्यात्मक सावधानियाँ हमलावरों को कोड का दुरुपयोग करने और अप्रत्याशित तर्क प्रवाह बनाने की अनुमति देती हैं। उदाहरण के लिए, नीचे दिए गए टाइम लॉकिंग कॉन्ट्रैक्ट पर विचार करें।

TimeLock.sol:```solidity
contract TimeLock {

    mapping(address => uint) public balances;
    mapping(address => uint) public lockTime;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
        lockTime[msg.sender] = now + 1 weeks;
    }

    function increaseLockTime(uint _secondsToIncrease) public {
        lockTime[msg.sender] += _secondsToIncrease;
    }

    function withdraw() public {
        require(balances[msg.sender] > 0);
        require(now > lockTime[msg.sender]);
        uint transferValue = balances[msg.sender];
        balances[msg.sender] = 0;
        msg.sender.transfer(transferValue);
    }
}

यह कॉन्ट्रैक्ट एक टाइम वॉल्ट की तरह कार्य करने के लिए डिज़ाइन किया गया है, जहाँ उपयोगकर्ता कॉन्ट्रैक्ट में ईथर जमा कर सकते हैं और यह वहाँ कम से कम एक सप्ताह के लिए लॉक रहेगा। उपयोगकर्ता चाहें तो प्रतीक्षा समय को 1 सप्ताह से अधिक बढ़ा सकते हैं, लेकिन एक बार जमा करने के बाद, उपयोगकर्ता निश्चिंत हो सकता है कि उनका ईथर कम से कम एक सप्ताह के लिए सुरक्षित रूप से लॉक है। या क्या वे सच में निश्चिंत हो सकते हैं?...

यदि किसी उपयोगकर्ता को अपनी निजी कुंजी (private key) सौंपने के लिए मजबूर किया जाए (बंधक स्थिति की कल्पना करें), तो ऐसा कॉन्ट्रैक्ट यह सुनिश्चित करने के लिए उपयोगी हो सकता है कि ईथर कम समय में प्राप्त न हो सके। अगर किसी उपयोगकर्ता ने इस कॉन्ट्रैक्ट में 100 ether लॉक किया हो और अपनी कुंजियाँ किसी हमलावर को सौंप दी हों, तो हमलावर lockTime की परवाह किए बिना, ओवरफ्लो का उपयोग करके ईथर प्राप्त कर सकता है।

हमलावर उस पते के लिए वर्तमान lockTime निर्धारित कर सकता है जिसकी कुंजी अब उसके पास है (यह एक सार्वजनिक चर है)। आइए इसे userLockTime कहते हैं। फिर वे increaseLockTime फ़ंक्शन को कॉल कर सकते हैं और तर्क के रूप में 2^256 - userLockTime संख्या पास कर सकते हैं। यह संख्या वर्तमान userLockTime में जोड़ दी जाएगी और ओवरफ्लो का कारण बनेगी, जिससे lockTime[msg.sender] रीसेट होकर 0 हो जाएगा। इसके बाद हमलावर अपना पुरस्कार प्राप्त करने के लिए केवल withdraw फ़ंक्शन को कॉल कर सकता है।

आइए एक और उदाहरण देखें, यह Ethernaut Challanges से है।

SPOILER ALERT: यदि आपने अभी तक Ethernaut चुनौतियाँ पूरी नहीं की हैं, तो यह एक स्तर का समाधान देता है।```solidity pragma solidity ^0.4.18;

contract Token {

mapping(address => uint) balances; uint public totalSupply;

function Token(uint _initialSupply) { balances[msg.sender] = totalSupply = _initialSupply; }

function transfer(address _to, uint _value) public returns (bool) { require(balances[msg.sender] - _value >= 0); balances[msg.sender] -= _value; balances[_to] += _value; return true; }

function balanceOf(address _owner) public constant returns (uint balance) { return balances[_owner]; } }

root@kitploit:~
यह एक सरल टोकन अनुबंध है जो `transfer()` फ़ंक्शन का उपयोग करता है, जिससे प्रतिभागी अपने टोकन को इधर-उधर स्थानांतरित कर सकते हैं। क्या आप इस अनुबंध में त्रुटि देख सकते हैं?

दोष `transfer()` फ़ंक्शन में है। पंक्ति \[13\] पर दिया गया require स्टेटमेंट अंडरफ्लो का उपयोग करके बायपास किया जा सकता है। एक ऐसे उपयोगकर्ता पर विचार करें जिसके पास कोई शेष राशि नहीं है। वे किसी भी गैर-शून्य `_value` के साथ `transfer()` फ़ंक्शन को कॉल कर सकते हैं और पंक्ति \[13\] के require स्टेटमेंट को पास कर सकते हैं। ऐसा इसलिए है क्योंकि `balances[msg.sender]` शून्य है (और एक `uint256` है), इसलिए किसी भी सकारात्मक राशि (`2^256` को छोड़कर) को घटाने पर ऊपर वर्णित अंडरफ्लो के कारण एक सकारात्मक संख्या प्राप्त होगी। यह पंक्ति \[14\] के लिए भी सत्य है, जहाँ हमारी शेष राशि को एक सकारात्मक संख्या से क्रेडिट किया जाएगा। इस प्रकार, इस उदाहरण में, हमने अंडरफ्लो भेद्यता के कारण मुफ्त टोकन प्राप्त कर लिए हैं।

<h3 id="ou-prevention">निवारक तकनीकें</h3>

(वर्तमान में) अंडर/ओवरफ्लो भेद्यताओं से बचाव के लिए पारंपरिक तकनीक गणितीय लाइब्रेरियों का उपयोग या निर्माण करना है जो मानक गणितीय ऑपरेटरों को प्रतिस्थापित करती हैं; जोड़, घटाव और गुणा (भाग को बाहर रखा गया है क्योंकि यह ओवर/अंडर फ्लो का कारण नहीं बनता है और EVM 0 से भाग देने पर revert करता है)।

[OppenZepplin](https://github.com/OpenZeppelin/zeppelin-solidity) ने सुरक्षित लाइब्रेरियों के निर्माण और ऑडिटिंग में शानदार काम किया है, जिनका उपयोग Ethereum समुदाय द्वारा किया जा सकता है। विशेष रूप से, उनकी [Safe Math Library](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol) अंडर/ओवर फ्लो भेद्यताओं से बचने के लिए उपयोग करने हेतु एक संदर्भ या लाइब्रेरी है।

यह प्रदर्शित करने के लिए कि इन लाइब्रेरियों का उपयोग Solidity में कैसे किया जाता है, आइए हम Open Zepplin की `SafeMath` लाइब्रेरी का उपयोग करके `TimeLock` अनुबंध को सही करें। ओवरफ्लो-मुक्त अनुबंध इस प्रकार होगा:```solidity
library SafeMath {

  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

contract TimeLock {
    using SafeMath for uint; // use the library for uint type
    mapping(address => uint256) public balances;
    mapping(address => uint256) public lockTime;

    function deposit() public payable {
        balances[msg.sender] = balances[msg.sender].add(msg.value);
        lockTime[msg.sender] = now.add(1 weeks);
    }

    function increaseLockTime(uint256 _secondsToIncrease) public {
        lockTime[msg.sender] = lockTime[msg.sender].add(_secondsToIncrease);
    }

    function withdraw() public {
        require(balances[msg.sender] > 0);
        require(now > lockTime[msg.sender]);
        uint transferValue = balances[msg.sender];
        balances[msg.sender] = 0;
        msg.sender.transfer(transferValue);
    }
}

ध्यान दें कि सभी मानक गणितीय ऑपरेशनों को SafeMath लाइब्रेरी में परिभाषित ऑपरेशनों से बदल दिया गया है। TimeLock कॉन्ट्रैक्ट अब कोई भी ऐसा ऑपरेशन नहीं करता जो अंडर/ओवर फ्लो करने में सक्षम हो।

वास्तविक-विश्व उदाहरण: PoWHC और बैच ट्रांसफर ओवरफ्लो (CVE-2018–10299)

एक 4chan समूह ने सोचा कि Solidity में लिखा Ethereum पर पोंजी स्कीम बनाना एक बहुत अच्छा विचार है। उन्होंने इसे Proof of Weak Hands Coin (PoWHC) नाम दिया। दुर्भाग्य से, ऐसा लगता है कि कॉन्ट्रैक्ट के लेखक ने पहले कभी अंडर/ओवर फ्लो नहीं देखा था, और परिणामस्वरूप, 866 ether उसके कॉन्ट्रैक्ट से निकाल लिया गया। अंडरफ्लो कैसे होता है (जो ऊपर दी गई Ethernaut चुनौती से बहुत अलग नहीं है) इसका एक अच्छा अवलोकन Eric Banisadar की पोस्ट में दिया गया है।

कुछ डेवलपर्स ने कुछ ERC20 टोकन कॉन्ट्रैक्ट्स में एक batchTransfer() फ़ंक्शन भी लागू किया। इस इम्प्लीमेंटेशन में ओवरफ्लो था। यह पोस्ट इसे समझाती है, हालांकि मुझे लगता है कि शीर्षक भ्रामक है, क्योंकि इसका ERC20 मानक से कोई लेना-देना नहीं है, बल्कि कुछ ERC20 टोकन कॉन्ट्रैक्ट्स में एक असुरक्षित batchTransfer() फ़ंक्शन लागू होता है।

3. अप्रत्याशित Ether

आम तौर पर जब ether को किसी कॉन्ट्रैक्ट पर भेजा जाता है, तो उसे या तो fallback फ़ंक्शन या कॉन्ट्रैक्ट में वर्णित कोई अन्य फ़ंक्शन निष्पादित करना होता है। इसके दो अपवाद हैं, जहाँ ether कॉन्ट्रैक्ट में बिना कोई कोड निष्पादित किए मौजूद हो सकता है। जो कॉन्ट्रैक्ट कॉन्ट्रैक्ट को भेजे गए हर ether के लिए कोड निष्पादन पर निर्भर करते हैं, वे उन हमलों के प्रति संवेदनशील हो सकते हैं जिनमें ether को जबरन कॉन्ट्रैक्ट में भेज दिया जाता है।

इस पर और अधिक पढ़ने के लिए, देखें अपने स्मार्ट कॉन्ट्रैक्ट्स को कैसे सुरक्षित करें: 6 और Solidity सुरक्षा पैटर्न - किसी कॉन्ट्रैक्ट पर ether को बलपूर्वक भेजना .

भेद्यता

सही स्टेट ट्रांज़िशन लागू करने या ऑपरेशनों को मान्य करने में उपयोगी एक सामान्य रक्षात्मक प्रोग्रामिंग तकनीक invariant-checking है। इस तकनीक में इनवेरिएंट्स का एक सेट परिभाषित करना शामिल है (ऐसे मेट्रिक्स या पैरामीटर जिन्हें नहीं बदलना चाहिए) और यह जाँचना कि एक (या कई) ऑपरेशन के बाद ये इनवेरिएंट अपरिवर्तित रहते हैं। यह आम तौर पर अच्छा डिज़ाइन है, बशर्ते कि जाँचे जा रहे इनवेरिएंट वास्तव में इनवेरिएंट हों। इनवेरिएंट का एक उदाहरण एक निश्चित निर्गमन (fixed issuance) वाले ERC20 टोकन का totalSupply है। चूँकि किसी भी फ़ंक्शन को इस इनवेरिएंट को संशोधित नहीं करना चाहिए, इसलिए कोई transfer() फ़ंक्शन में एक जाँच जोड़ सकता है जो सुनिश्चित करती है कि फ़ंक्शन अपेक्षा के अनुरूप काम कर रहा है, इसके लिए totalSupply अपरिवर्तित रहता है।

विशेष रूप से, एक स्पष्ट invariant है, जिसका उपयोग करना आकर्षक लग सकता है लेकिन वास्तव में बाहरी उपयोगकर्ताओं द्वारा हेरफेर किया जा सकता है (स्मार्ट कॉन्ट्रैक्ट में लागू किए गए नियमों की परवाह किए बिना) .यह कॉन्ट्रैक्ट में संग्रहीत वर्तमान ether है। अक्सर जब डेवलपर्स पहली बार Solidity सीखते हैं, तो उनमें यह ग़लतफ़हमी होती है कि एक कॉन्ट्रैक्ट केवल payable फ़ंक्शन के माध्यम से ether स्वीकार या प्राप्त कर सकता है। यह ग़लतफ़हमी ऐसे कॉन्ट्रैक्ट्स को जन्म दे सकती है जिनमें उनके भीतर ether बैलेंस के बारे में गलत धारणाएँ होती हैं, जो कई प्रकार की भेद्यताओं को जन्म दे सकती हैं। इस भेद्यता का सबसे पुख्ता सबूत है this.balance का (गलत) उपयोग। जैसा कि हम देखेंगे, this.balance का गलत उपयोग इस प्रकार की गंभीर भेद्यताओं को जन्म दे सकता है।

दो तरीके हैं जिनसे ether को बिना किसी payable फ़ंक्शन का उपयोग किए या कॉन्ट्रैक्ट पर कोई कोड निष्पादित किए (जबरन) किसी कॉन्ट्रैक्ट को भेजा जा सकता है। ये नीचे सूचीबद्ध हैं।

Self Destruct / Suicide

कोई भी कॉन्ट्रैक्ट selfdestruct(address) फ़ंक्शन को लागू करने में सक्षम है, जो कॉन्ट्रैक्ट पते से सभी बाइटकोड हटा देता है और वहाँ संग्रहीत सभी ether को पैरामीटर में निर्दिष्ट पते पर भेज देता है। यदि यह निर्दिष्ट पता भी एक कॉन्ट्रैक्ट है, तो कोई भी फ़ंक्शन (fallback सहित) कॉल नहीं किया जाता है। इसलिए, selfdestruct() फ़ंक्शन का उपयोग किसी भी कॉन्ट्रैक्ट को जबरन ether भेजने के लिए किया जा सकता है, भले ही कॉन्ट्रैक्ट में कोई भी कोड मौजूद हो। इसमें बिना किसी payable फ़ंक्शन वाले कॉन्ट्रैक्ट भी शामिल हैं। इसका मतलब है, कोई भी हमलावर selfdestruct() फ़ंक्शन वाला एक कॉन्ट्रैक्ट बना सकता है, उसमें ether भेज सकता है, selfdestruct(target) कॉल कर सकता है और target कॉन्ट्रैक्ट को ether भेजने के लिए मजबूर कर सकता है। Martin Swende के पास एक शानदार ब्लॉग पोस्ट है जिसमें self-destruct ऑपकोड की कुछ विचित्रताओं (Quirk #2) के साथ-साथ यह भी वर्णित है कि कैसे क्लाइंट नोड्स गलत इनवेरिएंट की जाँच कर रहे थे, जो क्लाइंट्स के काफी विनाशकारी न्यूकिंग का कारण बन सकता था।

पहले से भेजा गया Ether

दूसरा तरीका जिससे एक कॉन्ट्रैक्ट बिना selfdestruct() फ़ंक्शन का उपयोग किए या बिना किसी payable फ़ंक्शन को कॉल किए ether प्राप्त कर सकता है, वह है कॉन्ट्रैक्ट पते को पहले से ether से लोड करना। कॉन्ट्रैक्ट पते नियतात्मक (deterministic) होते हैं, वास्तव में यह पता कॉन्ट्रैक्ट बनाने वाले पते और कॉन्ट्रैक्ट बनाने वाले transaction nonce के keccak256 (कभी-कभी SHA3 के साथ समानार्थी) हैश से गणना किया जाता है। विशेष रूप से, यह इस रूप में होता है: address = sha3(rlp.encode([account_address,transaction_nonce])) (इसके कुछ मज़ेदार उपयोगों के लिए Keyless Ether देखें)। इसका मतलब है, कोई भी व्यक्ति गणना कर सकता है कि कॉन्ट्रैक्ट बनने से पहले उसका पता क्या होगा और इस प्रकार उस पते पर ether भेज सकता है। जब कॉन्ट्रैक्ट बनता है तो उसका ether बैलेंस गैर-शून्य होगा।

आइए उपरोक्त ज्ञान को देखते हुए उत्पन्न होने वाली कुछ समस्याओं का पता लगाएँ।

इस अत्यंत सरल कॉन्ट्रैक्ट पर विचार करें,

EtherGame.sol:```solidity contract EtherGame {

root@kitploit:~
uint public payoutMileStone1 = 3 ether;
uint public mileStone1Reward = 2 ether;
uint public payoutMileStone2 = 5 ether;
uint public mileStone2Reward = 3 ether;
uint public finalMileStone = 10 ether;
uint public finalReward = 5 ether;

mapping(address => uint) redeemableEther;
// users pay 0.5 ether. At specific milestones, credit their accounts
function play() public payable {
    require(msg.value == 0.5 ether); // each play is 0.5 ether
    uint currentBalance = this.balance + msg.value;
    // ensure no players after the game as finished
    require(currentBalance <= finalMileStone);
    // if at a milestone credit the players account
    if (currentBalance == payoutMileStone1) {
        redeemableEther[msg.sender] += mileStone1Reward;
    }
    else if (currentBalance == payoutMileStone2) {
        redeemableEther[msg.sender] += mileStone2Reward;
    }
    else if (currentBalance == finalMileStone ) {
        redeemableEther[msg.sender] += finalReward;
    }
    return;
}

function claimReward() public {
    // ensure the game is complete
    require(this.balance == finalMileStone);
    // ensure there is a reward to give
    require(redeemableEther[msg.sender] > 0);
    uint transferValue = redeemableEther[msg.sender];
    redeemableEther[msg.sender] = 0;
    msg.sender.transfer(transferValue);
}

}

root@kitploit:~
यह अनुबंध एक सरल खेल का प्रतिनिधित्व करता है (जो स्वाभाविक रूप से [race-conditions](#race-conditions) को आमंत्रित करेगा) जिसमें खिलाड़ी अनुबंध को `0.5 ether` की मात्रा भेजते हैं, इस उम्मीद में कि वे उस खिलाड़ी बनें जो पहले तीन मील के पत्थरों में से एक तक पहुँचता है। मील के पत्थर ether में मापे जाते हैं। जो पहले मील के पत्थर तक पहुँचता है, वह खेल समाप्त होने पर ether का एक हिस्सा दावा कर सकता है। खेल तब समाप्त होता है जब अंतिम मील का पत्थर (`10 ether`) प्राप्त हो जाता है और उपयोगकर्ता अपने पुरस्कारों का दावा कर सकते हैं।

`EtherGame` अनुबंध के साथ समस्याएँ पंक्तियों \[14\] (और संबंधित रूप से \[16\]) और \[32\] पर `this.balance` के खराब उपयोग से आती हैं। एक शरारती हमलावर `selfdestruct()` फ़ंक्शन के माध्यम से थोड़ी मात्रा में ether, मान लीजिए `0.1 ether`, जबरन भेज सकता है ताकि भविष्य के किसी भी खिलाड़ी को मील के पत्थर तक पहुँचने से रोका जा सके। चूँकि सभी वैध खिलाड़ी केवल `0.5 ether` की वृद्धि भेज सकते हैं, `this.balance` अब आधे-पूर्णांक संख्याएँ नहीं रहेगा, क्योंकि इसमें `0.1 ether` का योगदान भी शामिल होगा। यह पंक्तियों \[18\], \[21\] और \[24\] की सभी if शर्तों को सत्य होने से रोकता है।

इससे भी बदतर, एक प्रतिशोधी हमलावर जो मील के पत्थर से चूक गया है, जबरन `10 ether` भेज सकता है (या ether की एक समतुल्य मात्रा जो अनुबंध की शेष राशि को `finalMileStone` से ऊपर धकेल देती है), जो सभी पुरस्कारों को अनुबंध में हमेशा के लिए बंद कर देगा। ऐसा इसलिए है क्योंकि `claimReward()` फ़ंक्शन हमेशा revert करेगा, पंक्ति \[32\] पर require के कारण (अर्थात `this.balance`, `finalMileStone` से अधिक है)।

<h3 id="ether-prevention">निवारक तकनीकें</h3>

यह भेद्यता आमतौर पर `this.balance` के दुरुपयोग से उत्पन्न होती है। अनुबंध तर्क, जब संभव हो, अनुबंध की शेष राशि के सटीक मूल्यों पर निर्भर होने से बचना चाहिए क्योंकि इसे कृत्रिम रूप से हेरफेर किया जा सकता है। यदि `this.balance` के आधार पर तर्क लागू कर रहे हैं, तो अप्रत्याशित शेष राशियों का हिसाब रखना सुनिश्चित करें।

यदि जमा किए गए ether के सटीक मूल्यों की आवश्यकता है, तो एक स्व-परिभाषित चर का उपयोग किया जाना चाहिए जो payable फ़ंक्शनों में बढ़ाया जाता है, ताकि जमा किए गए ether को सुरक्षित रूप से ट्रैक किया जा सके। यह चर `selfdestruct()` कॉल के माध्यम से भेजे गए जबरन ether से प्रभावित नहीं होगा।

इसे ध्यान में रखते हुए, `EtherGame` अनुबंध का एक सही संस्करण इस प्रकार दिख सकता है:```solidity
contract EtherGame {

    uint public payoutMileStone1 = 3 ether;
    uint public mileStone1Reward = 2 ether;
    uint public payoutMileStone2 = 5 ether;
    uint public mileStone2Reward = 3 ether;
    uint public finalMileStone = 10 ether;
    uint public finalReward = 5 ether;
    uint public depositedWei;

    mapping (address => uint) redeemableEther;

    function play() public payable {
        require(msg.value == 0.5 ether);
        uint currentBalance = depositedWei + msg.value;
        // ensure no players after the game as finished
        require(currentBalance <= finalMileStone);
        if (currentBalance == payoutMileStone1) {
            redeemableEther[msg.sender] += mileStone1Reward;
        }
        else if (currentBalance == payoutMileStone2) {
            redeemableEther[msg.sender] += mileStone2Reward;
        }
        else if (currentBalance == finalMileStone ) {
            redeemableEther[msg.sender] += finalReward;
        }
        depositedWei += msg.value;
        return;
    }

    function claimReward() public {
        // ensure the game is complete
        require(depositedWei == finalMileStone);
        // ensure there is a reward to give
        require(redeemableEther[msg.sender] > 0);
        uint transferValue = redeemableEther[msg.sender];
        redeemableEther[msg.sender] = 0;
        msg.sender.transfer(transferValue);
    }
 }

यहाँ, हमने अभी एक नया वेरिएबल, depositedWei बनाया है जो ज्ञात जमा ईथर का ट्रैक रखता है, और यह वही वेरिएबल है जिस पर हम अपनी आवश्यकताएँ और परीक्षण करते हैं। ध्यान दें, कि अब हमारे पास this.balance का कोई संदर्भ नहीं है।

वास्तविक-विश्व उदाहरण: अज्ञात

मुझे अभी तक इसका ऐसा उदाहरण नहीं मिला है जिसका वास्तविक दुनिया में शोषण किया गया हो। हालाँकि, Underhanded Solidity Contest में शोषण-योग्य कॉन्ट्रैक्ट्स के कुछ उदाहरण दिए गए थे।

4. Delegatecall

CALL और DELEGATECALL ऑपकोड Ethereum डेवलपर्स को अपने कोड को मॉड्यूलर बनाने में सक्षम बनाने के लिए उपयोगी हैं। कॉन्ट्रैक्ट्स के लिए मानक बाहरी संदेश कॉल को CALL ऑपकोड द्वारा संभाला जाता है, जिसके तहत कोड बाहरी कॉन्ट्रैक्ट/फ़ंक्शन के संदर्भ में चलाया जाता है। DELEGATECALL ऑपकोड मानक संदेश कॉल के समान है, सिवाय इसके कि लक्षित पते पर निष्पादित कोड कॉल करने वाले कॉन्ट्रैक्ट के संदर्भ में चलाया जाता है, साथ ही msg.sender और msg.value अपरिवर्तित रहते हैं। यह सुविधा लाइब्रेरीज़ के कार्यान्वयन को सक्षम बनाती है, जिससे डेवलपर्स भविष्य के कॉन्ट्रैक्ट्स के लिए पुन: प्रयोज्य कोड बना सकते हैं।

हालाँकि इन दोनों ऑपकोडों के बीच अंतर सरल और सहज है, फिर भी DELEGATECALL का उपयोग अप्रत्याशित कोड निष्पादन का कारण बन सकता है।

आगे पढ़ने के लिए, Ethereum Stack Exchange Question, Solidity Docs और How to Secure Your Smart Contracts: 6 देखें।

भेद्यता

DELEGATECALL की संदर्भ-संरक्षण प्रकृति ने सिद्ध कर दिया है कि भेद्यता-मुक्त कस्टम लाइब्रेरीज़ बनाना उतना आसान नहीं है जितना कोई सोच सकता है। लाइब्रेरीज़ में मौजूद कोड स्वयं सुरक्षित और भेद्यता-मुक्त हो सकता है, लेकिन जब इसे किसी अन्य एप्लिकेशन के संदर्भ में चलाया जाता है, तो नई भेद्यताएँ उत्पन्न हो सकती हैं। आइए Fibonacci संख्याओं का उपयोग करके इसका एक काफी जटिल उदाहरण देखें।

निम्नलिखित लाइब्रेरी पर विचार करें जो Fibonacci अनुक्रम और समान रूप के अनुक्रम उत्पन्न कर सकती है। FibonacciLib.sol[^1]```solidity // library contract - calculates fibonacci-like numbers; contract FibonacciLib { // initializing the standard fibonacci sequence; uint public start; uint public calculatedFibNumber;

root@kitploit:~
// modify the zeroth number in the sequence
function setStart(uint _start) public {
    start = _start;
}

function setFibonacci(uint n) public {
    calculatedFibNumber = fibonacci(n);
}

function fibonacci(uint n) internal returns (uint) {
    if (n == 0) return start;
    else if (n == 1) return start + 1;
    else return fibonacci(n - 1) + fibonacci(n - 2);
}

}

root@kitploit:~
यह लाइब्रेरी एक फ़ंक्शन प्रदान करती है जो अनुक्रम में *n*-वीं Fibonacci संख्या उत्पन्न कर सकता है। यह उपयोगकर्ताओं को अनुक्रम की प्रारंभिक संख्या (`start`) बदलने और इस नए अनुक्रम में *n*-वीं Fibonacci-जैसी संख्याएँ गणना करने की अनुमति देता है।

अब आइए एक कॉन्ट्रैक्ट पर विचार करें जो इस लाइब्रेरी का उपयोग करता है।


`FibonacciBalance.sol`:```solidity
contract FibonacciBalance {

    address public fibonacciLibrary;
    // the current fibonacci number to withdraw
    uint public calculatedFibNumber;
    // the starting fibonacci sequence number
    uint public start = 3;
    uint public withdrawalCounter;
    // the fibonancci function selector
    bytes4 constant fibSig = bytes4(sha3("setFibonacci(uint256)"));

    // constructor - loads the contract with ether
    constructor(address _fibonacciLibrary) public payable {
        fibonacciLibrary = _fibonacciLibrary;
    }

    function withdraw() {
        withdrawalCounter += 1;
        // calculate the fibonacci number for the current withdrawal user
        // this sets calculatedFibNumber
        require(fibonacciLibrary.delegatecall(fibSig, withdrawalCounter));
        msg.sender.transfer(calculatedFibNumber * 1 ether);
    }

    // allow users to call fibonacci library functions
    function() public {
        require(fibonacciLibrary.delegatecall(msg.data));
    }
}

यह कॉन्ट्रैक्ट एक प्रतिभागी को कॉन्ट्रैक्ट से ईथर निकालने की अनुमति देता है, और निकाली गई ईथर की मात्रा प्रतिभागी की निकासी क्रम के अनुरूप फाइबोनैचि संख्या के बराबर होती है; अर्थात, पहला प्रतिभागी 1 ईथर प्राप्त करता है, दूसरे को भी 1, तीसरे को 2, चौथे को 3, पाँचवें को 5, और इसी तरह आगे (जब तक कि कॉन्ट्रैक्ट की शेष राशि निकाली जा रही फाइबोनैचि संख्या से कम न हो जाए)।

इस कॉन्ट्रैक्ट में कई तत्व हैं जिन्हें कुछ स्पष्टीकरण की आवश्यकता हो सकती है। सबसे पहले, एक दिलचस्प दिखने वाला वेरिएबल है, fibSig। इसमें स्ट्रिंग "setFibonacci(uint256)" के Keccak (SHA-3) हैश के पहले 4 बाइट्स होते हैं। इसे फ़ंक्शन सेलेक्टर के रूप में जाना जाता है और इसे calldata में डाला जाता है ताकि यह निर्दिष्ट किया जा सके कि स्मार्ट कॉन्ट्रैक्ट का कौन-सा फ़ंक्शन कॉल किया जाएगा। इसका उपयोग लाइन [21] पर delegatecall फ़ंक्शन में यह निर्दिष्ट करने के लिए किया जाता है कि हम setFibonacci(uint256) फ़ंक्शन चलाना चाहते हैं। delegatecall में दूसरा आर्गुमेंट वह पैरामीटर है जिसे हम फ़ंक्शन को पास कर रहे हैं। दूसरे, हम मान लेते हैं कि FibonacciLib लाइब्रेरी के लिए एड्रेस कंस्ट्रक्टर में सही ढंग से संदर्भित है (सेक्शन बाह्य कॉन्ट्रैक्ट संदर्भ इस प्रकार के कॉन्ट्रैक्ट संदर्भ प्रारंभ से संबंधित कुछ संभावित कमजोरियों पर चर्चा करता है)।

क्या आप इस कॉन्ट्रैक्ट में कोई त्रुटि देख सकते हैं? यदि आप इसे remix में डालते हैं, इसे ईथर से भरते हैं और withdraw() को कॉल करते हैं, तो यह संभवतः रिवर्ट हो जाएगा।

आपने देखा होगा कि स्टेट वेरिएबल start लाइब्रेरी और मुख्य कॉल करने वाले कॉन्ट्रैक्ट दोनों में उपयोग किया गया है। लाइब्रेरी कॉन्ट्रैक्ट में, start का उपयोग फाइबोनैचि अनुक्रम की शुरुआत निर्दिष्ट करने के लिए किया जाता है और इसे 0 पर सेट किया जाता है, जबकि FibonacciBalance कॉन्ट्रैक्ट में इसे 3 पर सेट किया गया है। आपने यह भी देखा होगा कि FibonacciBalance कॉन्ट्रैक्ट में फॉलबैक फ़ंक्शन सभी कॉल्स को लाइब्रेरी कॉन्ट्रैक्ट में पास करने की अनुमति देता है, जो लाइब्रेरी कॉन्ट्रैक्ट के setStart() फ़ंक्शन को भी कॉल करने की अनुमति देता है। यह याद रखते हुए कि हम कॉन्ट्रैक्ट की स्थिति को संरक्षित रखते हैं, ऐसा लग सकता है कि यह फ़ंक्शन आपको स्थानीय FibonnacciBalance कॉन्ट्रैक्ट में start वेरिएबल की स्थिति बदलने की अनुमति देगा। यदि ऐसा है, तो यह किसी को अधिक ईथर निकालने की अनुमति देगा, क्योंकि परिणामी calculatedFibNumber start वेरिएबल पर निर्भर है (जैसा कि लाइब्रेरी कॉन्ट्रैक्ट में देखा गया है)। वास्तव में, setStart() फ़ंक्शन कॉन्ट्रैक्ट में वेरिएबल को संशोधित नहीं करता है (और न ही कर सकता है)। इस कॉन्ट्रैक्ट में अंतर्निहित कमजोरी केवल वेरिएबल को संशोधित करने से कहीं अधिक गंभीर है।

वास्तविक मुद्दे पर चर्चा करने से पहले, हम यह समझने के लिए एक संक्षिप्त चक्कर लगाते हैं कि स्टेट वेरिएबल (storage वेरिएबल) वास्तव में कॉन्ट्रैक्ट्स में कैसे संग्रहीत होते हैं। स्टेट या storage वेरिएबल (जो व्यक्तिगत लेनदेन के बीच बने रहने वाले वेरिएबल हैं) को कॉन्ट्रैक्ट में उनके परिचय के क्रम में slots में क्रमिक रूप से रखा जाता है। (यहाँ कुछ जटिलताएँ हैं, और मैं पाठक को अधिक गहन समझ के लिए स्टोरेज में स्टेट वेरिएबल्स की व्यवस्था पढ़ने के लिए प्रोत्साहित करता हूँ)।

एक उदाहरण के रूप में, आइए लाइब्रेरी कॉन्ट्रैक्ट को देखें। इसमें दो स्टेट वेरिएबल हैं, start और calculatedFibNumber। पहला वेरिएबल start है, इसलिए इसे कॉन्ट्रैक्ट के स्टोरेज में slot[0] (अर्थात पहले स्लॉट) पर संग्रहीत किया जाता है। दूसरा वेरिएबल, calculatedFibNumber, अगले उपलब्ध स्टोरेज स्लॉट, slot[1] में रखा जाता है। यदि हम setStart() फ़ंक्शन को देखें, तो यह एक इनपुट लेता है और start को इनपुट के बराबर सेट करता है। इसलिए यह फ़ंक्शन slot[0] को उस इनपुट पर सेट कर रहा है जो हम setStart() फ़ंक्शन में प्रदान करते हैं। इसी तरह, setFibonacci() फ़ंक्शन calculatedFibNumber को fibonacci(n) के परिणाम पर सेट करता है। फिर से, यह केवल स्टोरेज को के मान पर सेट करना है।

अब आइए FibonacciBalance कॉन्ट्रैक्ट को देखें। स्टोरेज slot[0] अब fibonacciLibrary एड्रेस के अनुरूप है और slot[1] calculatedFibNumber के अनुरूप है। इसी गलत मैपिंग में कमजोरी उत्पन्न होती है। delegatecall कॉन्ट्रैक्ट संदर्भ को संरक्षित रखता है। इसका अर्थ है कि delegatecall के माध्यम से निष्पादित कोड कॉल करने वाले कॉन्ट्रैक्ट की स्थिति (अर्थात स्टोरेज) पर कार्य करेगा।

अब ध्यान दें कि withdraw() में लाइन [21] पर हम fibonacciLibrary.delegatecall(fibSig,withdrawalCounter) निष्पादित करते हैं। यह setFibonacci() फ़ंक्शन को कॉल करता है, जो जैसा कि हमने चर्चा की, स्टोरेज slot[1] को संशोधित करता है, जो हमारे वर्तमान संदर्भ में calculatedFibNumber है। यह अपेक्षित है (अर्थात निष्पादन के बाद, calculatedFibNumber समायोजित हो जाता है)। हालाँकि, याद रखें कि FibonacciLib कॉन्ट्रैक्ट में start वेरिएबल स्टोरेज slot[0] में स्थित है, जो वर्तमान कॉन्ट्रैक्ट में fibonacciLibrary एड्रेस है। इसका अर्थ है कि fibonacci() फ़ंक्शन एक अप्रत्याशित परिणाम देगा। ऐसा इसलिए है क्योंकि यह start (slot[0]) को संदर्भित करता है, जो वर्तमान कॉलिंग संदर्भ में एड्रेस है (जो के रूप में व्याख्या करने पर अक्सर काफी बड़ा होगा)। इस प्रकार यह संभावना है कि फ़ंक्शन रिवर्ट हो जाएगा क्योंकि इसमें मात्रा में ईथर नहीं होगा, जो लौटाएगा।

और भी बुरी बात, FibonacciBalance कॉन्ट्रैक्ट उपयोगकर्ताओं को लाइन [26] पर फॉलबैक फ़ंक्शन के माध्यम से सभी fibonacciLibrary फ़ंक्शन कॉल करने की अनुमति देता है। जैसा कि हमने पहले चर्चा की, इसमें setStart() फ़ंक्शन शामिल है। हमने चर्चा की कि यह फ़ंक्शन किसी को भी स्टोरेज slot[0] को संशोधित या सेट करने की अनुमति देता है। इस मामले में, स्टोरेज slot[0] fibonacciLibrary एड्रेस है। इसलिए, एक हमलावर एक दुर्भावनापूर्ण कॉन्ट्रैक्ट बना सकता है (इसका एक उदाहरण नीचे दिया गया है), एड्रेस को uint में बदल सकता है (यह python में आसानी से int('<address>',16) का उपयोग करके किया जा सकता है) और फिर setStart(<attack_contract_address_as_uint>) कॉल कर सकता है। यह fibonacciLibrary को हमले वाले कॉन्ट्रैक्ट के एड्रेस में बदल देगा। फिर, जब भी कोई उपयोगकर्ता withdraw() या फॉलबैक फ़ंक्शन कॉल करता है, तो दुर्भावनापूर्ण कॉन्ट्रैक्ट चलेगा (जो कॉन्ट्रैक्ट की पूरी शेष राशि चुरा सकता है) क्योंकि हमने fibonacciLibrary के वास्तविक एड्रेस को संशोधित कर दिया है। ऐसे हमले वाले कॉन्ट्रैक्ट का एक उदाहरण होगा,```solidity contract Attack { uint storageSlot0; // corresponds to fibonacciLibrary uint storageSlot1; // corresponds to calculatedFibNumber

root@kitploit:~
// fallback - this will run if a specified function is not found
function() public {
    storageSlot1 = 0; // we set calculatedFibNumber to 0, so that if withdraw
    // is called we don't send out any ether.
    <attacker_address>.transfer(this.balance); // we take all the ether
}

}

root@kitploit:~
ध्यान दें कि यह attack contract `calculatedFibNumber` को storage `slot[1]` बदलकर संशोधित करता है। सिद्धांत रूप में, एक हमलावर अपनी पसंद के किसी भी अन्य storage slot को संशोधित कर सकता है ताकि इस contract पर विभिन्न प्रकार के हमले कर सके। मैं सभी पाठकों को प्रोत्साहित करता हूँ कि इन contracts को [Remix](https://remix.ethereum.org) में डालें और इन `delegatecall` फ़ंक्शनों के माध्यम से विभिन्न attack contracts और state changes के साथ प्रयोग करें।

यह भी ध्यान देना महत्वपूर्ण है कि जब हम कहते हैं कि `delegatecall` state-preserving है, तो हम contract के variable names की बात नहीं कर रहे हैं, बल्कि उन वास्तविक storage slots की बात कर रहे हैं जिनकी ओर ये नाम इंगित करते हैं। जैसा कि आप इस उदाहरण से देख सकते हैं, एक साधारण गलती किसी हमलावर को पूरे contract और उसकी ether पर कब्ज़ा करने का अवसर दे सकती है।

<h3 id="dc-prevention">रोकथाम की तकनीकें</h3>

Solidity लाइब्रेरी कॉन्ट्रैक्ट्स को लागू करने के लिए `library` कीवर्ड प्रदान करता है (अधिक विवरण के लिए [Solidity Docs](http://solidity.readthedocs.io/en/latest/contracts.html?highlight=library#libraries) देखें)। यह सुनिश्चित करता है कि लाइब्रेरी कॉन्ट्रैक्ट stateless और non-self-destructable है। लाइब्रेरीज़ को stateless रहने के लिए बाध्य करना इस अनुभाग में प्रदर्शित storage context की जटिलताओं को कम करता है। Stateless लाइब्रेरीज़ उन हमलों को भी रोकती हैं जिनमें हमलावर लाइब्रेरी की स्थिति को सीधे संशोधित करके उन कॉन्ट्रैक्ट्स को प्रभावित करते हैं जो लाइब्रेरी के कोड पर निर्भर हैं।
सामान्य नियम के रूप में, `DELEGATECALL` का उपयोग करते समय लाइब्रेरी कॉन्ट्रैक्ट और calling contract दोनों के संभावित calling context पर सावधानीपूर्वक ध्यान दें, और जब भी संभव हो, state-less लाइब्रेरीज़ बनाएँ।

<h3 id="dc-example">वास्तविक दुनिया का उदाहरण: पैरिटी मल्टीसिग वॉलेट (दूसरा हैक)</h3>

दूसरा पैरिटी मल्टीसिग वॉलेट हैक इस बात का उदाहरण है कि कैसे अच्छी तरह से लिखे गए लाइब्रेरी कोड के संदर्भ का शोषण किया जा सकता है यदि उसे उसके गैर-अभीष्ट संदर्भ में चलाया जाए। इस हैक की कई अच्छी व्याख्याएँ मौजूद हैं, जैसे यह अवलोकन: [Parity MultiSig Hacked. Again](https://medium.com/chain-cloud-company-blog/parity-multisig-hack-again-b46771eaa838) Anthony Akentiev द्वारा, यह [stack exchange प्रश्न](https://ethereum.stackexchange.com/questions/30128/explanation-of-parity-library-suicide/30130) और [An In-Depth Look at the Parity Multisig Bug](http://hackingdistributed.com/2017/07/22/deep-dive-parity-bug/)।

इन संदर्भों के अतिरिक्त, आइए उन contracts का पता लगाएँ जिनका शोषण किया गया था। लाइब्रेरी और वॉलेट कॉन्ट्रैक्ट parity github पर [यहाँ](https://github.com/paritytech/parity/blob/b640df8fbb964da7538eef268dffc125b081a82f/js/src/contracts/snippets/enhanced-wallet.sol) पाए जा सकते हैं।

आइए इस contract के प्रासंगिक पहलुओं को देखें। यहाँ दो रुचिकर contracts शामिल हैं: लाइब्रेरी कॉन्ट्रैक्ट और वॉलेट कॉन्ट्रैक्ट।

लाइब्रेरी कॉन्ट्रैक्ट,```solidity
contract WalletLibrary is WalletEvents {

  ...

  // throw unless the contract is not yet initialized.
  modifier only_uninitialized { if (m_numOwners > 0) throw; _; }

  // constructor - just pass on the owner array to the multiowned and
  // the limit to daylimit
  function initWallet(address[] _owners, uint _required, uint _daylimit) only_uninitialized {
    initDaylimit(_daylimit);
    initMultiowned(_owners, _required);
  }

  // kills the contract sending everything to `_to`.
  function kill(address _to) onlymanyowners(sha3(msg.data)) external {
    suicide(_to);
  }

  ...

}

और वॉलेट कॉन्ट्रैक्ट,```solidity contract Wallet is WalletEvents {

...

// METHODS

// gets called when no other function matches function() payable { // just being sent some cash? if (msg.value > 0) Deposit(msg.sender, msg.value); else if (msg.data.length > 0) _walletLibrary.delegatecall(msg.data); }

...

// FIELDS address constant _walletLibrary = 0xcafecafecafecafecafecafecafecafecafecafe; }

root@kitploit:~
ध्यान दें कि `Wallet` अनुबंध मूल रूप से सभी कॉलों को `WalletLibrary` अनुबंध को delegate call के माध्यम से पास करता है। इस कोड स्निपेट में `_walletLibrary` पता स्थिरांक वास्तव में तैनात किए गए `WalletLibrary` अनुबंध के लिए एक प्लेसहोल्डर के रूप में कार्य करता है (जो `0x863DF6BFa4469f3ead0bE8f9F2AAE51c91A907b4` पर था)।

इन अनुबंधों का इच्छित संचालन एक सरल कम लागत वाला तैनात करने योग्य `Wallet` अनुबंध रखना था जिसका कोड बेस और मुख्य कार्यक्षमता `WalletLibrary` अनुबंध में थी। दुर्भाग्य से, `WalletLibrary` अनुबंध स्वयं एक अनुबंध है और अपनी स्वयं की स्थिति बनाए रखता है। क्या आप समझ सकते हैं कि यह एक समस्या क्यों हो सकती है?

`WalletLibrary` अनुबंध को स्वयं कॉल भेजना संभव है। विशेष रूप से, `WalletLibrary` अनुबंध को आरंभीकृत किया जा सकता है, और स्वामित्व प्राप्त किया जा सकता है। एक उपयोगकर्ता ने `WalletLibrary` अनुबंध पर `initWallet()` फ़ंक्शन को कॉल करके ऐसा किया, जिससे वह लाइब्रेरी अनुबंध का स्वामी बन गया। उसी उपयोगकर्ता ने बाद में `kill()` फ़ंक्शन को कॉल किया। चूंकि उपयोगकर्ता लाइब्रेरी अनुबंध का स्वामी था, modifier पास हो गया और लाइब्रेरी अनुबंध ने आत्म-विनाश कर लिया। चूंकि अस्तित्व में सभी `Wallet` अनुबंध इस लाइब्रेरी अनुबंध को संदर्भित करते हैं और इस संदर्भ को बदलने के लिए कोई विधि नहीं रखते हैं, उनकी सभी कार्यक्षमता, ether निकालने की क्षमता सहित, `WalletLibrary` अनुबंध के साथ खो जाती है। अधिक सीधे तौर पर, इस प्रकार के सभी Parity multi-sig वॉलेट्स में मौजूद सारा ether तुरंत खो जाता है या स्थायी रूप से अप्राप्य हो जाता है।

<h2 id="visibility"><span id="SP-5">5. डिफ़ॉल्ट दृश्यताएँ</span></h2>

Solidity में फ़ंक्शन में विज़िबिलिटी स्पेसिफायर होते हैं जो यह निर्धारित करते हैं कि फ़ंक्शन को कैसे कॉल करने की अनुमति है। विज़िबिलिटी यह निर्धारित करती है कि फ़ंक्शन को उपयोगकर्ताओं द्वारा बाहरी रूप से, अन्य व्युत्पन्न अनुबंधों द्वारा, केवल आंतरिक रूप से या केवल बाह्य रूप से कॉल किया जा सकता है। चार विज़िबिलिटी स्पेसिफायर हैं, जिनका विस्तार से [Solidity Docs](http://solidity.readthedocs.io/en/latest/contracts.html?highlight=library#visibility-and-getters) में वर्णन किया गया है। फ़ंक्शन डिफ़ॉल्ट रूप से `public` होते हैं जिससे उपयोगकर्ता उन्हें बाहरी रूप से कॉल कर सकते हैं। विज़िबिलिटी स्पेसिफायर का गलत उपयोग स्मार्ट अनुबंधों में कुछ विनाशकारी कमजोरियाँ पैदा कर सकता है, जैसा कि इस अनुभाग में चर्चा की जाएगी।

<h3 id="visibility-vuln">भेद्यता</h3>

फ़ंक्शन के लिए डिफ़ॉल्ट विज़िबिलिटी `public` है। इसलिए जो फ़ंक्शन कोई विज़िबिलिटी निर्दिष्ट नहीं करते हैं, वे बाहरी उपयोगकर्ताओं द्वारा कॉल करने योग्य होंगे।  समस्या तब आती है जब डेवलपर्स गलती से उन फ़ंक्शन पर विज़िबिलिटी स्पेसिफायर को अनदेखा कर देते हैं जो निजी (या केवल अनुबंध के भीतर ही कॉल करने योग्य) होने चाहिए।

आइए शीघ्रता से एक साधारण उदाहरण देखें।```solidity
contract HashForEther {

    function withdrawWinnings() {
        // Winner if the last 8 hex characters of the address are 0.
        require(uint32(msg.sender) == 0);
        _sendWinnings();
     }

     function _sendWinnings() {
         msg.sender.transfer(this.balance);
     }
}

यह सरल अनुबंध एक पता-अनुमान बाउंटी गेम के रूप में कार्य करने के लिए डिज़ाइन किया गया है। अनुबंध की शेष राशि जीतने के लिए, उपयोगकर्ता को एक Ethereum पता उत्पन्न करना होगा जिसके अंतिम 8 हेक्स वर्ण 0 हों। एक बार प्राप्त होने पर, वे अपनी बाउंटी प्राप्त करने के लिए WithdrawWinnings() फ़ंक्शन को कॉल कर सकते हैं।

दुर्भाग्य से, फ़ंक्शनों की दृश्यता निर्दिष्ट नहीं की गई है। विशेष रूप से, _sendWinnings() फ़ंक्शन public है और इस प्रकार कोई भी पता इस फ़ंक्शन को कॉल करके बाउंटी चुरा सकता है।

रोकथाम की तकनीकें

यह अच्छा अभ्यास है कि किसी अनुबंध में सभी फ़ंक्शनों की दृश्यता हमेशा निर्दिष्ट की जाए, भले ही वे जानबूझकर public हों। Solidity के हाल के संस्करण अब संकलन के दौरान उन फ़ंक्शनों के लिए चेतावनी दिखाएंगे जिनके लिए कोई स्पष्ट दृश्यता निर्धारित नहीं है, ताकि इस अभ्यास को प्रोत्साहित किया जा सके।

वास्तविक-विश्व उदाहरण: Parity MultiSig Wallet (पहला हैक)

पहले Parity multi-sig हैक में, मुख्य रूप से तीन वॉलेट्स से लगभग $31M मूल्य का Ether चुराया गया था। यह वास्तव में कैसे किया गया, इसका एक अच्छा सारांश Haseeb Qureshi द्वारा इस पोस्ट में दिया गया है।

मूल रूप से, multi-sig वॉलेट (जिसे यहाँ पाया जा सकता है) एक आधार Wallet अनुबंध से निर्मित होता है, जो मुख्य कार्यक्षमता वाले एक लाइब्रेरी अनुबंध को कॉल करता है (जैसा कि वास्तविक-विश्व उदाहरण: Parity Multisig (दूसरा हैक) में वर्णित है)। लाइब्रेरी अनुबंध में वॉलेट को आरंभ करने का कोड होता है, जैसा कि निम्नलिखित स्निपेट से देखा जा सकता है।```solidity contract WalletLibrary is WalletEvents {

...

// METHODS

...

// constructor is given number of sigs required to do protected "onlymanyowners" transactions // as well as the selection of addresses capable of confirming them. function initMultiowned(address[] _owners, uint _required) { m_numOwners = _owners.length + 1; m_owners[1] = uint(msg.sender); m_ownerIndex[uint(msg.sender)] = 1; for (uint i = 0; i < _owners.length; ++i) { m_owners[2 + i] = uint(_owners[i]); m_ownerIndex[uint(_owners[i])] = 2 + i; } m_required = _required; }

...

// constructor - just pass on the owner array to the multiowned and // the limit to daylimit function initWallet(address[] _owners, uint _required, uint _daylimit) { initDaylimit(_daylimit); initMultiowned(_owners, _required); } }

root@kitploit:~
Notice that neither of the functions have explicitly specified a visibility. Both functions default to `public`. The `initWallet()` function is called in the wallets constructor and sets the owners for the multi-sig wallet as can be seen in the `initMultiowned()` function. Because these functions were accidentally left `public`, an attacker was able to call these functions on deployed contracts, resetting the ownership to the attackers address. Being the owner, the attacker then drained the wallets of all their ether, to the tune of \$31M.

<h2 id="entropy"><span id="SP-6">6. एंट्रॉपी भ्रम</span></h2>

All transactions on the Ethereum blockchain are deterministic state transition operations. Meaning that every transaction modifies the global state of the Ethereum ecosystem and it does so in a calculable way with no uncertainty. This ultimately means that inside the blockchain ecosystem there is no source of entropy or randomness. There is no `rand()` function in Solidity. Achieving decentralised entropy (randomness) is a well established problem and many ideas have been proposed to address this (see for example, [RandDAO](https://github.com/randao/randao) or using a chain of Hashes as described by Vitalik in this [post](https://vitalik.ca/files/randomness.html)).

<h3 id="entropy-vuln">भेद्यता</h3>

Some of the first contracts built on the Ethereum platform were based around gambling. Fundamentally, gambling requires uncertainty (something to bet on), which makes building a gambling system on the blockchain (a deterministic system) rather difficult. It is clear that the uncertainty must come from a source external to the blockchain. This is possible for bets amongst peers (see for example the [commit-reveal technique](https://ethereum.stackexchange.com/questions/191/how-can-i-securely-generate-a-random-number-in-my-smart-contract)), however, it is significantly more difficult if you want to implement a contract to act as *the house* (like in blackjack or roulette). A common pitfall is to use future block variables, such as hashes, timestamps, block number or gas limit. The issue with these are that they are controlled by the miner who mines the block and as such are not truly random. Consider, for example, a roulette smart contract with logic that returns a black number if the next block hash ends in an even number. A miner (or miner pool) could bet \$1M on black. If they solve the next block and find the hash ends in an odd number, they would happily not publish their block and mine another until they find a solution with the block hash being an even number (assuming the block reward and fees are less than $1M). Using past or present variables can be even more devastating as Martin Swende demonstrates in his excellent [blog post](http://martin.swende.se/blog/Breaking_the_house.html). Furthermore, using solely block variables mean that the pseudo-random number will be the same for all transactions in a block, so an attacker can multiply their wins by doing many transactions within a block (should there be a maximum bet).

<h3 id="entropy-prevention">रोकथाम की तकनीकें</h3>

The source of entropy (randomness) must be external to the blockchain. This can be done amongst peers with systems such as [commit-reveal](https://ethereum.stackexchange.com/questions/191/how-can-i-securely-generate-a-random-number-in-my-smart-contract), or via changing the trust model to a group of participants (such as in [RandDAO](https://github.com/randao/randao)). This can also be done via a centralised entity, which acts as a randomness oracle. Block variables (in general, there are some exceptions) should not be used to source entropy as they can be manipulated by miners.

<h3 id="entropy-example">वास्तविक-दुनिया का उदाहरण: PRNG कॉन्ट्रैक्ट</h3>

Arseny Reutov wrote a [blog post](https://blog.positive.com/predicting-random-numbers-in-ethereum-smart-contracts-e5358c6b8620) after he analysed 3649 live smart contracts which were using some sort of pseudo random number generator (PRNG) and found 43 contracts which could be exploited.

<h2 id="contract-reference"><span id="SP-7">7. बाहरी कॉन्ट्रैक्ट संदर्भन</span></h2>

One of the benefits of the Ethereum *global computer* is the ability to re-use code and interact with contracts already deployed on the network. As a result, a large number of contracts reference external contracts and in general operation use external message calls to interact with these contracts. These external message calls can mask malicious actors intentions in some non-obvious ways, which we will discuss.

<h3 id="cr-vuln">भेद्यता</h3>

In Solidity, any address can be cast as a contract regardless of whether the code at the address represents the contract type being cast. This can be deceiving, especially when the author of the contract is trying to hide malicious code. Let us illustrate this with an example:

Consider a piece of code which rudimentarily implements the [Rot13](https://github.com/al1ex/soliditysecurity/blob/HEAD/www.wikipedia.com/rot13) cipher.

`Rot13Encryption.sol`:```solidity
//encryption contract
contract Rot13Encryption {

   event Result(string convertedString);

    //rot13 encrypt a string
    function rot13Encrypt (string text) public {
        uint256 length = bytes(text).length;
        for (var i = 0; i < length; i++) {
            byte char = bytes(text)[i];
            //inline assembly to modify the string
            assembly {
                char := byte(0,char) // get the first byte
                if and(gt(char,0x6D), lt(char,0x7B)) // if the character is in [n,z], i.e. wrapping.
                { char:= sub(0x60, sub(0x7A,char)) } // subtract from the ascii number a by the difference char is from z.
                if iszero(eq(char, 0x20)) // ignore spaces
                {mstore8(add(add(text,0x20), mul(i,1)), add(char,13))} // add 13 to char.
            }
        }
        emit Result(text);
    }

    // rot13 decrypt a string
    function rot13Decrypt (string text) public {
        uint256 length = bytes(text).length;
        for (var i = 0; i < length; i++) {
            byte char = bytes(text)[i];
            assembly {
                char := byte(0,char)
                if and(gt(char,0x60), lt(char,0x6E))
                { char:= add(0x7B, sub(char,0x61)) }
                if iszero(eq(char, 0x20))
                {mstore8(add(add(text,0x20), mul(i,1)), sub(char,13))}
            }
        }
        emit Result(text);
    }
}

यह कोड बस एक स्ट्रिंग (a-z अक्षर, बिना किसी सत्यापन के) लेता है और प्रत्येक वर्ण को 13 स्थान दाईं ओर खिसका कर (z के चारों ओर लपेटते हुए) एन्क्रिप्ट करता है; अर्थात 'a' 'n' में बदलता है और 'x' 'k' में। यहाँ की असेंबली महत्वपूर्ण नहीं है, इसलिए चिंता न करें अगर यह इस चरण में समझ में न आए।

निम्नलिखित कॉन्ट्रैक्ट पर विचार करें जो अपने एन्क्रिप्शन के लिए इस कोड का उपयोग करता है,```solidity import "Rot13Encryption.sol";

// encrypt your top secret info contract EncryptionContract { // library for encryption Rot13Encryption encryptionLibrary;

root@kitploit:~
// constructor - initialise the library
constructor(Rot13Encryption _encryptionLibrary) {
    encryptionLibrary = _encryptionLibrary;
}

function encryptPrivateData(string privateInfo) {
    // potentially do some operations here
    encryptionLibrary.rot13Encrypt(privateInfo);
 }

}

root@kitploit:~
इस अनुबंध के साथ समस्या यह है कि `encryptionLibrary` पता सार्वजनिक या स्थिर नहीं है। इस प्रकार, अनुबंध का डिप्लॉयर कंस्ट्रक्टर में एक ऐसा पता दे सकता था जो इस अनुबंध की ओर इंगित करता है:```solidity
//encryption contract
contract Rot26Encryption {

   event Result(string convertedString);

    //rot13 encrypt a string
    function rot13Encrypt (string text) public {
        uint256 length = bytes(text).length;
        for (var i = 0; i < length; i++) {
            byte char = bytes(text)[i];
            //inline assembly to modify the string
            assembly {
                char := byte(0,char) // get the first byte
                if and(gt(char,0x6D), lt(char,0x7B)) // if the character is in [n,z], i.e. wrapping.
                { char:= sub(0x60, sub(0x7A,char)) } // subtract from the ascii number a by the difference char is from z.
                if iszero(eq(char, 0x20)) // ignore spaces
                {mstore8(add(add(text,0x20), mul(i,1)), add(char,26))} // add 13 to char.
            }
        }
        emit Result(text);
    }

    // rot13 decrypt a string
    function rot13Decrypt (string text) public {
        uint256 length = bytes(text).length;
        for (var i = 0; i < length; i++) {
            byte char = bytes(text)[i];
            assembly {
                char := byte(0,char)
                if and(gt(char,0x60), lt(char,0x6E))
                { char:= add(0x7B, sub(char,0x61)) }
                if iszero(eq(char, 0x20))
                {mstore8(add(add(text,0x20), mul(i,1)), sub(char,26))}
            }
        }
        emit Result(text);
    }
}

जो rot26 सिफर को लागू करता है (प्रत्येक अक्षर को 26 स्थानों पर स्थानांतरित करता है, समझे? :p)। फिर से, इस कॉन्ट्रैक्ट में असेंबली को समझने की कोई आवश्यकता नहीं है। डिप्लॉयर निम्नलिखित कॉन्ट्रैक्ट को भी लिंक कर सकता था:```solidity contract Print{ event Print(string text);

root@kitploit:~
function rot13Encrypt(string text) public {
    emit Print(text);
}

}

root@kitploit:~
यदि इनमें से किसी भी अनुबंध का पता कंस्ट्रक्टर में दिया गया होता, तो `encryptPrivateData()` फ़ंक्शन केवल एक इवेंट उत्पन्न करेगा जो अनएन्क्रिप्टेड निजी डेटा को प्रिंट करता है। हालाँकि इस उदाहरण में कंस्ट्रक्टर में एक लाइब्रेरी-जैसा अनुबंध सेट किया गया था, अक्सर ऐसा होता है कि एक विशेषाधिकार प्राप्त उपयोगकर्ता (जैसे `owner`) लाइब्रेरी अनुबंध पते बदल सकता है। यदि किसी लिंक किए गए अनुबंध में वह फ़ंक्शन शामिल नहीं है जिसे कॉल किया जा रहा है, तो फ़ॉलबैक फ़ंक्शन निष्पादित होगा। उदाहरण के लिए, `encryptionLibrary.rot13Encrypt()` पंक्ति के साथ, यदि `encryptionLibrary` द्वारा निर्दिष्ट अनुबंध था:```solidity
 contract Blank {
     event Print(string text);
     function () {
         emit Print("Here");
         //put malicious code here and it will run
     }
 }

तब "Here" पाठ वाला एक इवेंट उत्सर्जित होगा। इस प्रकार यदि उपयोगकर्ता कॉन्ट्रैक्ट लाइब्रेरीज़ को बदल सकते हैं, तो वे सैद्धांतिक रूप से उपयोगकर्ताओं से अनजाने में मनमाना कोड चलवा सकते हैं।

ध्यान दें: ऐसे एन्क्रिप्शन कॉन्ट्रैक्ट का उपयोग न करें, क्योंकि स्मार्ट कॉन्ट्रैक्ट के इनपुट पैरामीटर ब्लॉकचेन पर दृश्यमान होते हैं। साथ ही Rot सिफर एक अनुशंसित एन्क्रिप्शन तकनीक नहीं है :p

निवारक तकनीकें

जैसा ऊपर प्रदर्शित किया गया है, भेद्यता-मुक्त कॉन्ट्रैक्ट को (कुछ मामलों में) इस तरह तैनात किया जा सकता है कि वे दुर्भावनापूर्ण व्यवहार करें। एक ऑडिटर सार्वजनिक रूप से किसी कॉन्ट्रैक्ट को सत्यापित कर सकता है और उसका स्वामी इसे दुर्भावनापूर्ण तरीके से तैनात कर सकता है, जिसके परिणामस्वरूप एक सार्वजनिक रूप से ऑडिट किया गया कॉन्ट्रैक्ट होगा जिसमें भेद्यताएँ या दुर्भावनापूर्ण इरादे हों।

ऐसी कई तकनीकें हैं जो इन परिदृश्यों को रोकती हैं।

एक तकनीक, कॉन्ट्रैक्ट बनाने के लिए new कीवर्ड का उपयोग करना है। उपरोक्त उदाहरण में, कंस्ट्रक्टर इस प्रकार लिखा जा सकता है:```solidity constructor() { encryptionLibrary = new Rot13Encryption(); }

root@kitploit:~
इस तरह, संदर्भित कॉन्ट्रैक्ट का एक इंस्टेंस डिप्लॉयमेंट के समय बनाया जाता है और डिप्लॉयर स्मार्ट कॉन्ट्रैक्ट को संशोधित किए बिना `Rot13Encryption` कॉन्ट्रैक्ट को किसी और चीज़ से प्रतिस्थापित नहीं कर सकता।

एक और समाधान यह है कि यदि ज्ञात हों तो किसी भी बाहरी कॉन्ट्रैक्ट पते को हार्ड कोड कर दिया जाए।

सामान्य तौर पर, बाहरी कॉन्ट्रैक्ट को कॉल करने वाले कोड को हमेशा ध्यान से देखा जाना चाहिए। एक डेवलपर के रूप में, बाहरी कॉन्ट्रैक्ट को परिभाषित करते समय, कॉन्ट्रैक्ट पतों को सार्वजनिक करना एक अच्छा विचार हो सकता है (जैसा कि नीचे दिए गए हनी-पॉट उदाहरण में नहीं है) ताकि उपयोगकर्ता आसानी से जांच सकें कि कॉन्ट्रैक्ट द्वारा किस कोड का संदर्भ दिया जा रहा है। इसके विपरीत, यदि किसी कॉन्ट्रैक्ट में कोई निजी वेरिएबल कॉन्ट्रैक्ट पता है, तो यह किसी के दुर्भावनापूर्ण व्यवहार का संकेत हो सकता है (जैसा कि वास्तविक-विश्व उदाहरण में दिखाया गया है)। यदि कोई विशेषाधिकार प्राप्त (या कोई भी) उपयोगकर्ता किसी कॉन्ट्रैक्ट पते को बदलने में सक्षम है जिसका उपयोग बाहरी फ़ंक्शन को कॉल करने के लिए किया जाता है, तो (विकेंद्रीकृत सिस्टम के संदर्भ में) टाइम-लॉक या मतदान तंत्र लागू करना महत्वपूर्ण हो सकता है, ताकि उपयोगकर्ता देख सकें कि कौन सा कोड बदला जा रहा है या प्रतिभागियों को नए कॉन्ट्रैक्ट पते के साथ ऑप्ट इन/आउट करने का अवसर मिल सके।


<h3 id="cr-example">वास्तविक-विश्व उदाहरण: री-एंट्रेंसी हनी पॉट</h3>

हाल ही में कई हनी पॉट मेननेट पर जारी किए गए हैं। ये कॉन्ट्रैक्ट उन एथेरियम हैकर्स को मात देने की कोशिश करते हैं जो कॉन्ट्रैक्ट का शोषण करने की कोशिश करते हैं, लेकिन जो बदले में उस कॉन्ट्रैक्ट में ईथर खो देते हैं जिसका वे शोषण करने की उम्मीद करते हैं। एक उदाहरण उपरोक्त हमले का उपयोग करता है, जिसमें कंस्ट्रक्टर में एक अपेक्षित कॉन्ट्रैक्ट को एक दुर्भावनापूर्ण कॉन्ट्रैक्ट से बदल दिया जाता है। कोड [यहाँ](https://etherscan.io/address/0x95d34980095380851902ccd9a1fb4c813c2cb639#code) पाया जा सकता है:```solidity
pragma solidity ^0.4.19;

contract Private_Bank
{
    mapping (address => uint) public balances;
    uint public MinDeposit = 1 ether;
    Log TransferLog;

    function Private_Bank(address _log)
    {
        TransferLog = Log(_log);
    }

    function Deposit()
    public
    payable
    {
        if(msg.value >= MinDeposit)
        {
            balances[msg.sender]+=msg.value;
            TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
        }
    }

    function CashOut(uint _am)
    {
        if(_am<=balances[msg.sender])
        {
            if(msg.sender.call.value(_am)())
            {
                balances[msg.sender]-=_am;
                TransferLog.AddMessage(msg.sender,_am,"CashOut");
            }
        }
    }

    function() public payable{}

}

contract Log
{
    struct Message
    {
        address Sender;
        string  Data;
        uint Val;
        uint  Time;
    }

    Message[] public History;
    Message LastMsg;

    function AddMessage(address _adr,uint _val,string _data)
    public
    {
        LastMsg.Sender = _adr;
        LastMsg.Time = now;
        LastMsg.Val = _val;
        LastMsg.Data = _data;
        History.push(LastMsg);
    }
}

यह पोस्ट एक Reddit उपयोगकर्ता द्वारा बताती है कि कैसे उन्होंने इस कॉन्ट्रैक्ट में मौजूद री-एंट्रेंसी बग का फायदा उठाने की कोशिश करके 1 ईथर खो दिया।

8. शॉर्ट एड्रेस/पैरामीटर अटैक

यह अटैक विशेष रूप से Solidity कॉन्ट्रैक्ट्स पर नहीं, बल्कि तीसरे पक्ष के एप्लिकेशनों पर किया जाता है जो उनके साथ इंटरैक्ट कर सकते हैं। मैं इस अटैक को पूर्णता के लिए जोड़ रहा हूँ और यह जानने के लिए कि कॉन्ट्रैक्ट्स में पैरामीटर कैसे हेरफेर किए जा सकते हैं।

आगे पढ़ने के लिए, देखें The ERC20 Short Address Attack Explained, ICO Smart contract Vulnerability: Short Address Attack या यह reddit post।

कमजोरी

स्मार्ट कॉन्ट्रैक्ट में पैरामीटर पास करते समय, पैरामीटर ABI specification के अनुसार एन्कोड किए जाते हैं। ऐसे एन्कोडेड पैरामीटर भेजना संभव है जो अपेक्षित पैरामीटर लंबाई से छोटे हों (उदाहरण के लिए, मानक 40 हेक्स अक्षरों (20 बाइट्स) के बजाय केवल 38 हेक्स अक्षरों (19 बाइट्स) वाला एड्रेस भेजना)। ऐसे परिदृश्य में, EVM अपेक्षित लंबाई पूरी करने के लिए एन्कोडेड पैरामीटर के अंत में 0 जोड़ देगा।

यह तब समस्या बन जाता है जब तीसरे पक्ष के एप्लिकेशन इनपुट सत्यापित नहीं करते। सबसे स्पष्ट उदाहरण एक एक्सचेंज है जो यह सत्यापित नहीं करता कि उपयोगकर्ता द्वारा निकासी का अनुरोध करते समय ERC20 टोकन का एड्रेस सही है। यह उदाहरण पीटर वेनेसीस की पोस्ट, The ERC20 Short Address Attack Explained में अधिक विस्तार से कवर किया गया है, जिसका ऊपर उल्लेख किया गया है।

मानक ERC20 transfer फ़ंक्शन इंटरफ़ेस पर विचार करें, पैरामीटर के क्रम पर ध्यान दें,```solidity function transfer(address to, uint tokens) public returns (bool success);

root@kitploit:~
Now consider, an exchange, holding a large amount of a token (let's say `REP`) and a user wishes to withdraw their share of 100 tokens. The user would submit their address, `0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead` and the number of tokens, `100`. The exchange would encode these parameters in the order specified by the `transfer()` function, i.e. `address` then `tokens`. The encoded result would be `a9059cbb000000000000000000000000deaddeaddeaddeaddeaddeaddeaddeaddeaddead0000000000` `000000000000000000000000000000000056bc75e2d63100000`. The first four bytes (`a9059cbb`) are the `transfer()` [function signature/selector](https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector), the second 32 bytes are the address, followed by the final 32 bytes which represent the `uint256` number of tokens. Notice that the hex `56bc75e2d63100000` at the end corresponds to 100 tokens (with 18 decimal places, as specified by the `REP` token contract).

ठीक है, अब देखते हैं कि क्या होता है यदि हम एक ऐसा पता भेजते हैं जिसमें 1 बाइट (2 हेक्स अंक) कम हों। विशेष रूप से, मान लें कि एक हमलावर `0xdeaddeaddeaddeaddeaddeaddeaddeaddeadde` को पते के रूप में भेजता है (अंतिम दो अंक गायब हैं) और उसी `100` टोकन को निकालने के लिए। यदि एक्सचेंज इस इनपुट को मान्य नहीं करता है, तो यह `a9059cbb000000000000000000000000deaddeaddeaddeaddeaddeaddeaddeaddeadde00000000000000` `00000000000000000000000000000000056bc75e2d6310000000` के रूप में एनकोड हो जाएगा। अंतर सूक्ष्म है। ध्यान दें कि भेजे गए छोटे पते की भरपाई के लिए एन्कोडिंग के अंत में `00` जोड़ दिया गया है। जब यह स्मार्ट कॉन्ट्रैक्ट को भेजा जाता है, तो `address` पैरामीटर `0xdeaddeaddeaddeaddeaddeaddeaddeaddeadde00` के रूप में पढ़े जाएंगे और मान `56bc75e2d6310000000` के रूप में पढ़ा जाएगा (दो अतिरिक्त `0` देखें)। यह मान अब `25600` टोकन है (मान को `256` से गुणा किया गया है)। इस उदाहरण में, यदि एक्सचेंज के पास इतने टोकन होते, तो उपयोगकर्ता संशोधित पते पर `25600` टोकन निकाल लेता (जबकि एक्सचेंज सोचता है कि उपयोगकर्ता केवल `100` निकाल रहा है)। जाहिर है, इस उदाहरण में हमलावर के पास संशोधित पता नहीं होगा, लेकिन यदि हमलावर कोई भी ऐसा पता उत्पन्न करता है जो `0` पर समाप्त होता है (जिसे आसानी से ब्रूट फोर्स किया जा सकता है) और उस उत्पन्न पते का उपयोग करता है, तो वह आसानी से अनजान एक्सचेंज से टोकन चुरा सकता है।

<h3 id="short-prev">निवारक तकनीकें</h3>

Read more

टूल डाउनलोड करें

Attack.sol - लाइन [25] - दुर्भावनापूर्ण अनुबंध को भेजा गया ether फिर फ़ॉलबैक फ़ंक्शन को निष्पादित करेगा।

  • Attack.sol - लाइन [26] - EtherStore अनुबंध का कुल बैलेंस 10 ether था और अब 9 ether है, इसलिए यह if स्टेटमेंट पास हो जाता है।

  • Attack.sol - लाइन [27] - फिर फ़ॉलबैक फ़ंक्शन EtherStore के withdrawFunds() फ़ंक्शन को दोबारा कॉल करता है और EtherStore अनुबंध में re-enters (पुनः प्रवेश) करता है।

  • EtherStore.sol - लाइन [11] - withdrawFunds() की इस दूसरी कॉल में, हमारा बैलेंस अभी भी 1 ether है क्योंकि लाइन [18] अभी तक निष्पादित नहीं हुई है। इस प्रकार, हमारे पास अभी भी balances[0x0..123] = 1 ether है। यही बात lastWithdrawTime चर के लिए भी सत्य है। हम फिर से सभी आवश्यकताओं को पूरा करते हैं।

  • EtherStore.sol - लाइन [17] - हम एक और 1 ether निकाल लेते हैं।

  • चरण 4-8 दोहराए जाएँगे - जब तक EtherStore.balance >= 1 हो, जैसा कि Attack.sol में लाइन [26] द्वारा निर्धारित है।

  • Attack.sol - लाइन [26] - एक बार EtherStore अनुबंध में 1 (या उससे कम) ether बच जाता है, तो यह if स्टेटमेंट विफल हो जाएगा। इसके बाद EtherStore अनुबंध की लाइनें [18] और [19] निष्पादित हो सकेंगी (withdrawFunds() फ़ंक्शन की प्रत्येक कॉल के लिए)।

  • EtherStore.sol - लाइनें [18] और [19] - balances और lastWithdrawTime मैपिंग सेट कर दी जाएँगी और निष्पादन समाप्त हो जाएगा।

  • FibonacciBalance
    start
    start
    slot[1]
    fibonacci(n)
    fibonacciLibrary
    uint
    withdraw()
    uint(fibonacciLibrary)
    calculatedFibNumber