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

构造函数缺失漏洞分析

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

一、前言
构造函数缺失漏洞自智能合约产生以来就一直出现,归根到底是由于新进开发者对 solidity 代码结构不熟悉造成的。BUGX.IO团队本次就来介绍一下漏洞的基本原理、表现形式以及对开发者的建议。
二、漏洞原理
1. 什么是构造函数
Solidity编写合约和面向对象编程语言非常相似,我们可以通过构造函数(constructor)来初始化合约对象。构造函数就是方法名和合约名字相同的函数,创建合约时会调用构造函数对状态变量进行数据初始化操作。

构造函数可用的函数类型为 public 或 internal,如果有 payable 修饰,就只能是 public 类型。而大部分人的写法都是 public 或者不写。不写类型则由函数可见性默认为 public 类型。同时,如果构造函数带参数,则一定要放在合约下的第一个函数。
pragma solidity 0.4.21;
contract Foo {
  function Foo() public {
    // ...
  }
}
合约结构的规范化写作可以让其他人更好地阅读,并且 constructor 和 fallback 函数要放在前面以便更好地查看。官方建议以如下顺序写作:
* constructor
* fallback function (if exists)
* external
* public
* internal
* private
合约结构的规范写法如下:
contract A {
    constructor() public {
        ...
    }
    function() external {
        ...
    }
    // External functions
    // ...
    // External functions that are view
    // ...
    // External functions that are pure
    // ...
    // Public functions
    // ...
    // Internal functions
    // ...
    // Private functions
    // ...
}
2. 构造函数缺失与危害
构造函数缺失则是由于构造函数与合约名字不同,而又为 public 类型,就变成了一个公有函数了,可以被任何人调用,一般函数函数比较敏感,用于初始化合约时定义通证数量、管理员地址等基本变量状态,一时变成了公有函数,危害可想而知,权限控制、通证管理基本全线奔溃。
3. 版本升级后构造函数的变化
从 `0.4.22`版本开始,solidity 编译器引入了 constructors 关键字,以替代低版本的将合约名作为构造函数名的语法,避免程序员容易出现的编码错误。使用旧写法会出现 warning 信息。
新版本写法为:
contract Ownable {
    address public owner;
    address public admin;
    constructor() public {
        owner = msg.sender;
        admin = msg.sender;
    }
    // Other code
}
三、常见漏洞代码形式
1. 构造函数使用库合约名称,使得构造函数变成了公有函数,可被任意调用。
我们发现了不少这种错误写法的合约,在主合约中,构造函数写成了 Token() 或 ERC20Token() 。这样子的函数非构造函数,变成了普通函数了。
如 DealGuard 合约:
https://etherscan.io//address/0xb47c5e8f389dc1fa8247c9a4b9e5dcdc79754152#code

2. 合约名与构造函数名不同,如大小写不同、拼写错误等,使得构造函数变成了公有函数,可被任意人调用。
只能说开发者太大意,对智能合约开发有什么误解吧。经常看到的漏洞形式是合约名与构造函数不同,只与 name 变量名相同,估计是开发者以为合约名相同就行了,却忽略了构造函数。
如 ReaperCoin11 合约:
https://etherscan.io//address/0x1b7cd071187ec0b2995b96ee82296cfa639572f1#code

还有这个 Krypticoin 合约,乍一看看不出来,仔细瞅瞅,再仔细瞅瞅,原来 coin 拼错了 。

之前知道创宇发布了关于 `owned`大小写编码漏洞的文章。同时,我们也可以找一些类似的容易大小写错误的库合约,如 `ownable`。不过经过我们的分析,还是以 owned 大小写错误为主。
如 MORPH 合约:
https://etherscan.io//address/0x2ef27bf41236bd859a95209e17a43fbd26851f92#code
contract Owned {
    address public owner;
    function owned() public {
        owner = msg.sender;
    }
3. constructor 前加了function ,或者加了 fucntion 然后开头的 C写成了大写,即 `function Constructor()public {}`,使得构造函数变成了公有函数,可被任意人调用。
版本升级后的构造函数只需要单独使用 constructor 即可,但很多开发者却忽略了此细节。上面这个写法错误在于两点:

[1] [2]  下一页

一、前言
构造函数缺失漏洞自智能合约产生以来就一直出现,归根到底是由于新进开发者对 solidity 代码结构不熟悉造成的。BUGX.IO团队本次就来介绍一下漏洞的基本原理、表现形式以及对开发者的建议。
二、漏洞原理
1. 什么是构造函数
Solidity编写合约和面向对象编程语言非常相似,我们可以通过构造函数(constructor)来初始化合约对象。构造函数就是方法名和合约名字相同的函数,创建合约时会调用构造函数对状态变量进行数据初始化操作。

构造函数可用的函数类型为 public 或 internal,如果有 payable 修饰,就只能是 public 类型。而大部分人的写法都是 public 或者不写。不写类型则由函数可见性默认为 public 类型。同时,如果构造函数带参数,则一定要放在合约下的第一个函数。
pragma solidity 0.4.21;
contract Foo {
  function Foo() public {
    // ...
  }

内容来自无奈安全网

}
合约结构的规范化写作可以让其他人更好地阅读,并且 constructor 和 fallback 函数要放在前面以便更好地查看。官方建议以如下顺序写作:
* constructor
* fallback function (if exists)
* external
* public
* internal
* private
合约结构的规范写法如下:
contract A {
    constructor() public {
        ...
    }
    function() external {
        ...
    }
    // External functions
    // ...
    // External functions that are view
    // ...
    // External functions that are pure
    // ...
    // Public functions
    // ...
    // Internal functions
    // ...
    // Private functions
    // ...
无奈人生安全网

}
2. 构造函数缺失与危害
构造函数缺失则是由于构造函数与合约名字不同,而又为 public 类型,就变成了一个公有函数了,可以被任何人调用,一般函数函数比较敏感,用于初始化合约时定义通证数量、管理员地址等基本变量状态,一时变成了公有函数,危害可想而知,权限控制、通证管理基本全线奔溃。
3. 版本升级后构造函数的变化
从 `0.4.22`版本开始,solidity 编译器引入了 constructors 关键字,以替代低版本的将合约名作为构造函数名的语法,避免程序员容易出现的编码错误。使用旧写法会出现 warning 信息。
新版本写法为:
contract Ownable {
    address public owner;
    address public admin;
    constructor() public {
        owner = msg.sender;
        admin = msg.sender;
    }
    // Other code
}
三、常见漏洞代码形式
1. 构造函数使用库合约名称,使得构造函数变成了公有函数,可被任意调用。
我们发现了不少这种错误写法的合约,在主合约中,构造函数写成了 Token() 或 ERC20Token() 。这样子的函数非构造函数,变成了普通函数了。 www.wnhack.com
如 DealGuard 合约:
https://etherscan.io//address/0xb47c5e8f389dc1fa8247c9a4b9e5dcdc79754152#code

2. 合约名与构造函数名不同,如大小写不同、拼写错误等,使得构造函数变成了公有函数,可被任意人调用。
只能说开发者太大意,对智能合约开发有什么误解吧。经常看到的漏洞形式是合约名与构造函数不同,只与 name 变量名相同,估计是开发者以为合约名相同就行了,却忽略了构造函数。
如 ReaperCoin11 合约:
https://etherscan.io//address/0x1b7cd071187ec0b2995b96ee82296cfa639572f1#code

还有这个 Krypticoin 合约,乍一看看不出来,仔细瞅瞅,再仔细瞅瞅,原来 coin 拼错了 。
www.wnhack.com

之前知道创宇发布了关于 `owned`大小写编码漏洞的文章。同时,我们也可以找一些类似的容易大小写错误的库合约,如 `ownable`。不过经过我们的分析,还是以 owned 大小写错误为主。
如 MORPH 合约:
https://etherscan.io//address/0x2ef27bf41236bd859a95209e17a43fbd26851f92#code
contract Owned {
    address public owner;
    function owned() public {
        owner = msg.sender;
    }
3. constructor 前加了function ,或者加了 fucntion 然后开头的 C写成了大写,即 `function Constructor()public {}`,使得构造函数变成了公有函数,可被任意人调用。
版本升级后的构造函数只需要单独使用 constructor 即可,但很多开发者却忽略了此细节。上面这个写法错误在于两点:
无奈人生安全网

[1] [2]  下一页 www.wnhack.com

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