智能合约漏洞(二):访问控制缺陷漏洞与跨合约调用漏洞

【本篇内容仅用作学习 科研所需 禁止用作任何违法行为 学安全为安全】

作为区块链方向的学生 最近在学合约审计 总结一下

访问控制缺陷漏洞:

漏洞简介:
即某些对权限有要求的方法的修饰符逻辑错误造成合约中的某些私有函数可以被非法调用

常出现的地方:

在function修饰符modifier上 或者访问权限 private public internal external 调用方法:call delegatecall中

防范方法:
1.在编写合约的时候 务必检查好函数调用权限 调用逻辑一定要清晰 否则一旦部署到区块链上 则不可更改 容易造成经济损失
2.避免disable enable在合约逻辑中存在
3.敏感变量必须通过函数修饰符进行权限控制 对可以操纵合约内部敏感变量的函数 应该用assert if-else等进行权限限制

漏洞举例:

 IcxToken 合约中的	
    modifier onlyFromWallet {
   
    require(msg.sender != walletAddress);
    _;
}	


function disableTokenTransfer()
external
onlyFromWallet {
   
    tokenTransfer = false;
    TokenTransfer();
}

function IcxToken( uint initial_balance, address wallet) {
   
    require(wallet != 0);
    require(initial_balance != 0);
    _balances[msg.sender] = initial_balance;
    _supply = initial_balance;
    walletAddress = wallet;
    }

在 disableTokenTransfer方法中 关闭合约交易权限应该只能由wallet执行
否则 如果被恶意调用disableTokenTransfer函数 那么该合约中被isTokenTransfer修饰的函数均不可正常使用
即这里的msg.sender != walletAddress 应该为 msg.sender == walletAddress

利用方法:
只要调用disableTokenTransfer的地址不是walletaddress即可
在remix实验时,可以直接点击函数进行调用

智能合约

跨合约调用漏洞:

漏洞简介:
由call系列函数引起的外部合约注入,即外部合约A调用B合约中的私有 || 具有权限限制的函数

原理解释:
solidity中 合约相互调用有两种:
对象: 合约地址当作合约对象适用 然后调用
用call() delegatecall() callcode()

方法解释:
call函数与delegatecall函数:
比如:
B中的function名字为 Bfunc
如果 A合约中以call方式调用B合约的Bfunc 那么Bfunc会在B合约上下文中执行 结果返回给A合约
如果用delegatecall调用Bfunc 那么会将Bfunc方法以“复制粘贴”的方式放在A合约中(A中需要包含Bfunc所需函数与变量),然后在A合约中调用

安全漏洞主要是由call()方法调用引起的:
call():
调用方法:
address.call(function_name, args[])
|| address.call(bytes)

防范方法:
出现这类漏洞的根本在于滥用call系列方法,防范自然是减少此类方法使用 比如交易可以用transfer()实现

实例:
漏洞代码:

	contract sample{
   
	
	function a(byte data) {
   
	this.call(data)
}
	function secret public{
   
	require(this == msg.sender)
	//code
}
}

在这个合约中 secret函数要求调用方必须为合约自己
如果在函数a中 合约byte码指向的合约构造了一个调用:调用secret函数 那么根据call函数机制 会将此代码“粘贴”到secret函数中
那么通过a函数 就可以调用secret函数 达到注入攻击目的

关于callcode的漏洞:
EVM中,对callcode方法:传参时,不会验证参数的个数,只要找到了需要的参数,其他参数就会忽略 不会产生影响

漏洞地址:https://etherscan.io/address/0x461733c17b0755ca5649b6db08b3e213fcf22546#code

漏洞处代码:

function transferFrom(address _from, address _to, uint256 _amount, bytes _data, string _custom_fallback)
    public
    returns (bool success)
{
   
    // Alerts the token controller of the transfer
    if (isContract(controller)) {
   
        if (!TokenController(controller).onTransfer(_from, _to, _amount))
           throw;
    }

    require(super.transferFrom(_from, _to, _amount));

    if (isContract(_to)) {
   
        ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
        receiver.call.value(0)(bytes4(keccak256(_custom_fallback)), _from, _amount, _data);
    }

    ERC223Transfer(_from, _to, _amount, _data);

    return true;
}

代码解释:
漏洞核心部分为

receiver.call.value(0)(bytes4(keccak256(_custom_fallback)), _from, _amount, _data);

在这里 如果目标地址为合约 就调用_custom_fallback 回退函数 并且依次填入from amount data

漏洞利用:
如果将_to的地址写为该合约本身,那么就可以实现以owner身份,即该合约自身的权限调用该合约,那么就可以调用合约中的setOwner方法,那么就可以将任意address设置为owner,进而进行其他非法操作。

P.S.
跨合约调用漏洞代码:


```typescript

```typescript
/**
 *Submitted for verification at Etherscan.io on 2017-11-17
*/

pragma solidity ^0.4.13;

contract DSAuthority {
   
    function canCall(
        address src, address dst, bytes4 sig
    ) public view returns (bool);
}

contract DSAuthEvents {
   
    event LogSetAuthority (address indexed authority);
    event LogSetOwner     (address indexed owner);
}

contract DSAuth is DSAuthEvents {
   
    DSAuthority  public  authority;
    address      public  owner;

    function DSAuth() public {
   
        owner = msg.sender;
        LogSetOwner(msg.sender);
    }

    function setOwner(address owner_)
        public
        auth
    {
   
        owner = owner_;
        LogSetOwner(owner);
    }

    function setAuthority(DSAuthority authority_)
        public
        auth
    {
   
        authority = authority_;
        LogSetAuthority(authority);
    }

    modifier auth {
   
        require(isAuthorized(msg.sender, msg.sig));
        _;
    }

    function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
   
        if (src == address(this)) {
   
            return true;
        } else if (src == owner) {
   
            return true;
        } else if (authority == DSAuthority(0)) {
   
            return false;
        } else {
   
            return authority.canCall(src, this, sig);
        }
    }
}

contract DSNote {
   
    event LogNote(
        bytes4   indexed  sig,
        address  indexed  guy,
        bytes32  indexed  foo,
        bytes32  indexed  bar,
        uint              wad,
        bytes             fax
    ) anonymous;

    modifier note {
   
        bytes32 foo;
        bytes32 bar;

        assembly {
   
            foo := calldataload(4)
            bar := calldataload(36)
        }

        LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);

        _;
    }
}

contract DSStop is DSNote, DSAuth {
   

    bool public stopped;

    modifier stoppable {
   
        require(!stopped);
     
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
智能合约是由代码编写的自动执行合约,通常在区块链技术中使用。与传统的合约不同,智能合约可以自动执行、验证和执行合约条款,无需第三方干预。然而,由于智能合约是由代码编写的,因此它们可能存在一些安全漏洞,这些漏洞可能会导致合约执行不当或被黑客攻击。 以下是一些常见的智能合约安全漏洞: 1. 重入攻击:重入攻击是一种攻击,攻击者利用合约中的漏洞,使其可以重复执行一个函数,从而实现对合约的攻击。攻击者可以在合约执行期间多次调用函数,从而获取更多的资产。 2. 溢出错误:当智能合约处理某些数值时,如果没有正确的检查,可能会发生溢出错误。攻击者可以利用这种漏洞来篡改合约的状态或窃取资产。 3. 未授权的访问:如果智能合约中的某些函数未正确实现访问控制,攻击者可能会访问他们不应该访问的功能。这可能会导致资产丢失或合约被篡改。 4. 错误的随机数生成:在智能合约中,随机数很重要,因为它们可以用来确保合约的安全性。如果随机数生成不正确,攻击者可能会利用这种弱点来攻击合约。 5. 不正确的代码:当智能合约中的代码有错误时,可能会引发安全漏洞。攻击者可能会利用这些漏洞来对合约进行攻击或篡改。 这些是智能合约中常见的安全漏洞,因此在编写智能合约时,必须严格遵循安全最佳实践,以确保合约的安全性。同时,定期进行安全审核和测试也是非常重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值