合约安全之越权攻击

 

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

火柴截图20200808212922556.jpg

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

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

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

火柴截图20200808213706027.jpg

而对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

火柴截图20200808220646965.jpg

因为初始化了都是0

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

火柴截图20200808220813826.jpg

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

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

火柴截图20200808220954315.jpg

发现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的前四个字节。

火柴截图20200808222443234.jpg 0xdd365b8b

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

火柴截图20200808222726067.jpg

都是一样的

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

火柴截图20200808222840294.jpg

这个时候已经改成功了。


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

火柴截图20200808223218502.jpg

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

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

火柴截图20200808223642839.jpg

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

火柴截图20200808223822916.jpg


心愿世界和平~

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值