编按:XREX 资安长暨总经理 Sun Huang 拥有超过 15 年的国际资安经验,并获得 Offensive Security Certified Professional (OSCP)、Certified Ethical Hacker (CEH)、AWS Certified Security – Specialty (AWS ACS) 等国际资安执照及认证。近期,Sun Huang 开源两套 Web3 资安工具,协助工程师与开发者强化智能合约安全开发。Sun Huang 撰写本文,分享开发工具的缘由,并分享实例示范如何使用这两套工具。
做为 XREX 资安长,我从今年 3 月开始主持公司内部培训,提升资安团队的两大技能:Web3 资安分析能力,以及虚拟货币链上金流的威胁分析,也对 XREX 产品工程团队举办了两次 Web3 资安工作坊,这也是我分别在今年 6 月和 7 月开源两套 Web3 资安工具 DeFiHackLabs 和 DeFiVulnLabs 的缘由。
每一次只要有 DeFi 项目遭骇,XREX 内部都会分析事件的根本原因并尝试重现问题。我们会透过 Fork 主网特定区块状态,模拟骇客攻击智能合约的手法,并观察余额状态的改变。每一次的攻击事件都可以帮助我们在未来开发时,避免踩到同样的坑、犯同样的错。
我心想,这些宝贵的经验也应该让更多人受惠,因此就在 6 月中开源了一个 Web3 安全相关的工具 DeFiHackLabs ,将过往累积的资安事件概念性验证程序 (Proof of Concept,PoC) 都收录进去。我使用 Paradigm 推出的以太坊开发工具 Foundry 做为框架,因为编译快速、集成了很多实用功能,使用起来非常顺手,更多 Foundry 使用的相关资讯,可参考 Foundry Book。
原先我的初衷只是希望在 Web3 的发展过程中,为资安做点贡献,如常地发到 Twitter 做个纪录。非常意外的是,隔日我收到了无数 Twitter 通知,才知道原来我的推文被 Paradigm 的技术长 Georgios Konstantopoulos 转推,引起社群很好的响应。
随后有许多人私讯我,想了解有没有适合新手或刚入圈的工程师的 Solidity 常见漏洞教学。了解到这些需求后,我在 7 月初再开源了另一个工具 DeFiVulnLabs,整理了常见 Solidity 的漏洞测试与防御方式,当天推文的转推数量与单日 4 万次的访问量蛮令我惊讶的,由此也可以知道,有非常多人对区块链技术的开发非常感兴趣,积极想要增进资安能力并从过往的事件中学习,这让我非常振奋,也很期待未来持续在 Web3 安全领域做出贡献。
这篇部落格,也与各位分享 DeFiHackLabs 和 DeFiVulnLabs 这两套 Web3 资安工具和使用方式,希望在大家打造智能合约与开发 DeFi 项目时,可以免于在区块链黑暗森林中迷失与跌倒。
(难度等级: 初级)
DeFiVulnLabs 目前收录了 19 种智能合约的常见漏洞类型,如下表所列:
漏洞类型 |
说明 |
Integer Overflow |
在以太坊虚拟机 (EVM) 中,整数为指定固定大小的资料类型,在 Solidity 0.8.x 版本之前,算术运算时会造成整数型溢出问题。 |
Selfdestruct |
当合约有使用到 selfdestruct,且函数存取权限未有效控管,攻击者可以销毁该合约。 |
Unsafe Delegatecall |
允许攻击者使用 delegatecall 呼叫第三方合约函数来动态执行在目标合约上。 |
Reentrancy |
如果智能合约中可透过回调执行攻击者的外部合约时,外部合约可接管控制流程,达到非预期影响。通常造成这个问题的原因是没有遵循「检查 – 生效 – 交互」 (Checks-Effects-Interactions) 的机制,或没有使用ReentrancyGuard 保护控制流程。 |
ERC777 callbacks and reentrancy |
ERC777 允许在转移资产时透过挂钩 (Hook) 来进行任意回调。 |
Unsafe low level call – call injection |
如果 call value 可控,容易造成任意函数执行。 |
Private data |
状态变数可见性设为 Private 不等于安全,因为每个智能合约的 Storage 都是公开透明,可以透过指定合约地址中对应的 Slot 读出内容。敏感资讯不建议放在智能合约程式中。 |
Unprotected callback – NFT over mint |
_safeMint 真的安全吗? 攻击者可以透过 mint 函数内的 onERC721Received 进行重入。 |
Backdoor assembly |
攻击者可以透过写入内联汇编 (Inline Assembly) 来当作后门操纵智能合约。可随时更改任何敏感参数。 |
Bypass isContract |
攻击者只需要将程式码写在智能合约的建构子 (Constructor) 里面,就可以绕过是否为智能合约的侦测机制。 |
Denial of service |
透过呼叫外部非完整的智能合约,来造成目标合约瘫痪。例如接收 Ether 的合约中不包含 fallback 或 receive 函数。 |
Randomness |
避免使用全域变数来产生随机数,如:block.hash、block.number、block.timestamp,这些都是可被预测的。 |
Visibility |
函数预设可见性是 Public,如果存在不安全的可见性设定,可让攻击者直接呼叫智能合约中的敏感函数。 |
txorigin – phishing |
tx.origin 是 Solidity 中的一个全域变数,在智能合约中使用该变数进行身份验证,会使该合约容易受到网路钓鱼的攻击。 |
Uninitialized state variables |
如果未初始化的变数可控,容易被攻击者执行初始化后,导致不预期影响。 |
Storage collision |
如果代理合约和逻辑合约的敏感变数存储插槽 (Storage Slot)相同,那么就容易发生存储冲突,容易被攻击者覆蓋变数。 |
Approval scam |
目前大部分诈骗都是透过 approve 或 setApprovalForAll 来骗取你的转帐权。这部分要特别小心。 |
Signature replay |
如果缺乏完善的签名检查机制,容易造成签名重放攻击。 |
Data location – storage vs memory |
错误使用储存空间和记忆体来保存变数状态,容易造成合约使用未更新的数值来进行计算。 |
使用方式
以 ERC777 callbacks and reentrancy 为例:
智能合约要求代币总供给量必须 ≤ 1000 颗,否则不允许铸造新的代币。你能绕过最大总供给量限制吗?
ERC777 callbacks and reentrancy 原始码连结
执行: forge test –contracts ./src/test/ERC777-reentrancy.sol -vvvv
-v 参数代表显示测试程式码的 logs 与 Execution traces,共有 5 个 Level。
执行输出如下所示:
我们节录关键 Execution traces 向读者解读为何 Token 余额可以从 1,000 增加至 10,000,如下图所示:
可以看到当攻击合约 `ContractTest` 呼叫 `MyERC777.transfer()` 时,`ERC1820Registry` 合约会回调呼叫 `ContractTest.tokensReceived()`,这意味着攻击者可以在 `tokensReceived()` 里写入恶意程式码并再次重新进入 `MyERC777` 合约的执行流程。
此处的恶意程式码是再次呼叫 `MyERC777.mint()`,使代币合约再次铸造 9,000 颗 Token 给攻击合约。最后就可以看到攻击合约的余额共有 10,000 颗 Token 了。
(难度等级: 中级)
DeFiHackLabs 目前收录了 42 个过往 DeFi 资安事件重现,可以从真实世界中了解过往的骇客攻击手法,并在开发智能合约时避免踩到一样的坑。近期 Foundry 支援了可以一次 fork 不同区块,也可以跨链,不需要从 CLI 带入 fork-url & fork-block-number 参数,在测试上又更方便了!
使用方式
以 InverseFinance – Flashloan & Price Oracle Manipulation 为例:
Inverse Finance 项目在 2022 年 6 月 16 日时,遭受闪电贷攻击,损失约 120 万美金,由于项目方实作了不安全的预言机来计算抵押品价格,导致攻击者可透过闪电贷操控抵押品价格来获利。
执行: forge test –contracts ./src/test/InverseFinance_exp.sol -vvvv
希望以上两个工具的分享,可以帮助想要开发 Web3 项目的团队加强智能合约的安全性与韧性。若有任何疑问,也欢迎在推特上(@1nf0s3cpt)与我交流。
XREX 将在 8月19至20日出席 2022 HITCON x Yourator 数位职涯博览会。欢迎有志之士前来与我们聊聊。到时见!
共同编撰:Sun Huang / Seal Cao 曹富翔 / Yoyo Yu 尤芷薇 / Fred Lai 赖彦志