智能合约之其他类型攻击

本篇将为大家介绍一下以太坊智能合约的 拒绝服务、可预测随机数、不安全函数返回值、构造函数拼写错误等引起的漏洞,接下来依据漏洞的类型分别为大家做介绍。

1. 拒绝服务攻击
拒绝服务顾名思义就是通过制造错误返回来拒绝为其他人提供服务,那么在以太坊的智能合约是怎么做到的呢?下面先来看一份智能合约代码:

pragma solidity ^0.4.10;

contract PresidentOfCountry {
    address public president;
    uint256 price;

    function PresidentOfCountry(uint256 _price) {
        require(_price > 0);
        price = _price;
        president = msg.sender;
    }

    function becomePresident() payable {
        require(msg.value >= price); 
        president.transfer(price);  
        president = msg.sender;     
        price = price * 2;        
    }
}

上述智能合约的代码逻辑很简单,就是谁的出价高,谁就会成为新的president ,并将智能合约目前拥有的price以太币通过transfer()函数返回给前任的president的地址。
这份合约看起来貌似没有什么问题,但仔细思考,以太坊的账户有合约账户和普通账户。如果普通用户调用这份合约没有什么问题,如果是恶意攻击的合约账户呢?
我们都知道,合约账户的以太币转账都是通过 fallback() 函数进行的,如果攻击者在 fallback()代码中恶意进行了类似 revert() 这样主动跑出错误的操作,那么其他账户也就无法再正常通过 becomePresident()函数逻辑成为 president 。下面给出恶意攻击的合约代码:

pragma solidity ^0.4.10;

contract Attack {
    function () { revert(); }
    
    function Attack(address _target) payable {
        _target.call.value(msg.value)(bytes4(keccak256("becomePresident()")));
    }
}

2. 可预测随机数攻击
可预测随机数顾名思义就是随机数是可以预测的即为伪随机数。伪随机问题一直都存在于现代计算机系统中,但是在开放的区块链中,像在以太坊智能合约中编写的基于随机数的处理逻辑感觉就有点不切实际了,由于人人都能访问链上数据,合约中的存储数据都能在链上查询分析得到。如果合约代码没有严格考虑到链上数据公开的问题去使用随机数,可能会被攻击者恶意利用来进行 “作弊”。下面介绍一段示例代码:

uint256 private seed;
    
function play() public payable {
	require(msg.value >= 1 ether);
	iteration++;
	uint randomNumber = uint(keccak256(seed + iteration));
	if (randomNumber % 2 == 0) {
		msg.sender.transfer(this.balance);
	}
}

在上述代码中 seed 变量被标记为了私有变量,前面有说过链上的数据都是公开的,seed 的值可以通过扫描与该合约相关的 TX 来获得。获取 seed 值后,同样的 iteration 值也是可以得到的,那么整个 uint(keccak256(seed + iteration)) 的值就是可预测了。攻击者可以利用可以预见的随机数在逻辑上做对应的攻击来获取利益。

3. 不安全函数返回值攻击
由于合约代码调用底层的函数,但没有对返回值进行判断,函数执行错误后续的代码还继续执行,从而形成漏洞。下面来介绍一下常用的底层函数及其用法:
call()函数:call() 用于 Solidity 进行外部调用,例如调用外部合约函数 address.call(bytes4(keccak(“somefunc(params)”), params)),外部调用 call() 返回一个 bool 值来表明外部调用成功与否。

delegatecall():除了 delegatecall() 会将外部代码作直接作用于合约上下文以外,其他与 call() 一致,同样也是只能获取一个 bool 值来表示调用成功或者失败(发生异常)。

callcode()函数:callcode() 其实是 delegatecall() 之前的一个版本,两者都是将外部代码加载到当前上下文中进行执行,但是在 msg.sender 和 msg.value 的指向上却有差异。

call.value()()函数:在合约中直接发起 TX 的函数之一。

send()函数:通过 send() 函数发送 Ether 失败时直接返回 false;这里需要注意的一点就是,send() 的目标如果是合约账户,则会尝试调用它的 fallbcak() 函数,fallback() 函数中执行失败,send() 同样也只会返回 false。但由于只会提供 2300 Gas 给 fallback() 函数,所以可以防重入漏洞(恶意递归调用)。

transfer()函数:transfer() 也可以发起 Ether 交易,但与 send() 不同的时,transfer() 是一个较为安全的转币操作,当发送失败时会自动回滚状态,该函数调用没有返回值。同样的,如果 transfer() 的目标是合约账户,也会调用合约的 fallback() 函数,并且只会传递 2300 Gas 用于 fallback() 函数执行,可以防止重入漏洞(恶意递归调用)。

下面来给出一个示例代码来说明未判断函数的返回值操作的漏洞:

function _send(uint256 _amount) public {
	require(balances[msg.sender] >= _amount);
	balances[msg.sender] -= _amount;
	etherLeft -= _amount;
	msg.sender.send(_amount);  // 未验证 send() 返回值,若 msg.sender 为合约账户 fallback() 调用失败,则 send() 返回 false
}

4. 构造函数拼写错误攻击
构造函数拼写错误顾名思义就是智能合约的构造函数在拼写时,函数名拼写错误。大家都知道,一个智能合约只能拥有一个构造函数,在部署智能合约的时候执行一次,之后不再执行。在某些时候,由于开发人员的疏忽,将智能合约的构造函数拼写错误造成灾难性的后果,下面给出一段示例代码:

pragma solidity ^0.4.16;

//基类合约
contract Ownable {
    address public owner;

    function ownable() public {  
        owner = msg.sender;
        //构造函数,对owner进行赋值,部署合约的发起方
    }
	
	...

上述代码中,由于构造函数 function ownable() public的拼写错误(第一次字母应该是大写O),本来应该是构造函数变成一个对外可调用的普通函数,任何一个账户都可以调用这段代码,将自己的账户地址设置为owner。

在后续的Soildity-Remix代码编辑器,针对智能合约的构造函数增加了 construct 关键字进行修饰,具体使用请大家自行查阅资料。

智能合约漏洞是指在智能合约的设计者实现中存在的安全问题,可能导致恶意用户利用漏洞攻击智能合约,从而获得非法利益。常见的智能合约漏洞类型包括以下几种: 1. 逻辑漏洞:指智能合约的设计者实现存在缺陷,导致恶意用户可以绕过正常的业务逻辑,从而获取非法的利益。例如,DAO攻击就是一种逻辑漏洞,攻击者利用了智能合约中的代码缺陷,从而取得了大量数字货币。 2. 重入攻击:指恶意用户在智能合约执行过程中,利用合约中的漏洞,多次进入合约,从而实施攻击。例如,以太坊的DAO事件中,攻击者利用了重入攻击,从而取得了大量数字货币。 3. 溢出漏洞:指智能合约在处理数字货币时,由于没有进行正确的溢出检查,导致攻击者可以通过输入超出合约处理能力的数字货币,从而获取非法利益。例如,以太坊智能合约Parity Multisig就曾因为溢出漏洞而被攻击。 4. 合约隐私泄露:指智能合约在设计者实现中,存在泄露用户隐私的漏洞,从而导致用户的隐私信息泄漏。例如,以太坊的智能合约Etherscan就曾因为泄露用户隐私而引起争议。 5. 代码漏洞:指智能合约中的代码存在缺陷,导致攻击者可以通过输入恶意代码来攻击合约,从而获取非法利益。例如,以太坊智能合约DAO就曾因为代码漏洞而遭受攻击。 总的来说,智能合约漏洞对数字货币的安全和用户隐私都会造成严重的威胁,因此在设计和实现智能合约时,必须非常谨慎,并且进行充分的测试和审计,以确保合约的安全性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值