The GivingThanks
contract uses the low-level call
method to transfer Ether to the charity in the donate
function. The call
method is risky because it allows the called contract to execute arbitrary code, and if the receiving contract is malicious, it can exploit this to perform unintended actions (such as reentrancy or manipulating contract state).
The vulnerability is located in the donate
function, specifically on Line 16 where the contract transfers Ether to the charity using call
:
The line of code above uses the low-level call
method to transfer Ether. The call
method, while flexible, has inherent security risks.
call
:Arbitrary Code Execution: When using call
, the target address can execute any code it wants, including calling back into the donating contract. This could potentially trigger unintended behavior in the contract (such as reentrancy attacks or other malicious actions).
No Return Value Handling: The result of the call
method is not properly checked. Although the result is checked (require(sent, "Failed to send Ether")
), it's possible for the transfer to fail silently if the charity contract is not properly designed to handle call
or if it reverts unexpectedly.
Risk of Reentrancy: If the charity address is a contract, and it has fallback or receive functions that call back into the GivingThanks
contract, it could exploit the vulnerability to execute arbitrary logic, including re-entering the contract’s functions.
If an attacker deploys a malicious charity contract, they could use the fallback function to exploit the call
method in the following way:
The attacker donates Ether to the contract, triggering the donate
function.
The call
method sends Ether to the malicious charity contract.
The malicious contract’s fallback function could call the donate
function again before the state changes occur (reentrancy), potentially draining the contract or minting more NFTs than intended.
This attack can be repeated, enabling the attacker to manipulate the contract and steal funds.
Funds Drain: The attacker could exploit the vulnerability to drain the contract’s balance via reentrancy.
NFT Abuse: If combined with a reentrancy vulnerability (as previously mentioned), the attacker could mint multiple NFTs for a single donation.
Unintended Logic Execution: The attacker could execute arbitrary code, affecting the contract’s state or behavior unexpectedly.
The use of the call
method without proper safeguards (like a reentrancy guard or checks-effects-interactions pattern) exposes the contract to the risk of reentrancy and other malicious contract interactions.
Financial Loss: The contract’s Ether balance can be drained.
NFT Minting Exploitation: Attackers could mint multiple NFTs for a single donation.
Potential for Arbitrary Code Execution: If the charity contract is malicious, it could interfere with the contract's logic.
Slither: Static analysis tool to identify risky code patterns and detect potential vulnerabilities in smart contracts.
MyEtherWallet: Used for interacting with the smart contract to test and simulate transactions.
Foundry: Used to simulate and test exploit scenarios involving malicious contracts.
MyCrypto: Utilized to further test interaction with the call
function and simulate transactions involving charity contracts.
To mitigate this issue, consider the following actions:
call
for Ether TransfersInstead of using the low-level call
, consider using safer methods to transfer Ether:
transfer
: The transfer
function automatically limits the gas forwarded to the recipient to 2300 gas, preventing reentrancy.
Example fix:
However, transfer
is not ideal when sending large amounts of Ether, as it limits the gas available. Therefore, call
may still be used, but with proper precautions.
Implement a reentrancy guard in the contract to prevent reentrant calls when transferring Ether. The ReentrancyGuard
contract from OpenZeppelin provides a simple way to protect functions from reentrancy attacks.
Example fix:
Always apply the Checks-Effects-Interactions pattern:
Check: Verify the validity of inputs and conditions.
Effect: Update the contract’s state.
Interaction: Only interact with external contracts after the state is updated.
This pattern reduces the risk of reentrancy attacks and ensures that the contract's state is always consistent before interacting with external contracts.
Instead of using call
, use the transfer
function to ensure that failure is explicitly handled, and it won’t result in unintended behaviors. If you continue to use call
, you should ensure that the charity contract is trusted and does not perform arbitrary actions upon receiving Ether.
call
Method UsageThe vulnerability allows attackers to interact with malicious charity contracts that can execute arbitrary code upon receiving Ether, enabling exploits such as reentrancy or draining funds.
Attacker: The attacker deploys a malicious charity contract to exploit the call
method in the donate
function.
Victim: The victim is the GivingThanks
contract and donors who interact with it.
Protocol: The GivingThanks
contract.
Malicious Charity Contract:
Exploit the Insecure call
:
The attacker donates Ether to the contract, triggering the insecure call
function. The malicious contract’s fallback function re-enters the donate
function, exploiting the vulnerability.
The insecure usage of the call
method in the GivingThanks
contract exposes it to potential exploits such as reentrancy attacks and arbitrary code execution. To mitigate this, safer methods like transfer
, reentrancy guards, and the Checks-Effects-Interactions pattern should be adopted. The vulnerability is high-risk, as it involves transferring funds to external contracts that can execute arbitrary code.
Charity contracts are validated by the admin, it is safe at this step since admin is trusted.
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.