欢迎来到 无奈人生 安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

智能合约安全性问题CheckList

来源: 作者: 时间:2019-02-24 19:29 点击: 我要投稿
广告位API接口通信错误,查看德得广告获取帮助

根据腾讯腾讯安全2018上半年区块链安全报告,智能合约引发的安全问题以成为区块链自身机制安全性的主要问题,本文就目前文献中提到的主流安全性问题做出总结,并列出目前的相关研究。
整形溢出(Arithmetic Issues)
如下代码,如果没有assert判断,那么sellerBalance+value可能会超出uint上限制导致溢出。
pragma solidity ^0.4.15;
contract Overflow {
    uint private sellerBalance=0;
    function add(uint value) returns (bool, uint){
        sellerBalance += value; // complicated math with possible overflow
        // possible auditor assert
        assert(sellerBalance >= value);
    }
}
危险的delegatecall(dangerous delegatecall)[contractfuzzer]
首先需要了解call和delegatecall的区别:call和delegatecall都为合约相互调用时的函数,假设A调用B函数,call方法结果展示到B中,delegatecall方法结果展示到A中。
在如下示例中,Mark如果用delegatecall调用了恶意合约Steal,那么Mark合约会被删除。
复现:
1.用A账户部署Steal,用B账户部署Mark合约,并在部署时为合约附加10个ether。
2.账户B调用Mark.call(address(Steal)),即用B调用Steal的Innocence方法,实际上innocence会在Mark的上下文环境运行,发现账户B收到合约的10 ether(注意不是A账户)
3.用C账户执行Mark.deposit()方法,并附加10ether,再调用destruct方法,发现B无法收到10ether,说明合约确实已经在第二步被销毁。
pragma solidity ^0.4.2;
contract Steal{
    address owner;
    constructor () payable {
        owner = msg.sender;
    }
    function innocence() {
        log0("123");
        selfdestruct(owner);
    }
}
contract Mark {
    address owner;
    constructor () payable {
        owner = msg.sender;
    }
    function Deposit() payable {}
    function call(address a) {
        a.delegatecall(bytes4(keccak256("innocence()")));
    }
}
无Gas发送(Gasless Send)[contractfuzzer]
合约C调用合约D1时,由于fallback函数修改了storage变量——这是一个消耗大量gas的操作——导致了超过fallback的gas上限(2300gas)导致fallback失败,调用D2时,由于没有超过上限,调用成功。
复现:
1.用10ether部署C合约,0ether部署D1合约,0ether部署D2合约
2.调用C.pay(1000000000000000000, address(D1)),D1的count值仍为0
3.调用D1.kill(),以太币不增加。2,3两步说明了D1的fallback调用失败
4.调用C.pay(1000000000000000000,address(D2))
5.调用D2.kill(),发现账户增加1ether,说明D2的fallback调用成功
pragma solidity ^0.4.2;
contract C {
    address owner;
    constructor () payable{
        owner=msg.sender;
    }
    function pay(uint n, address d){
        d.send(n);
    }
    function kill() {
       if (owner == msg.sender) {
          selfdestruct(owner);
       }
    }
}
contract D1 {
    address owner;
    uint public count = 0;
    constructor () payable{
        owner=msg.sender;
    }
    function() payable {
        count = count+1;
    }
    function kill() {
       if (owner == msg.sender) {
          selfdestruct(owner);
       }
    }
}
contract D2  {
    address owner;
    constructor () payable{
        owner=msg.sender;
    }
    function() payable {}
    function kill() {
       if (owner == msg.sender) {
          selfdestruct(owner);
       }
    }
}
依赖于交易顺序/条件竞争(TOD/Front Running)[smarter]
由于:
1.只有当交易被打包进区块时,他才是不可更改的
2.区块会优先打包gasprice更高的交易
所以攻击者可以恶意操控交易顺序从而使合约对自己有利。如图,出题人和做题人同时发起合约,那么做题人得到的奖励因合约执行顺序不同而不同。

[1] [2] [3] [4]  下一页

根据腾讯腾讯安全2018上半年区块链安全报告,智能合约引发的安全问题以成为区块链自身机制安全性的主要问题,本文就目前文献中提到的主流安全性问题做出总结,并列出目前的相关研究。
整形溢出(Arithmetic Issues)
如下代码,如果没有assert判断,那么sellerBalance+value可能会超出uint上限制导致溢出。
pragma solidity ^0.4.15;
contract Overflow {
    uint private sellerBalance=0;
    function add(uint value) returns (bool, uint){
        sellerBalance += value; // complicated math with possible overflow
        // possible auditor assert
        assert(sellerBalance >= value);
    }
}
危险的delegatecall(dangerous delegatecall)[contractfuzzer]
首先需要了解call和delegatecall的区别:call和delegatecall都为合约相互调用时的函数,假设A调用B函数,call方法结果展示到B中,delegatecall方法结果展示到A中。

本文来自无奈人生安全网

在如下示例中,Mark如果用delegatecall调用了恶意合约Steal,那么Mark合约会被删除。
复现:
1.用A账户部署Steal,用B账户部署Mark合约,并在部署时为合约附加10个ether。
2.账户B调用Mark.call(address(Steal)),即用B调用Steal的Innocence方法,实际上innocence会在Mark的上下文环境运行,发现账户B收到合约的10 ether(注意不是A账户)
3.用C账户执行Mark.deposit()方法,并附加10ether,再调用destruct方法,发现B无法收到10ether,说明合约确实已经在第二步被销毁。
pragma solidity ^0.4.2;
contract Steal{
    address owner;
    constructor () payable {
        owner = msg.sender;
    }
    function innocence() {
        log0("123");
        selfdestruct(owner);
    }
}
contract Mark {
    address owner;
    constructor () payable {
        owner = msg.sender;

copyright 无奈人生


    }
    function Deposit() payable {}
    function call(address a) {
        a.delegatecall(bytes4(keccak256("innocence()")));
    }
}
无Gas发送(Gasless Send)[contractfuzzer]
合约C调用合约D1时,由于fallback函数修改了storage变量——这是一个消耗大量gas的操作——导致了超过fallback的gas上限(2300gas)导致fallback失败,调用D2时,由于没有超过上限,调用成功。
复现:
1.用10ether部署C合约,0ether部署D1合约,0ether部署D2合约
2.调用C.pay(1000000000000000000, address(D1)),D1的count值仍为0
3.调用D1.kill(),以太币不增加。2,3两步说明了D1的fallback调用失败
4.调用C.pay(1000000000000000000,address(D2))
5.调用D2.kill(),发现账户增加1ether,说明D2的fallback调用成功
pragma solidity ^0.4.2;
contract C {
    address owner;
    constructor () payable{
        owner=msg.sender;
无奈人生安全网

    }
    function pay(uint n, address d){
        d.send(n);
    }
    function kill() {
       if (owner == msg.sender) {
          selfdestruct(owner);
       }
    }
}
contract D1 {
    address owner;
    uint public count = 0;
    constructor () payable{
        owner=msg.sender;
    }
    function() payable {
        count = count+1;
    }
    function kill() {
       if (owner == msg.sender) {
          selfdestruct(owner);
       } copyright 无奈人生
    }
}
contract D2  {
    address owner;
    constructor () payable{
        owner=msg.sender;
    }
    function() payable {}
    function kill() {
       if (owner == msg.sender) {
          selfdestruct(owner);
       }
    }
}
依赖于交易顺序/条件竞争(TOD/Front Running)[smarter]
由于:
1.只有当交易被打包进区块时,他才是不可更改的
2.区块会优先打包gasprice更高的交易
所以攻击者可以恶意操控交易顺序从而使合约对自己有利。如图,出题人和做题人同时发起合约,那么做题人得到的奖励因合约执行顺序不同而不同。
copyright 无奈人生

[1] [2] [3] [4]  下一页

无奈人生安全网

。 (责任编辑:admin)
【声明】:无奈人生安全网(http://www.wnhack.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱472701013@qq.com,我们会在最短的时间内进行处理。