区块见闻 区块见闻
Ctrl+D收藏区块见闻

COM:二十三种 DeFi 安全事故汇总:智能合约风险与防范_Compound

作者:

时间:

撰文:AustinZhang,JonLi,AsymmetriesTechnologies

智能合约的安全性问题一直是业界的一个重点话题,由于程序员的某些疏忽造成了思维和逻辑上的漏洞,从而导致黑客有了可乘之机。我们搜集了目前在DeFi领域已经发生了安全事故的智能合约,并根据我们编写的示例代码来实证分析其中的原因,希望能给到同事和同行们一些启示。

重入攻击

主要攻击方式之一:合约调用恶意外部合约结束之前,恶意外部合约函数反向调用原合约函数利用相关漏洞。

示例代码

案例1:2021年12月22日UniswapV3流动性管理协议Visor被盗120ETH

事故原因:deposit函数没有防重入锁也没有验证from地址是否是合法的Visor合约地址。攻击者传入攻击合约地址,重复调用deposit函数绕过取款金额检查多次取款。

案例2:2021年6月5日BurgerSwap被盗700万美金

事故原因:类似Uniswap的原创dex,分为Platform和Pool两个合约。Platform类似Uniswap的Router,Pair类似Uniswap的Pool,开发者错误的将K值校验放在Platform计算,攻击者在Platform中进行重入攻击,多次以旧的K值换取代币,造成流动性提供者损失。

解决方案:调用外部合约前确保所有中间状态变量已更新并使用再入锁。

未检查函数返回值

调用外部合约函数时,有些函数调用失败不会抛出错误回滚交易而是返回false,如果忘记检查函数返回值会导致误以为调用成功。

示例代码

案例:2021年4月4日ForceDao到被攻击损失183ETH

北京发布互联网3.0创新发展白皮书:5月27日消息,在北京市科协主办的2023中关村论坛平行论坛“互联网3.0:未来互联网产业发展”上,北京市科委、中关村管委会正式发布《北京市互联网3.0创新发展白皮书(2023)》。

白皮书认为,北京在互联网3.0产业发展政策举措、创新企业、科研基础等方面处于全国领先地位。当前,北京正在围绕关键技术、共性技术平台、应用场景、创新生态和监管等方面,谋划开展系列工作举措,加快推动北京建设具有国际影响力的互联网3.0创新高地。

同时,北京不断强化市区协同,推动区域特色化发展。当前,海淀区着力打造原始技术创新高地,朝阳区重点开展创新企业培育和企业集聚发展,石景山区全力打造科幻、体育等标杆场景示范,通州区加快推动文旅、智慧城市场景应用和元宇宙创新中心建设。北京市还支持东城等区依托自身优势,积极谋划本区互联网3.0优势产业发展。

不过,北京互联网3.0产业发展在技术和人才支撑能力、产业链完整性、法律规范等方面仍面临挑战。白皮书建议,北京应加强政策支持与组织保障,加快技术攻关与共性平台搭建,推动“互联网3.0+”应用场景建设,做好风险监管工作,为北京互联网3.0创新发展营造良好生态环境。[2023/5/27 9:45:47]

事故原因:Force代币的transferFrom余额不足时返回false而不是直接回滚交易,合约中未做判断导致转账失败时也被认为成功,可以换取到对应代币。

解决方案:使用call函数调用外部合约时必须检查调用是否成功。注:call调用外部合约未匹配到函数时,会调用外部合约fallback或者receive函数,如果外部合约有定义receive函数且call函数未携带calldata则会调用外部合约receive函数,其他情况调用fallback函数。

未正确设置函数可见性

数据:DeGods #5995以70 ETH价格成交,创该系列迄今为止最高交易记录:5月4日消息,据NFTgo.io数据显示,DeGods #5995已经以70 ETH的价格在Blur平台拍卖成交,价值约合12.9万美元,创下该NFT系列迄今为止的最高交易记录,卖家为NFT巨鲸sighduck.eth,买家为“0x1F5d5A”开头地址。DeGods最初是一个Solana链上PFP项目,今年四月开放以太坊迁移并得到Blur的支持,目前该系列在以太坊上的交易将会收取0.33%的版税。[2023/5/4 14:42:14]

Solidity中函数默认为public,可以被外部调用,一旦未将关键函数设置为Private,就会导致安全风险。

示例代码

案例1:2022年1月22日DexCrosswise被攻击损失80万美金

事故原因:Crosswise虽然实现了权限验证函数onlyOwner,但忘记设置setTrustedForwarder为private,导致被攻击者利用,将自己设置为池子的Owner将代币全部转走。

案例2:2020年6月18日跨链桥BancorNetwork被攻击损失14万美金

事故原因:合约用于转账的函数默认为public,攻击者可以直接调用转走合约中的代币。

解决方案:提款函数事关合约资产的转移,需谨慎设置权限控制,确保初始化函数只能运行一次。

未验证Map中Key不存在的情况

Solidity中的Mapping在获取对应Key的Value时,如果Key不存在,会返回对应类型的默认值,而不是报错。例如Mapping(int→int),如果对应int的Key不存在,会返回默认值0。

示例代码

MOOAR宣布NFT Launchpad第二季开放提交:1月9日消息,STEPN旗下NFT市场MOOAR宣布,NFT Launchpad第二季开放提交,截止日期为2月16日。团队将审核所有提交的内容,10个项目将获得批准并正式进入第2季Launchpad竞赛。[2023/1/10 11:02:56]

案例:2021年7月11日跨链桥ChainSwap被攻击损失400万美金

事故原因:ChainSwap依赖其网络中的validator进行转账。为了限制validator一次转走超过其质押的代币,设置了配额。结果合约中存在漏洞可以绕过配额限制,当地址变量signatory不存在时,authQuotes和lasttimeUpdateQuoteOf会返回0,导致配额计算错误返回预期外的大量配额。

解决方案:使用map时必须检查key是否存在。

在状态变更前进行转账

转账时有可能被重入,利用未变更的状态进行攻击。

案例:2021年8月17日XSURGE被攻击损失500万美金

事故原因:在转账后才修改totalSupply,转账时被重入另外一个未加重入锁的函数损失500万美金。

解决方案:使用了再入锁也要在所有状态变更之后在转账。

初始化函数未做调用和权限限制

很多合约需要初始化子合约,例如Uniswap需要通过Factory合约初始化Pool合约,这时候如果忘记对子合约的初始化函数做权限和重复初始化限制,可能被攻击者进行恶意初始化。

案例:2021年8月11日PunkProtocol被攻击损失400万美金

事故原因:池子的initialize函数未做权限和重复调用限制,攻击者调用该函数将自己设置为Forge管理员权限,并调用withdrawToForge将池子所有资金都发送到攻击者地址。

Vitalik Buterin与YC创始人已在社交媒体上互相取关:11月22日消息,以太坊联合创始人Vitalik Buterin与Y Combinator联合创始人Paul Graham已在社交媒体上互相取关。以太坊联合创始人Vitalik Buterin此前发推讽刺Paul Graham的小道消息推文,并表示过去一周发现难以忍受的一个现象:人们散布谣言,很多人转发它们,很多人开始根据这些谣言信息进行交易……总之,我认为我们不应该把“Trustme”的谣言交易合法化。这为操纵市场提供了成熟的空间,甚至可能造成波动。另一个更深层次的问题是,加密领域有一段悠久的历史,人们利用谣言来诱导价格朝着有利于他们的方向波动。故意操纵市场并获取收益并不符合加密金融文化。[2022/11/22 7:55:26]

解决方案:初始化函数必须设置成只能初始化一次。

未正确检查对应合约函数实现

通常智能合约被调用的函数不存在时会报错,但如果合约实现了fallback函数,则会自动调用fallback函数。有时fallback函数并不会报错,导致调用方误以为调用成功。

案例:2022年1月18日跨链桥Multichain被攻击损失450ETH

事故原因:通常ERC20的合约会实现permit函数,用于签名检查与授权操作。但WETH、PERI、OMT、WBNB、MATIC、AVAX六种代币的合约没有实现permit却实现了fallback,Multichain在检查这些代币的权限时误以为用户已经授权转账给攻击者,导致代币被盗。

解决方案:不同代币的实现方式不同,引入新代币之前应仔细检查其具体实现。

未正确处理带转账费的代币

有些代币在转账时会销毁一部分转账费用,导致实际收到的代币余额偏少,如果开发者没考虑到这一点,以转账值计算,会导致出现偏差。

Riot Blockchain 股东拒绝向五位比特币矿业高管授予 9000 万美元的薪酬:金色财经报道,Riot Blockchain 最近的股东投票否决了对高管薪酬的重大咨询投票,该提案将向五名Riot高管支付超过9000万美元。首席执行官Jason Les和执行主席Benjamin Yi将分别获得约2100万美元。即使是薪酬最低的高管、总法律顾问William Jackman,也有可能获得1300万美元的薪酬。该议案旨在留住人才并确保实现长期战略目标。?

但VanEck分析师指出,股东不同意董事会一致建议,敦促他们投票支持“薪酬发言”提案。

根据 VanEck 的数据,2022年IT行业的直接薪酬中位数为220万美元。Riot其他加密货币矿业公司支付的薪酬中位数为1080万美元,比IT行业高出 390%。[2022/9/1 13:01:19]

案例:2021年8月19日Pinecone被盗20万美金

事故原因:Pinecone使用其代币PCT作为资金池的质押代币,PCT转账会有手续费的损耗。合约并没有考虑相关损耗导致用户份额和质押的PCT总额出现偏差,被攻击者利用领取多余的奖励。

解决方案:谨记不是所有的代币转账费都为nativetoken。

签名验证漏洞

签名被重复使用,或者利用椭圆曲线签名算法的对称性,根据已有签名构造合法签名。

案例:2021年7月12日AnySwap被盗800万美金

事故原因:对交易签名除了私钥外需要一个随机数R,但是Anyswap部署新合约失误,导致在BSC上的V3路由器MPC帐户下有两个交易具有相同的R值签名,攻击者反推到这个MPC账户的私钥转走了被盗资金。

解决方案:使用EIP-712标准验证签名,参考OpenZeppelin的实现:https://docs.openzeppelin.com/contracts/3.x/api/drafts。

未考虑合约余额可能产生的变化

矿工挖出块时或者智能合约调用selfdestruct函数销毁自己时可以向任意地址强行打币改变其原生代币的余额。当使用余额函数返回值作为判断条件时,余额有可能被强行改变导致风险,极端情况下甚至导致合约拒绝服务。

示例代码

即使捐赠合约不能接受代币转账,合约余额也可能在部署后被改变,严格检查已空投总量与合约余额之和等于总供应量可能导致捐赠合约拒绝服务。

解决方案:在合约中避免对合约余额做严格相等的检查。

使用delegatecall调用外部合约

delegatecall可以将对应合约的函数代码内嵌到当前上下文中执行,就像调用内置函数一般。如果不小心调用了恶意合约极易导致攻击。

示例代码

当攻击者调用forward函数并传入Attack合约地址以及函数setOwner()作为参数时,Proxy合约owner将被修改为攻击者地址。

解决方案:不推荐使用delegatecall调用外部合约。

授权tx.origin

tx.origin是交易的发起者地址,合约如果使用tx.origin做权限检查,当合约的授权用户与恶意合约交互时,恶意合约调用合约即可通过合约权限检查。

示例代码

当MyWallet合约owner使用transferTo函数向Attack合约转账时,Attack合约会重入MyWallet合约,并调用transferTo函数,此时tx.origin仍然为MyWalletowner,require条件满足,MyWallet余额将被全部转移至Attack合约。

解决方案:不使用tx.origin做权限检查。

交易排序竞争

全节点运行者可以在交易被确认之前获取交易信息,进而根据获取的交易信息,构造高手续费交易,让矿工优先打包自己的交易以执行对自己有利的策略。例如,谜语合约奖励最快找出谜底的用户,恶意用户可以在获悉诚实用户提交的谜底后,构造高手续费交易优先诚实用户提交谜底,从而获取奖励;又如当用户更新授权额度时,被授权用户可以在更新授权额度交易被确认之前转移旧的授权额度,如此,被授权人实际获得的授权额度为两次授权额度之和。

解决方案:针对谜语合约,获得谜底的用户先提交「随机数+自身地址+谜底」的哈希值,谜语合约存储该哈希值后,用户再提交随机信息与答案,合约检查哈希值匹配后再发放奖励;更新授权额度时先置零授权额度。

使用block.timestamp或者block.number作为合约时间参考

block.timestamp与block.number都不能获得精确都时间,用作智能合约的时间参考会引入潜在的风险。

解决方案:使用oracle获取时间信息。

Denial-of-Service(DoS)拒绝服务

调用外部合约可能永久失败导致本合约不能接受新的指令,例如当合约主动对另外一个合约转账,而被转账合约没有接受转账的函数时,转账失败,此时合约可能进入拒绝服务状态。

示例代码

当合约向其中一个账号转账失败会导致所有转账全部失败。

解决方案:合约调用外部合约时可能出现的失败,合约需包含处理调用失败情况的代码,防止合约进入拒绝服务状态。

使用链属性作为随机源

链属性如block.timestamp,blockhash,bock.difficulty以及其他属性可被矿工操控,存在风险。

解决方案:考虑使用RANDAO,oracle或比特币区块hash作为随机源。

继承顺序错误

多个被继承合约都定义了同一个函数时,继承合约调用该函数的优先级由继承顺序决定,错误的继承顺序将导致函数调用错误。

解决方案:继承顺序说明请参考官方实例:https://solidity-by-example.org/inheritance/。

Gas不足攻击

多签情况下或者需要其他人帮自己代付Gas时,用户准备好签名交易并交给代执行人,代执行人再将用户交易提交给执行合约,代执行人可以提前审查用户代交易,恶意的代执行人或当交易内容不利于代执行人时,可以通过限制Gas的供给,使交易的执行失败,从而阻止交易的执行。

示例代码

当Relayer调用者通过限制Gas使用导致某个交易失败,那么失败的交易将永远不能再被提交。

解决方案:选择信任的代执行人,或者在执行合约中检查代理人提供的Gas费是否足够。

函数类型变量跳转

solidity支持函数类型变量,当函数类型变量使用汇编指令赋值时,函数类型变量有可能被指向恶意构造当函数。

解决方案:如无必要,尽量避免在智能合约中使用汇编指令。

GasLimit服务拒绝攻击

区块设置有Gas使用上限,如果合约当执行超过了区块Gas使用上限,则合约永远不能被执行成功。

示例代码

当操作的循环次数过大时,执行合约所需Gas将超过区块上限,导致合约执行失败。

解决方案:在智能合约中谨慎操作大数组,或循环。

abi.encodePacked()哈希碰撞

abi.encodePacked()采用非填充序列化,当序列化参数包含多个变长数组时,攻击者可以在保持所有元素顺序不变的前提下,改变两个变长数组的元素,如此序列化的结果相同。

示例代码

通过构造addUser的输入,攻击者可以将regularUsers的成员加入admins成员,但是构造的输入和原输入的签名相同。

解决方案:使用定长数组,或者不让调用者传入abi.encodePacked()的参数,或者使用abi.encode()。

transfer()和send()函数Gas不足

transfer()和send()函数使用2300gas以防止重入攻击,公链升级后可能导致gas不足。

解决方案:推荐使用call()函数,但需做好重入攻击防护。

链上未加密隐私数据

链上数据完全透明,合约的private关键字不能阻止合约的隐私数据泄漏。

示例代码

虽然players为private,但攻击者仍然可以通过解析链上数据读取players。

解决方案:隐私数据需要加密放在链上。

以上是我们分析和总结的二十三种安全事故类型汇总,希望能够给到您些许参考和启示。

标签:COMUNDOMPCompoundIncome Island TokenARTIC FoundationCompound Wrapped BTCCompounder

比特币交易热门资讯
LEC:除巨鲸外,还有哪些类型的 NFT 持有者潜入海底?_NFT

作者:NFTGo 在加密货币市场,巨鲸是指持有大量特定代币的对象——个人、机构和交易所。例如,当谈到比特币时,巨鲸一般是指持有1000个或更多比特币的账户.

AUD:第 4 章:音乐_COL

世界各地的音乐家也开始接受这种创新媒介,为音乐产业注入新的活力。从未发行的歌曲到独家的完整专辑,艺术家们现在可以直接以NFT的形式发布他们的歌曲,并直接从粉丝那里获得收入,无需任何中间媒介的干预.

OMP:第 6 章:去中心化借贷_Compounder

资金借贷是金融业提供的最常见的服务之一,其由信用与担保的概念所促成。可以说,商业规模借贷的发明带来了文艺复兴时代,不太富裕的人也能通过借贷获得启动资金,从而引发了经济活动的热潮.

STE:成为性能最佳的 EVM,Trust EVM 的野望_GAS

作者:EOS网络基金会 2022年6月16日,TrustEVM官方在TwitterSpace展开主题为“Trust如何实现最快的EVM”的直播活动.

TRUST:Messari:市场低迷之际,DeFi仍吹响了“无形革命”的号角_DEF

作者:ChaseDevens,Messari原文标题:《DeFi''sInvisibleRevolution》编译:Hsilung,链捕手 摘要: 尽管短期来看,似乎前景黯淡.

AUR:掀起 BAL 的「Balancer War」之争?速读 0xMaki 新项目 Aura Finance_RICKMORTYDOXX

作者:0xMaki 编译:foresightnews3月28日,参考「CRV-veCRV」代币经济学的veBAL机制正式上线Balancer.