共计 4332 个字符,预计需要花费 11 分钟才能阅读完成。
寻找智能合约 bug 可能是一项高回报的工作,而且它也爱护了生态系统免受黑客攻击。我最近有幸采访了一位开发人员,他发现了一个价值 70 亿美元的谬误,并因报告该谬误而取得了 220 万美元的报酬。
在这篇文章中,我将具体介绍该开发人员发现的 bug 的过程,以及它如何有可能侵害 70 亿美元的价值,而后再提供一些可帮忙你查找谬误的策略和工具。
让咱们开始吧。
Polygon 智能合约 bug 案例
背景
2020 年 5 月 31 日,Matic 区块链上线(Matic 起初更名为 Polygon)。Polygon 是一种与 EVM 兼容的区块链,以其低 gas 费用和短块工夫而闻名。该链最近开始摸索 zk-rollup 技术。
如果你查看 Polygon 的“创世”区块,即区块链的第一个区块,你将看到 10 笔交易。其中一笔交易创立了一个名为 MRC20 的合约。
Polygon 创世区块
这个智能合约是什么?
当咱们发送原生区块链通证时,咱们必须破费 gas。因而,Polygon 团队部署了一个合约,容许你签名一项交易以向某人发送 ETH,而其他人则能够领取这笔交易的 gas 费。这种性能被称为“元交易”,随着 EIP-712 的推出而遍及。
你能够看到,该合约取得了近 100 亿个 MATIC 通证,以帮忙促成这些无需 gas 的交易。然而,这个设计精美的合约却蕴含一个 bug,而这个 bug 可能会被利用来盗走全副余额!
2021 年 12 月 3 日,故事的主人公、伪匿名开发者 Leon Spacewalker 向 Immunefi bug 赏金打算提交了一份报告,具体介绍了这个函数的问题。第二位英雄,咱们称之为 Whitehat2,也在一天后报告了该 bug。
在该链于 2021 年 12 月 5 日最终分叉、回滚和修复之前,大概有 800,000 个 MATIC 被盗。
这次事件给咱们抛出了很多问题:bug 是什么?它是如何长期未被发现的?它是怎么被发现的?
bug 利用
以下是发送无 gas 交易的函数
function transferWithSig(
bytes calldata sig,
uint256 amount,
bytes32 data,
uint256 expiration,
address to
) external returns (address from) {require(amount > 0);
require(
expiration == 0 || block.number <= expiration,
"Signature is expired"
);
bytes32 dataHash = getTokenTransferOrderHash(
msg.sender,
amount,
data,
expiration
);
require(disabledHashes[dataHash] == false, "Sig deactivated");
disabledHashes[dataHash] = true;
from = ecrecovery(dataHash, sig);
_transferFrom(from, address(uint160(to)), amount);
}
乍一看,它仿佛有害:它须要用户的签名、有多少通证、他们想将通证发送给谁、进一步的数据,以及交易的到期日期。
它也有一些限度,获取数据哈希以发送元交易,确保数据哈希未被应用,并执行这个 ecrecovery
函数。
这个函数实质上是 Solidity ecrecover 函数的 Wrapper。
Solidity ecrecover 函数的 wrapper
Here’s the actual code:
咱们这个函数验证签名交易的起源。你会留神到,即便在 Solidity 文档中,它也说它将“谬误的返回值为零”。ecrecovery 函数也一样,如果有问题,它会返回 0。正如许多开发人员所知,这可能是有危险的。如果它在出错时返回零,那意味着咱们应该查看以确保返回的地址不为零,对吗?
这是理论的代码:
这是现实中的代码:
咱们其实没有对地址执行查看以确保它不会导致谬误,好吧。transferWithSig
函数中的最初一行代码执行理论的转账,咱们必定要在那里执行某种查看,对吧?
function _transfer(address sender, address recipient, uint256 amount)
internal
{require(recipient != address(this), "can't send to MRC20");
address(uint160(recipient)).transfer(amount); // It just sends the money!
emit Transfer(sender, recipient, amount);
}
_transferFrom
函数刚刚调用了咱们的 _transfer
函数,如上所示。你会留神到它不会查看,以确保 from
地址有足够的余额。
这意味着有人能够发送有效签名,这将导致从 ecrecovery 返回零地址,但 MRC20 合约仍会向 to
地址发送肯定数量的通证。这就是 9,999,993,000 MATIC 被盗走的形式,因为 MRC20 合约间接从本身发送通证!
如果在合约中查看,以确保发件人地址有足够的余额用于此签名交易,就能够防止此问题。
为什么智能合约 bug 长期未被发现
令我感到奇怪的是,在该 bug 埋伏了将近一年半之后,它在几天之内就被另一位白帽子 Leon 和一名黑客发现了。
如同有猫腻的样子,但 Immunefi 团队通知我,这种状况常常产生。某些 bug 被利用可能会因一篇文章、文章或挑战而变得风行,而后人们开始寻找该 bug,导致多集体同时找到它。
但更有可能的是,事实证明 Polygon 在这段时间左右在 Polygonscan 上验证了合约——那也是人们真正开始关注它的时候。
兴许还有更多的故事,但兴许不是。
无论如何,让咱们把这个 bug 作为一个教学案例,看看 Leon 和其余 bug hunter 用来发现 bug 的一些技能,帮忙爱护 Web3 生态系统。
7 发现合约 bug 的技巧
当初,咱们将学习 Leon 和其余 bug hunter 用来发现这些 bug 并申请 bug 赏金的技能。此提醒列表假设你曾经理解智能合约的基础知识,所以是的,学习 Solidity 是先决条件。
请有道德地去应用这些技巧,请记住负责任地披露你发现的任何 bug。
许多查找 bug 的工作来自于查看代码和运行诸如 slither 之类的工具。对于这笔 220 万美元的播种,Leon 示意他可能通过逐行查看智能合约代码来找到 bug,所以请记住,发现 bug 通常须要大量的人工手动操作!
除了上面的实用技巧外,Leon 最大的播种是让智能合约 bug hunter“找到你的劣势”,什么意思?通常,这意味着找到让你有别于其他人的货色。作为一个社区,咱们须要笼罩智能合约空间的每一个角落,所以找到你特地善于和善于的局部。
这里有七个策略和技巧能够帮忙你找到劣势,让你变成胜利的智能合约的 bug hunter。
1. 找到一个我的项目而后搜寻 bug
找到谬误的第一种办法是具体地理解协定工作原理。这是每个智能合约 bug hunter 须要学习的首要技能之一:端到端了解协定的能力。
浏览文档,尝试本人从新实现协定,并在区块浏览器上通过该协定查看交易。
Leon 说这个策略对其余 bug hunter 无效,但对他有效。他专一于接下来的三个,但对于每个 bug hunter 来说,可能做到这一点很重要。
2. 找到 bug 而后搜寻我的项目
寻找 bug 的一种更简略的办法是:找到一个鲜为人知的 bug,而后尝试查看哪些协定的实现中蕴含这个 bug。
这种策略须要大量钻研,因为有很多人致力于向公众公开 bug。
你首先须要理解所有根本的智能合约 bug,而后是它们的高级版本。你须要理解最佳实际并查看是否有未遵循的协定。
一旦发现智能合约 bug,你认为很多我的项目可能无奈防备,就开始搜寻该 bug。直到真正相熟这个新的 bug 以及如何找到它。肯定写博客或某种帖子来帮忙遇到此 bug 的其余智能合约开发人员。
3. 要快
心愿 bug hunter 查看其智能合约的我的项目须要注册像 Immunefi 这样的破绽赏金打算。你会想成为第一批发现新赏金的开发者之一。如果你比其余猎人先开始查看合约,你将有更多工夫找到破绽。
有几种办法能够加快速度——Leon 可能在其他人之前找到智能合约破绽的办法之一是通过 Immunifi Discord 频道的告诉。每当有新我的项目进入或我的项目更新时,他都会收到告诉。像这样的工具能够帮忙你抢在其他人之前深入研究代码。
4. 要有创意
Leon 取得劣势的另一种形式是查看大量的社区论坛,发现他们正在思考提交 bug。而后他甚至在赏金取得批准之前就开始查看智能合约。这让他比其余开发人员有更多工夫查看合约,因为他人会期待我的项目方 bug 赏金提交胜利。
5. 理解你的工具
Bug hunter 要应用 VSCode Solidity 的 extension、Hardhat、Foundry、Brownie、Dune、Etherscan 以及许多其余工具。
一种的 bug 查找策略可能是加载 VSCode,应用 Solidity extension 将代码增加到 VSCode,而后逐行查找常见谬误或有破绽的代码实现。
找到潜在破绽后,设置测试环境以对合约运行测试。你通常能够重用协定开发人员最后应用的大量测试。
6. 不要放弃审计过的我的项目
这里就不多说了。审计公司会犯错误。Leon 发现破绽的许多我的项目都曾经过顶级公司的审计。
应用咱们在此博客中探讨的技巧能够帮忙你找到这些问题!
7. 行业特定常识
你最大劣势之一可能就是专一于特定的细分市场。如果你十分理解一个畛域,那么你将领有理解所有函数如何互相调用的常识。相同,如果你是一个厉害的智能合约破绽专家,但对 DeFi 无所不知,那么很难找到 DeFi 合约中的破绽。例如,许多开发人员理解代码,但不理解财务术语。
你可能十分善于了解去中心化交易所、借贷协定,或者只是 NFT!
如果你能成为平安专家和 Web3 中某个垂直畛域的专家,你将处于无利位置,在其余寻找破绽的人背后占据劣势。
总结
我心愿这篇文章在你的智能合约 bug 搜寻之旅中帮忙到你。如果你想在编写智能合约时理解更多无关平安的信息,请务必查看十大 DeFi 平安最佳实际。
而且,判若两人,我心愿看到你在那里建设并放弃生态系统更平安。
相干链接:
MRC20 contract.
Immunefi writeup.
Change to Polygon contracts.
Previous Polygon contracts.
Ecrecovery challenge.
这篇文章中表白的观点仅代表作者,并不反映 Chainlink。
欢送关注 Chainlink 预言机并且私信退出开发者社区,有大量对于智能合约的学习材料以及对于区块链的话题!