在对所有提交作品进行全面评估后,我们很高兴地分享今年“阴险 Solidity 竞赛”!
的获奖者。如果您不熟悉它,请阅读
在深入探讨获奖作品之前,我们要感谢所有参与竞赛的参赛者。总共收到 16 个符合资格的提交作品,您可以在 此仓库 中找到它们。所有 16 个提交作品都有资格获得“合格提交”的“阴险 Solidity”POAP NFT - 获奖者将额外获得一个“获奖者”POAP NFT。
我们将在不久后与所有参赛者联系,告知 NFT 领取流程以及主要奖项的详细信息。
现在,让我们从第五名开始,看看今年的获奖者!
“阴险 Solidity 竞赛” 2020 年获奖者
5️⃣ 第五名:Marius van der Wijden
评语来自 Alex Beregszaszi此提交作品强调了明确区分错误条件和返回值的必要性。该
ecrecover 预编译只有一个输出,即地址,在出错时会被设置为零。虽然 某些 此预编译的高级包装器会进行区分,但许多会引入新的错误条件,但仍然会重复使用相同机制,在出错时返回“零地址”。OpenZeppelin 的版本 之前 3.0 系列就是这种情况。
利用这种验证缺陷,此提交作品允许任何人创建无限的“投票已接受”交易。
Solidity 一直支持多个返回值,这允许分别返回状态/错误代码和数据,但更重要的是,已确立的最佳实践是使用 require 语句进行验证,而大多数 ecrecover 使用案例在今天都遵循此实践。
- 虽然此提交作品的编写清晰,并且如果没有同时分析 closeVote 和 受信任的 ECDSA.recover 函数,这个问题并不明显,但我们认为,有两个缺点引起了怀疑
- 仅追加数据结构并不常用。
最近人们越来越关注 ECDSA.recover,因此人们期望对它的应用进行更全面的审查。此提交作品使用了 OpenZeppelin 2.5.0 的版本。
4️⃣ 第四名:Richard Moore
评语来自 Stefan Beyer
此提交作品利用 CREATE2 劫持控制升级功能的多签合约。虽然这是一个已知问题,但这种情况证明了 CREATE2 与自毁相结合的影响,并表明在安全分析中评估合约部署过程的重要性。
3️⃣ 第三名:Cory Dickson
评语来自 Goncalo Sá
此提交作品突出了在 EVM 中验证非 EOA(外部拥有账户)地址的危险。即使评估与特定系统交互的账户是否不是合约一直是主网上许多生产黑客攻击的根源,因此是一个经过充分研究的错误模式,但用户通过自毁其合约来“DoS”系统的模式却并非如此。
简而言之,此攻击证明了在依赖可组合性且预期特定地址存在智能合约是时间无关函数的治理系统中,可能出现锁定情况。由于 OpenZeppelin 库用于检查账户是否为合约或非合约,即使合约可能在交易结束时自毁,也会返回 true,因此攻击者能够锁定后续的治理投票以更改委托的合约。
有什么缺点吗?
由于其极度简单,此提交作品在构建可能发生这种攻击的实际现实场景方面略有不足。故事讲述或智能合约系统的改进将受到欢迎。
我们为什么选择此提交作品作为获奖者之一?
它的简单性非常好。这种攻击不可能比它更直接,而且在当今 EVM 的安全环境中仍然具有相关性。
重申对上一个问题的回答,这种极度的简单性也是它不是最强大提交作品的原因之一。希望能够提供更多背景信息。
2️⃣ 第二名:Jaime Iglesias
评语来自 Austin Williams
在此提交作品中,使用 EIP-1967 代理来升级 ERC-20 代币合约。这里有两个关键角色:管理员和所有者。有一个 _optIn 存储变量,指示所有者是否同意升级。管理员只有在所有者将 _optIn 值设置为 true 时才能够进行升级。
该 _optIn 存储变量存储在存储槽 0x7b191067458f5b5c0c36f2be8ceaf27679e7ea94b6964093ce9e5c7db2aff82a 中,代码注释声称该存储槽是通过“对 'eip1967.proxy.optIn' 的 keccak-256 哈希值减 1”得出的。但是,该存储位置实际上指向存储中管理员已知地址的代币余额存储的位置。这意味着管理员可以将 _optIn 设置为 true,而无需所有者的同意,只需将一些代币发送到管理员已知地址,从而将 _optIn 存储位置的值从 0 更改为真值。
通过这种方式,可以通过向某些由管理员控制的地址发送和接收代币来解锁和锁定后门。
1️⃣ 第一名:Robert M C Forster
评语来自 Chris Reitwiessner
此提交作品实现了一个结构良好且非常简单的延时锁定升级:所有者建议一个新的委托实现,该实现将在建议一个月后生效。
唯一可疑的地方是,执行升级的时间点以月和日而不是时间戳的形式存储。该漏洞隐藏得很好,并利用了改变文本流方向的特殊 Unicode 符号。这些符号在代码中当然无效,但在注释中是可以接受的。
由于多行注释在从左到右读取和从右到左读取时工作方式相同,因此提交作品能够“从右到左”终止注释,并切换到代码模式,然后以“错误”的顺序显示。这会导致日和月变量在不知情的情况下被交换,并且升级比预期提前执行。
您可以在提交作品中选择 第 65 行的一部分 来查看(或不查看,取决于您的编辑器 😬)方向更改的实际情况。
这是一个可以通过在 Solidity 级别禁止文本方向更改跨越注释来防止的缺陷 (问题跟踪器),但我还要提醒 IDE、高亮器和代码分析器开发者注意这一点。我不确定代码分析器如何处理这种情况,但如果代码分析器标记了行末的多余空格,那么它肯定应该标记从注释中流出的文本方向更改。
荣誉提名
🦇 Chris Whinfrey 的 VampireSwap
为其巧妙而详细的故事讲述和文档点赞!
此提交作品展示了信任“已审计”可升级合约的社会方面:除非有人验证每个链上执行的升级(以及初始化),否则任何审计都没有意义。即使是 Open Trail of Diligence 的审计也不例外!;)
🐛 Luiz Soares & Boris Breslav 的 Superior Proxy
此提交作品利用了一个 Solidity 编译器错误,即 Solidity 动态数组清理错误,该错误在 Solidity v0.7.3 中已修复。从理论上来说,利用这个错误是一个好主意,但实现存在可疑之处,会引起怀疑。
期待在下一届“阴险 Solidity 竞赛”上与您相见!
我们要感谢 ConsenSys Diligence、Solidified、OpenZeppelin 和以太坊基金会提供奖品,并感谢我们的评委 Alex Beregszaszi、Austin Williams、Christian Reitwiessner、Gonçalo Sá 和 Stefan Beyer 的评估和支持!