Skip to content

Simple test to try and understand the DelegateCall and its vulnerability

Notifications You must be signed in to change notification settings

falconandrea/example-delegatecall-vulnerability

Repository files navigation

trackgit-views

Example of Solidity Delegatecall function and its Vulnerability

This repository provides an example of how delegatecall works in Solidity and demonstrates how it can be used to modify a storage slot in a contract.

Introduction

Delegatecall is a low-level function in Solidity that allows a contract to delegate the execution of a function to another contract while preserving the storage and context of the calling contract. This powerful feature enables contract composition and code reuse, but it also introduces potential security risks if not used carefully.

How Delegatecall Works

When using delegatecall, the code of the target contract is executed within the context of the calling contract. This means that the target contract can access and modify the storage variables of the calling contract. It can also execute its own logic using the storage and state of the calling contract.

Delegatecall takes the form:

(bool success, bytes memory result) = address(targetContract).delegatecall(abi.encodeWithSignature("functionName(uint256)", _paramName));

Where:

  • targetContract: The address of the contract to which the execution is delegated.
  • functionName: The name of the function to be called in the target contract (with the param type).
  • _paramName: The parameter to be passed to the function in the target contract.

Make sure to replace targetContract, functionName, and _paramName with the appropriate values for your specific use case.

The delegatecall function will execute the specified function in the target contract while preserving the storage and context of the calling contract. It returns a boolean value success indicating whether the delegatecall was successful, and result contains any data returned by the target contract's function.

Exploiting Delegatecall to Modify Storage Slot

One potential vulnerability with delegatecall is the ability to modify a storage slot in the calling contract. If the target contract is designed to modify a specific storage slot and the delegatecall is used without proper checks, an attacker can craft malicious function call data to modify that storage slot in an unintended way.

To mitigate this vulnerability, it's essential to implement appropriate checks and validate the function call data before executing delegatecall. Always validate the caller's authority and ensure that the provided data is safe and valid.

Contracts

  • Good.sol: This contract demonstrates the usage of delegatecall to invoke a function in another contract and modify a storage slot.
  • Helper.sol: This contract is the target of the delegatecall and contains the logic to modify a specific storage slot.
  • Attack.sol: This contract is the attacker that will take the address of a Good contract in the constructor. He will then call the attack function which will further initially call the setNum function present inside Good.sol.
  • Secure.sol: This contract is the Good.sol edited with the vulnerability fixed.

Vulnerability in Good.sol Contract

The vulnerability lies in the assumption made about the storage slot layout between Good.sol and Helper.sol. In Good.sol, slot 0 is expected to hold the address of the Helper contract, but in Helper.sol, the setNum function modifies slot 0 directly. This inconsistency leads to overwriting unintended data.

Specifically, in Good.sol, the setNum function delegates the execution to Helper.setNum, assuming that Helper.setNum will only modify the num variable. However, in Helper.sol, the setNum function directly modifies slot 0, which, in the context of Good.sol, holds the address of the Helper contract.

As a result, calling setNum in Good.sol using delegatecall inadvertently modifies slot 0 in the storage, overwriting the address of the Helper contract with a new value, potentially causing unexpected behavior and compromising the intended functionality of the contracts.

Usage

To run the example and test the delegatecall functionality:

  1. Install the required dependencies with npm install.
  2. Run the tests using npm test. This will execute the test cases in the tests/ directory.

Security Considerations

  • Always validate and sanitize input data before using delegatecall.
  • Be cautious when delegating execution to external contracts, as they may have unintended side effects or malicious code.
  • Ensure that only authorized contracts or addresses can perform delegatecall to avoid unauthorized modifications.
  • Use stateless library contracts which means that the contracts to which you delegate the call should only be used for execution of logic and should not maintain state. This way, it is not possible for functions in the library to modify the state of the calling contract.

Disclaimer

This repository is for educational purposes only. The code provided should not be used in production environments without thorough security audits. Use at your own risk.

About

Simple test to try and understand the DelegateCall and its vulnerability

Topics

Resources

Stars

Watchers

Forks