合约安全之越权攻击

 

越权的关键漏洞函数是:delegatecall。这个函数在之前的重入攻击中有提到

合约安全之越权攻击_第1张图片

是属于地址类型的成员函数。他还有一种调用方式:

addr.delegatecall(bytes4(keccak256("test(string,uint)")),"test",1);
addr.delegatecall(bytes4(keccak256("test()")));

在官网中,这些底层调用函数是这么解释的

合约安全之越权攻击_第2张图片

而对delegate官网也有专门的解释

委托调用/代码调用和库
有一种特殊类型的消息调用,被称为 委托调用(delegatecall) 。它和一般的消息调用的区别在于,目标地址的代码将在发起调用的合约的上下文中执行,并且 msg.sender 和 msg.value 不变。 这意味着一个合约可以在运行时从另外一个地址动态加载代码。存储、当前地址和余额都指向发起调用的合约,只有代码是从被调用地址获取的。 这使得 Solidity 可以实现”库“能力:可复用的代码库可以放在一个合约的存储上,如用来实现复杂的数据结构的库。

相当于什么意思呢,我们使用了B合约的相关函数在A合约中执行。有点前朝的剑斩本朝的官那味道。但这是空间上的不是时间上的跨度。用如下合约做简单理解

pragma solidity ^0.4.23;
contract Calltest {
    address public b;
 
    function test() public {
        b=address(this);
    }
}
contract Compare {
    address public b;
    address public testaddress;
    constructor(address _addressOfCalltest) public {
        testaddress = _addressOfCalltest;
    }
    function withcall() public {
        testaddress.call(bytes4(keccak256("test()")));
    }
    function withdelegatecall() public {
        testaddress.delegatecall(bytes4(keccak256("test()")));
    }
}
  1. 部署Calltest,再部署Compare构造函数中输入Calltest的addr
  2. 查看两个合约的b

合约安全之越权攻击_第3张图片

因为初始化了都是0

  1. 现在调用withcall函数再查看两个合约的b

火柴截图20200808220813826.jpg

发现calltest合约的b变了,而compare合约的b没有变。

  1. 现在调用withdelegatecall在查看两个合约的b

合约安全之越权攻击_第4张图片

发现compare合约的b也变了,说明delegatecall是通过了calltest合约的函数而更改了本合约的b变量。而call是直接改了calltest合约的b变量,并且当且合约地址也就是calltest的地址。


CTF‘实战题’

pragma solidity ^0.4.10;

contract Delegate {
    address public owner;

    function Delegate(address _owner) {
        owner = _owner;
    }
    function pwn() {
        owner = msg.sender;
    }
}

contract Delegation {
    address public owner;
    Delegate delegate;

    function Delegation(address _delegateAddress) {
        delegate = Delegate(_delegateAddress);
        owner = msg.sender;
    }
    function () {
        if (delegate.delegatecall(msg.data)) {
            this;
        }
    }
}

看着这个合约,不看题干,盲猜是要改delegation合约的owner变量为自己。一般来说合约部署了之后没有更改owner的函数,就不能进行操作了。但是delegation合约中的匿名函数中有delegatecall,并且pwn中就有owner = msg.sender这种...

给fallback函数传入pwn函数就行了。 先测试看希pwn函数的sha3的前四个字节。

合约安全之越权攻击_第5张图片 0xdd365b8b

  1. 部署完成后查看两个合约的owner

合约安全之越权攻击_第6张图片

都是一样的

  1. 现在通过上面的payload把已经部署了的delegetion的owner更改一下。

合约安全之越权攻击_第7张图片

这个时候已经改成功了。


简单分析下parity钱包的漏洞合约

合约安全之越权攻击_第8张图片

在合约的 429行,当转入value = 0 并且 msg.lenght > 0 的时候就会执行上面说的delegatecall函数。像这个ctf题目一样msg.data时可控的。这样就能调用到当前合约下的所有函数。

最终调用到initMultiowned函数,将合约的owner设置为自己

合约安全之越权攻击_第9张图片

然后使用execute函数和自己的合约所有者身份把钱转走了!

合约安全之越权攻击_第10张图片


心愿世界和平~

✔https://cnmf.net.cn/

✔https://blog.csdn.net/xiaoyue2019

参考:https://github.com/openethereum/openethereum/blob/4d08e7b0aec46443bf26547b17d10cb302672835/js/src/contracts/snippets/enhanced-wallet.sol https://blog.csdn.net/fly_hps/article/details/81218219

你可能感兴趣的:(以太合约安全系列)