Lucene search

K
code423n4Code4renaCODE423N4:2023-03-WENWIN-FINDINGS-ISSUES-454
HistoryMar 09, 2023 - 12:00 a.m.

SWC-101 Artihmetic Overflow test/LotteryInvariantChecks.t.sol testBuyClaimFinalize()

2023-03-0900:00:00
Code4rena
github.com
4
arithmetic overflow
vulnerability
finalizedraw
testbuyclaimfinalize
failing test

Lines of code
<https://github.com/code-423n4/2023-03-wenwin/blob/91b89482aaedf8b8feb73c771d11c257eed997e8/src/RNSourceBase.sol#L17-L20&gt;

Vulnerability details

Impact

Integer overflow on finalizeDraw() function.
Failing tests:
Encountered 1 failing test in test/LotteryInvariantChecks.t.sol:LotteryInvariantChecksTest
[FAIL. Reason: Arithmetic over/underflow Counterexample: calldata=0xbbbd8cb8000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000, args=[[0], [0x0000000000000000000000000000000000000000], 115792089237316195423570985008687907853269984665640564039457584007913129639935]] testBuyClaimFinalize(uint256[],address[],uint256) (runs: 298, μ: 2549628, ~: 571280)

Proof of Concept

# POC Code&gt; test/LotteryInvariantChecks.t.sol:

function testBuyClaimFinalize(uint256[] memory tickets, address[] memory users, uint256 randomNumber) public {
        vm.assume(tickets.length &gt; 0);
        vm.assume(users.length &gt; 0);

        buyRandomTickets(tickets, users);
        claimRewards();

        finalizeDraw(randomNumber+1); // oxtr3 added integer overfloe
    }



# Vulnerable Lines Of Code:
https://github.com/code-423n4/2023-03-wenwin/blob/91b89482aaedf8b8feb73c771d11c257eed997e8/src/Lottery.sol#L203-L214

https://github.com/code-423n4/2023-03-wenwin/blob/91b89482aaedf8b8feb73c771d11c257eed997e8/src/RNSourceBase.sol#L17-L20



# Command Line:
forge test -vvvv  --match-path "test/LotteryInvariantChecks.t.sol" --match-test "testBuyClaimFinalize"



# Log:
oxtr3 2023-03-wenwin % forge test -vvvv  --match-path "test/LotteryInvariantChecks.t.sol" --match-test "testBuyClaimFinalize"
[⠒] Compiling...
No files changed, compilation skipped

Running 1 test for test/LotteryInvariantChecks.t.sol:LotteryInvariantChecksTest
[FAIL. Reason: Arithmetic over/underflow Counterexample: calldata=0xbbbd8cb8000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000, args=[[0], [0x0000000000000000000000000000000000000000], 115792089237316195423570985008687907853269984665640564039457584007913129639935]] testBuyClaimFinalize(uint256[],address[],uint256) (runs: 298, μ: 2549628, ~: 571280)
Logs:
  Bound Result 1

Traces:
  [11618533] LotteryInvariantChecksTest::setUp() 
    ├─ [523854] → new TestToken@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    │   └─ ← 2391 bytes of code
    ├─ [8226018] → new Lottery@0x2e234DAe75C793f67A35089C9d99245E1C58470b
    │   ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: LotteryInvariantChecksTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496])
    │   ├─ [607209] → new LotteryToken@0xffD4505B3452Dc22f8473616d50503bA9E1710Ac
    │   │   ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], value: 1000000000000000000000000000)
    │   │   └─ ← 2576 bytes of code
    │   ├─ [266] TestToken::decimals() [staticcall]
    │   │   └─ ← 18
    │   ├─ [266] TestToken::decimals() [staticcall]
    │   │   └─ ← 18
    │   ├─ emit LotteryDeployed(token: TestToken: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], drawSchedule: 0x7c951a6396053543c7db9b57f82a1e88f32937b4a0c345d31d367e7074703ab3, ticketPrice: 5000000000000000000, selectionSize: 4, selectionMax: 10, expectedPayout: 380000000000000000, fixedRewards: [0, 5000000000000000000, 10000000000000000000, 15000000000000000000])
    │   ├─ [1177729] → new Staking@0x8d2C17FAd02B7bb64139109c6533b7C2b9CADb81
    │   │   └─ ← 5649 bytes of code
    │   ├─ [240] LotteryToken::INITIAL_SUPPLY() [staticcall]
    │   │   └─ ← 1000000000000000000000000000
    │   ├─ [20013] LotteryToken::transfer(LotteryInvariantChecksTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], 1000000000000000000000000000) 
    │   │   ├─ emit Transfer(from: Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], to: LotteryInvariantChecksTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], value: 1000000000000000000000000000)
    │   │   └─ ← true
    │   └─ ← 19401 bytes of code
    ├─ [327] Lottery::nativeToken() [staticcall]
    │   └─ ← LotteryToken: [0xffD4505B3452Dc22f8473616d50503bA9E1710Ac]
    ├─ [46544] TestToken::mint(1000000000000000000000000) 
    │   ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: LotteryInvariantChecksTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], value: 1000000000000000000000000)
    │   └─ ← ()
    ├─ [20031] TestToken::transfer(Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], 1000000000000000000000000) 
    │   ├─ emit Transfer(from: LotteryInvariantChecksTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], to: Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], value: 1000000000000000000000000)
    │   └─ ← true
    ├─ [263] Lottery::initialPotDeadline() [staticcall]
    │   └─ ← 172801
    ├─ [0] VM::warp(172802) 
    │   └─ ← ()
    ├─ [24520] Lottery::finalizeInitialPotRaise() 
    │   ├─ [540] TestToken::balanceOf(Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b]) [staticcall]
    │   │   └─ ← 1000000000000000000000000
    │   ├─ emit InitialPotPeriodFinalized(amountRaised: 1000000000000000000000000)
    │   └─ ← ()
    ├─ [24075] Lottery::initSource(0x00000000000000000000000000000000499602D2) 
    │   ├─ emit SourceSet(source: 0x00000000000000000000000000000000499602D2)
    │   └─ ← ()
    ├─ [0] VM::mockCall(0x00000000000000000000000000000000499602D2, 0x8678a7b2, 0x0000000000000000000000000000000000000000000000000000000000000000) 
    │   └─ ← ()
    └─ ← ()

  [315057] LotteryInvariantChecksTest::testBuyClaimFinalize([0], [0x0000000000000000000000000000000000000000], 115792089237316195423570985008687907853269984665640564039457584007913129639935) 
    ├─ [0] VM::assume(true) [staticcall]
    │   └─ ← ()
    ├─ [0] VM::assume(true) [staticcall]
    │   └─ ← ()
    ├─ [0] console::log(Bound Result, 1) [staticcall]
    │   └─ ← ()
    ├─ [0] VM::startPrank(0x0000000000000000000000000000000000000001) 
    │   └─ ← ()
    ├─ [29444] TestToken::mint(5000000000000000000) 
    │   ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000000000001, value: 5000000000000000000)
    │   └─ ← ()
    ├─ [24628] TestToken::approve(Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], 5000000000000000000) 
    │   ├─ emit Approval(owner: 0x0000000000000000000000000000000000000001, spender: Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], value: 5000000000000000000)
    │   └─ ← true
    ├─ [2504] Lottery::currentDraw() [staticcall]
    │   └─ ← 0
    ├─ [162734] Lottery::buyTickets([0], [15], 0x00000000000000000000000000000000000001bc, 0x0000000000000000000000000000000000000000) 
    │   ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000000000001, tokenId: 0)
    │   ├─ emit NewTicket(currentDraw: 0, ticketId: 0, drawId: 0, user: 0x0000000000000000000000000000000000000001, combination: 15, frontend: 0x00000000000000000000000000000000000001bc, referrer: 0x0000000000000000000000000000000000000000)
    │   ├─ [8498] TestToken::transferFrom(0x0000000000000000000000000000000000000001, Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], 5000000000000000000) 
    │   │   ├─ emit Approval(owner: 0x0000000000000000000000000000000000000001, spender: Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], value: 0)
    │   │   ├─ emit Transfer(from: 0x0000000000000000000000000000000000000001, to: Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], value: 5000000000000000000)
    │   │   └─ ← true
    │   └─ ← [0]
    ├─ [0] VM::stopPrank() 
    │   └─ ← ()
    ├─ [51959] Lottery::claimRewards(1) 
    │   ├─ emit ClaimedRewards(rewardRecipient: Staking: [0x8d2C17FAd02B7bb64139109c6533b7C2b9CADb81], amount: 1000000000000000000, rewardType: 1)
    │   ├─ [25038] TestToken::transfer(Staking: [0x8d2C17FAd02B7bb64139109c6533b7C2b9CADb81], 1000000000000000000) 
    │   │   ├─ emit Transfer(from: Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], to: Staking: [0x8d2C17FAd02B7bb64139109c6533b7C2b9CADb81], value: 1000000000000000000)
    │   │   └─ ← true
    │   └─ ← 1000000000000000000
    ├─ [0] VM::prank(0x00000000000000000000000000000000000001bc) 
    │   └─ ← ()
    ├─ [23874] Lottery::claimRewards(0) 
    │   ├─ emit ClaimedRewards(rewardRecipient: 0x00000000000000000000000000000000000001bc, amount: 500000000000000000, rewardType: 0)
    │   ├─ [25038] TestToken::transfer(0x00000000000000000000000000000000000001bc, 500000000000000000) 
    │   │   ├─ emit Transfer(from: Lottery: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], to: 0x00000000000000000000000000000000000001bc, value: 500000000000000000)
    │   │   └─ ← true
    │   └─ ← 500000000000000000
    ├─ [1238] Lottery::unclaimedRewards(1) [staticcall]
    │   └─ ← 0
    ├─ [0] VM::prank(0x00000000000000000000000000000000000001bc) 
    │   └─ ← ()
    ├─ [1107] Lottery::unclaimedRewards(0) [staticcall]
    │   └─ ← 0
    └─ ← "Arithmetic over/underflow"

Test result: FAILED. 0 passed; 1 failed; finished in 1.97s

Failing tests:
Encountered 1 failing test in test/LotteryInvariantChecks.t.sol:LotteryInvariantChecksTest
[FAIL. Reason: Arithmetic over/underflow Counterexample: calldata=0xbbbd8cb8000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000, args=[[0], [0x0000000000000000000000000000000000000000], 115792089237316195423570985008687907853269984665640564039457584007913129639935]] testBuyClaimFinalize(uint256[],address[],uint256) (runs: 298, μ: 2549628, ~: 571280)

Encountered a total of 1 failing tests, 0 tests succeeded
oxtr3 2023-03-wenwin %

Tools Used

Foundry + VS Code

Recommended Mitigation Steps

use safe math

The text was updated successfully, but these errors were encountered:

All reactions