The withdraw_shares() function in Cyfrin_Hub.vy violates the Checks-Effects-Interactions pattern, making it vulnerable to a reentrancy attack.
The function first calculates the payout amount and performs the external ETH transfer (raw_call) to the investor. Crucially, the investor's shares and the global issued_shares are only updated after the external transfer.
A malicious investor can deploy a contract that re-enters withdraw_shares() during the external transfer, allowing them to withdraw their shares multiple times before the state is updated. This allows the attacker to drain the company's entire ETH balance.
Note: The @nonreentrancy pragma is not supported in Vyper 0.4.3, making the function completely unprotected.
Likelihood: High
The vulnerability is easily exploitable by any investor who deploys a simple malicious contract. The attack path is straightforward and requires no special timing or prerequisites. The exploit was confirmed with a Proof of Concept.
Impact: High
The attacker can drain the entire company_balance of the Cyfrin_Hub contract, leading to a complete loss of funds for all other investors and the company itself. This results in a severe financial loss and protocol failure.
The exploit was confirmed using a custom Vyper contract ReentrancyPoC.vy that re-enters the withdraw_shares function during the external call.
Setup:
The Cyfrin_Hub is deployed and funded with 100 ETH.
A malicious investor (Attacker) invests 1 ETH and receives 1000 shares.
Attack:
The Attacker calls withdraw_shares() from their malicious contract.
Inside the malicious contract's fallback function, the Attacker immediately calls withdraw_shares() again.
Result:
The Attacker's shares are only updated to 0 after the first call completes.
The second call executes successfully, calculating the payout based on the original share balance, resulting in a double withdrawal.
By looping this, the Attacker can drain the entire 100 ETH balance.
Supporting Code:
The state updates must occur before the external call to the investor.
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.