跨链桥事件总结分析
Poly Network 跨链桥事件
Relayer的不完整检验
源链上(Ontology)的relayer没有对上链的交易做语义校验,因此包含修改keeper恶意交易可以被打包到poly chain上
目标链上(以太坊)上的relayer虽然对交易做了校验,但是攻击者可以直接调用以太坊上的EthCrossChainManager合约最终调用EthCrossChainData合约完成签名修改
攻击者精心够着了能导致hash冲突的函数签名,从而调用
putCurEpochConPubKeyBytes
完成对签名的修改
见攻击步骤的具体分析
Polygon Plasma Bridge漏洞
外部验证+乐观验证 该漏洞可以伪造铸币证明,导致双花攻击
完整的一次Withdraw交易过程如下:
- 用户在Polygon上发起Withdraw交易,该交易会burn掉用户在Polygon的代币;
- 经过一个检查点间隔(大约30分钟),等待该withdraw交易被包含到检查点中;
- 超过2/3的验证者签名后将其提交到以太坊,此时用户调用ERC20PredicateBurnOnly合约中的startExitWithBurntTokens()校验checkpoint是否包含burn交易;
- 校验通过,则铸造一个NFT退款凭证发给用户
- 用户等待7天挑战期
- 调用WithdrawManager.processExits()销毁NFT,并退款给用户
Polygon为了防止交易重放(双花攻击),使用NFT作为退款凭证,来唯一标识一笔Withdraw交易。但是,由于NFT的ID生成缺陷,造成了攻击者可以构造参数利用同一笔有效的Withdraw交易,生成多个不同ID的NFT,再利用这些NFT进行退款交易,从而实现“双花攻击”。
- addExitToQueue()会调用_addExitToQueue()铸造一个NFT,NFT的ID是由Plasma Bridge的age优先级生成
- WithdrawManager.verifyInclusion()函数对这样的withdraw交易进行校验,并生成对应的age
- 交易的校验和age的生成过程,都依赖参数data解码出的branchMaskBytes
- 交易的校验过程调用_getNibbleArray()对branceMaskBytes 进行了转码操作。
该函数将对应的HP编码,转成对应的Hex编码。
- 如果传入的HP编码后的值b的第一个十六进制位(半个字节)是1或3,就解析第二个十六进制位。否则,就直接忽略第一个字节。
- 那么如果攻击者构造一个branchMaskBytes参数,使得其第一个十六进制位不等于1和3,则共有14*16 = 224种方式,能够获得相同的转码后的值
1 | Hex转HP |
Meter.io 跨链桥事件
绕过源链上代币的锁定过程,却获得了代币的锁定证明,进而在目标链铸造资产
- deposit()用于ERC20代币的存款,depositETH()用于WETH/WBNB代币的存款。
- Bridge合约提供了两种方法:deposit()和depositETH()用于上述两种代币的存款,但是deposit()并没有阻止WETH/WBNB的存款交易,并且存在有着缺陷的逻辑判断。
当tokenAddress
不为_wtokenAddress
地址时进行 ERC20 代币的销毁或锁定,若为_wtokenAddress
则直接跳过该部分处理.
跨链桥合约中的depositETH
函数会将链平台币转为wToken
后转至depositHandler
地址,所以在depositHandler
执行deposit
逻辑时,已处理过代币转移,故跳过代币处理逻辑
但跨链桥合约的deposit
函数中并没有处理代币转移及校验,在转由deposiHandler
执行deposit
时,若data
数据构造成满足tokenAddress == _wtokenAddress
即可绕过处理
Wormhole Bridge跨链桥事件
利用虚假的签名,在目标链Solana链上mint了12万个WETH。
Wormhole中引入了Validator角色—即guardians
- Wormhole中没有leader角色,所有的guardians都对其监听到的
on-chain event
执行相同的计算,同时对Validator Action Approval
(VAA)签名。 - 若有⅔+的大多数guardian节点使用各自私钥对同一event签名,则在所有链上的Wormhole合约都将自动认为其是有效的,并触发相应的mint/burn操作。
- 攻击者在Ethereum上向Solana转入0.1ETH
- 在Solana上铸造Wormhole ETH的交易触发了Wormhole函数complete_wrapped
- 函数的参数之一是
transfer message
,guardians
签名的消息,说明铸造的代币和数量 transfer message
是通过触发post_vaa
函数创建的,检查guardians
的签名来检查消息是否有效- 实际上
post_vaa
并不检查签名,典型的Solana方式,智能合约通过调用verify_signatures
函数创建 verify_signatures
函数的输入之一是Solana内置的system
程序,- 在
verify_signatures
中调用Secp256k1
签名验证函数 - Wormhole合约使用函数
load_instruction_at
来检查Secp256k1
函数是否被首先调用 load_instruction_at
函数最近被弃用了,因为它不检查它是否针对实际系统地址执行- 攻击者创建自己的账户地址,存储与
Instrcutions sysvar
相同的数据。 - 使用这个伪造的
system
程序,攻击者可以有效地谎报签名检查程序已被执行,但根本没有检查签名
pNetwork跨链协议事件
绕过锁定的过程,攻击者合约发出对应的lock event .错误地提取,处理了恶意的日志事件。
- 攻击者部署了一组专门设计的智能合约,来滥用pNetwork节点寻找的peg-out日志事件。
- 创建一系列的事件日志,包含合法的peg-out请求,和攻击者合约发出了非法peg-out请求。
- 负责提取这些日志事件的Rust代码存在错误,提取并错误地处理了合法和错误的日志。