OpenZeppelin's ERC721.sol includes callback functions to manage NFTs and prevent them from getting stuck in contracts. For NFT contracts, there exist some implicit external function calls that could be neglected by developers. They include onERC721Received function. The onERC721Received function was designed to check whether the receiver contract can handle NFTs. This function is invoked in the safeTransferFrom() of the ERC721 contract. Due to this external function call, the reentrancy could happen without being noticed by contract developer.
According to what I said above, the malicious person can abuse the same things and write in the onERC721Received
function of his contract to call the withdrawTokens()
function many times in a loop.
In the withdrawTokens()
function of the Bridge.sol
contract, the _withdrawFromEscrow()
function is called.
https://github.com/Cyfrin/2024-07-ark-project/blob/main/apps/blockchain/ethereum/src/Bridge.sol#L201
safeTransferFrom
is called in the _withdrawFromEscrow
function
https://github.com/Cyfrin/2024-07-ark-project/blob/main/apps/blockchain/ethereum/src/Escrow.sol#L79
POC :
Attacker calls the withdrawTokens()
function.
Due to the lack of Reentrancy Guard adherence, the attacker re-enters the withdrawTokens()
function in onERC721Received
before the initial call completes.
This process can be repeated, allowing the attacker to withdraw token/NFT more than their allowed.
The same explanation above is also true for the following.
Actually, the onERC1155Received callback function is invoked in ERC1155.safeTransferFrom
.
In addition, there is also the problem of lack of CEI pattern here
https://github.com/Cyfrin/2024-07-ark-project/blob/main/apps/blockchain/ethereum/src/Bridge.sol#L129
https://github.com/Cyfrin/2024-07-ark-project/blob/main/apps/blockchain/ethereum/src/Escrow.sol#L46
https://samczsun.com/the-dangers-of-surprising-code/
https://blog.openzeppelin.com/reentrancy-after-istanbul
https://eips.ethereum.org/EIPS/eip-721
https://docs.openzeppelin.com/contracts/3.x/api/token/erc1155
https://medium.com/amber-group/position-exchanges-re-entrancy-loophole-explained-ef176a0fd987
https://medium.com/immunefi/hack-analysis-omni-protocol-july-2022-2d35091a0109
https://solodit.xyz/issues/re-entrancy-issue-for-erc1155-fixed-consensys-bridge-mutual-markdown
https://www.rareskills.io/post/where-to-find-solidity-reentrancy-attacks
https://blocksecteam.medium.com/revest-finance-vulnerabilities-more-than-re-entrancy-1609957b742f
An attacker can withdraw a large amount of tokens/NFTs using reentrancy.
Add a reentrancy guard (nonReentrant()
)
Impact: - NFT already bridged won’t be bridgeable anymore without being stuck. Likelyhood: Low. - Attackers will corrupt their own tokens, deploying a risky contract interacting with an upgradable proxy. They have to buy and sell them without real benefits, except being mean. Some really specific and rare scenario can also trigger that bug.
Impact: - NFT already bridged won’t be bridgeable anymore without being stuck. Likelyhood: Low. - Attackers will corrupt their own tokens, deploying a risky contract interacting with an upgradable proxy. They have to buy and sell them without real benefits, except being mean. Some really specific and rare scenario can also trigger that bug.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.