code-423n4 / 2024-02-althea-liquid-infrastructure-findings

3 stars 1 forks source link

Reentracy in '_withdrawBalancesTo' function in LiquidInfrastructureNFT.sol enables owner of account token to withdraw available balance mutiple times. #746

Closed c4-bot-6 closed 8 months ago

c4-bot-6 commented 9 months ago

Lines of code

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/bd6ee47162368e1999a0a5b8b17b701347cf9a7d/liquid-infrastructure/contracts/LiquidInfrastructureNFT.sol#L181

Vulnerability details

Impact

The 'withdrawBalancesTo' function makes an IERC20.transfer call to send balance to 'destination'. However, before updating the contract's internal balance, it checks if the transfer was successful.

' for (uint i = 0; i < erc20s.length; i++) { address erc20 = erc20s[i]; uint256 balance = IERC20(erc20).balanceOf(address(this)); if (balance > 0) { bool result = IERC20(erc20).transfer(destination, balance); require(result, "unsuccessful withdrawal"); amounts[i] = balance; } } emit SuccessfulWithdrawal(destination, erc20s, amounts); } '

This can be exploited by creating a malicious ERC20 contract that re-enters the 'withdrawBalancesTo' function after the transfer. The attacker's(owner of the account tokens in our case) contract could then trick the 'withdrawBalancesTo' function into withdrawing the balance multiple times before the state update occurs, essentially draining the contract's balance.

Proof of Concept

Steps

1.Attacker Deploys Malicious ERC20 Contract:

The contract implements a transferFrom function that allows the attacker to control the execution flow. When the contract calls transferFrom to transfer the balance, the attacker's contract can intercept the call and trigger its own malicious logic.

2.Attacker Initiates Withdrawal:

The attacker calls the withdrawBalancesTo function with the malicious ERC20 contract address as the destination.

3.'withdrawBalancesTo' function executes:

The withdrawBalancesTo function retrieves the balance of the ERC20 token in the contract. It then calls the transferFrom function of the malicious ERC20 contract to transfer the tokens to the attacker's address.

4.Attacker's Contract Re-Enters:

Inside the malicious transferFrom function, the attacker's contract: Calls the withdrawBalancesTo function again recursively, effectively re-entering the vulnerable function. This time, the attacker modifies the behavior of the transferFrom function to return a smaller amount of tokens (e.g., 0) to the contract.

5.Vulnerable Function Continues:

The withdrawBalancesTo function now receives the smaller amount of tokens back from the transferFrom call. Unaware of the re-entrance, it updates its internal balance with the smaller amount.

6.Attacker Drains Funds:

Since the attacker controlled the transferFrom behavior, they can repeat steps 4 and 5 withdrawing the stated balance as long as its not 0 an has not been updated. .

Tools Used

Manual review.

Recommended Mitigation Steps.

Check-before-effect patterns: Consider updating the internal balance before making the external transfer and also having reentrancy guards designed to prevent reentrancy.

Assessed type

Reentrancy

c4-pre-sort commented 9 months ago

0xRobocop marked the issue as insufficient quality report

c4-judge commented 8 months ago

0xA5DF marked the issue as unsatisfactory: Invalid

0xA5DF commented 8 months ago

the attacker's(owner of the account tokens in our case) contract could then trick the 'withdrawBalancesTo' function into withdrawing the balance multiple times

You can't transfer the balance more than once, the function would simply revert (or send 0 balance the second time)