solidity 合约权限授权_智能合约:整数溢出、访问控制缺陷漏洞与跨合约调用漏洞...

整数溢出:

漏洞简介:
简单来说,就是Solidity整形变量被赋值高于或者低于可以表示的范围时 值会发生改变 一般会溢出为2的uint类型次方 -1 或者 0:
**上溢:会溢出为0
下溢:会溢为2*n-1 如果是uint256 即为:2的256次方 -1

漏洞通常出现地方:
1.条件检测的地方容易出现
2.任何计算的地方都可能出现

规避方法:
1.在solidity中运算之前 必须对输入和输出进行有效性认证
在进行任何计算之前,务必对操作数进行可能溢出与否的预判,或者用safemath库来编写计算逻辑,否则就可能会出现溢出问题;

实际案例:
Beauty Chain中出现的整数溢出漏洞:
eth address: 0xC5d105E63711398aF9bbff092d4B6769C82F793D
源码搜索此地址:
https://etherscan.io/address/0xC5d105E63711398aF9bbff092d4B6769C82F793D#code

整数溢出部分代码:
function batchTransfer(address[] _reveivers,uint256 _value) public whenNotPaused returns(bool) {

//在这里只讨论存在溢出的部分的代码 其余部分省略 有兴趣可以在上述网址查看源码进行审计

uint cnt = _reveivers.length;
uint256 amount = uint256(cnt) * _value;
require(cnt >0 && cnt <= 20);
requitre(_value >0 && balances[msg.sender]>=amount);
(接下来是一些转账运算)

}

代码逻辑分析:
在这里 代码逻辑主要是检测交易发起人的余额是否大于要转账的总余额(转账人数 * 转给每个人的钱) 如果大于 就转账

漏洞利用:
注意该合约在进行乘法运算的时候,直接用cnt强转uint256然后乘以_value, 这个时候如果乘积溢出uint256最大值,那么就可以绕过require中的要求,并且进行非法请求

具体操作:
将_value 传值 2**256 +1 / 2
2为address数组长度 即两个收款人地址 这个具体是几无所谓 只要保证溢出条件即可(即 2 * (2的256次方+1)/2 = 2的256次方 +1 > uint256最大值)
那么 amount就溢出为0 那么就绕过了下面的require 从而进行非法操作

P.S.
python生成的数 方便审计检测使用:
unsigned int range:
Unsigned int(uint) 最大表示数 超过此数会上溢为0:
uint8 最高为: 255
uint16 最高为: 65535
uint24 最高为: 16777215
uint32 最高为: 4294967295
uint40 最高为: 1099511627775
uint48 最高为: 281474976710655
uint56 最高为: 72057594037927935
uint64 最高为: 18446744073709551615
uint72 最高为: 4722366482869645213695
uint80 最高为: 1208925819614629174706175
uint88 最高为: 309485009821345068724781055
uint96 最高为: 79228162514264337593543950335
uint104 最高为: 20282409603651670423947251286015
uint112 最高为: 5192296858534827628530496329220095
uint120 最高为: 1329227995784915872903807060280344575
uint128 最高为: 340282366920938463463374607431768211455
uint136 最高为: 87112285931760246646623899502532662132735
uint144 最高为: 22300745198530623141535718272648361505980415
uint152 最高为: 5708990770823839524233143877797980545530986495
uint160 最高为: 1461501637330902918203684832716283019655932542975
uint168 最高为: 374144419156711147060143317175368453031918731001855
uint176 最高为: 95780971304118053647396689196894323976171195136475135
uint184 最高为: 24519928653854221733733552434404946937899825954937634815
uint192 最高为: 6277101735386680763835789423207666416102355444464034512895
uint200 最高为: 1606938044258990275541962092341162602522202993782792835301375
uint208 最高为: 411376139330301510538742295639337626245683966408394965837152255
uint216 最高为: 105312291668557186697918027683670432318895095400549111254310977535
uint224 最高为: 26959946667150639794667015087019630673637144422540572481103610249215
uint232 最高为: 6901746346790563787434755862277025452451108972170386555162524223799295
uint240 最高为: 1766847064778384329583297500742918515827483896875618958121606201292619775
uint248 最高为: 452312848583266388373324160190187140051835877600158453279131187530910662655
uint256 最高为: 115792089237316195423570985008687907853269984665640564039457584007913129639935

访问控制缺陷漏洞:

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

常出现的地方:

在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)

漏洞代码:

 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方法:传参时,不会验证参数的个数,只要找到了需要的参数,其他参数就会忽略 不会产生影响

漏洞地址(之后补上):

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

实例:漏洞代码:

 contract sample{
    
 
 function a(byte data) {
 this.call(data)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值