跨链桥安全研究(二) | 首次去中心化抢劫Nomad跨链桥事件带给我们什么启发?
摘要: 任何攻击者只需要复制第一个黑客的交易并使用一个未曾使用过的攻击地址将其替换,然后点击通过Etherscan发送,就能盗取项目资金。
*以下仅为安全技术研究,不构成投资建议
欢迎大家来到成都链安出品的“跨链桥安全研究”系列文章,在上一篇文章里(深度 | Web3世界的信任边界,跨链互操作性技术会影响区块链发展的未来吗?),我们详细介绍跨链互操作性技术会影响区块链发展的未来,后面的文章,我们将选取一些出名的跨链桥协议,分析其关键技术,以及可能面临的安全问题。
今天,成都链安安全研究团队将对Nomad跨链桥协议再次进行专业的技术分析,毕竟这个项目曾在8月被黑客攻击,损失约1.9亿美元,本次事件带给我们哪些启发,请继续往下看。
1 _跨链桥Nomad是什么?
首先,我们先来认识本篇文章的主角——Nomad,一种用于区块链之间发送任意消息的互操作性协议。Nomad 自称能提供安全的互操作性解决方案,旨在降低成本并提高跨链消息传递的安全性,与基于验证者的跨链桥不同,Nomad 不依赖大量外部方来验证跨链通信,而是通过利用一种optimistic-rollup机制,让用户可以安全地发送消息和桥接资产。支持以下四种用户:
-
用户:代币桥接
-
资产发行者:多链代币的部署
-
DAO贡献者:跨链治理
-
开发者:跨链应用的开发
Nomad协议包括链上智能合约和链下代理两部分,具体的架构如下图所示:
链上智能合约:
实现了Nomad消息传递API,使开发人员可以将消息按序入列并访问不同链上的复制状态,主要包括Home、Replica合约两部分。其中,Home合约主要负责跨链消息Message的格式化、维护Message默克尔消息树和默克尔树root值队列;Replica合约是所有想要接收跨链消息的区块链都必须部署的,主要负责维护与Home合约对应的默克尔消息树和root值队列、Message的验证和执行。Nomad与其他一对一的跨链通信模型不同,其允许一对N的广播通信。其中,Home合约负责消息生成,而任何希望复制该消息状态或从Home合约接收消息的目标链都必须部署一个与该Home合约对应的Replica合约。
链下代理合约:
跨链的安全和状态中继,形成消息传递层的主干。主要包括:Updater、Relayer、Processor和Watcher。其中,Updater主要负责监听原链上的Home合约,对Home合约生成的新root值进行签名,再生成对应的证明(包括前一个root的证明和新root的证明)并发回;Watcher主要负责保证Updater的安全性,通过监听Updater和Home合约之间的交互,提交Updater的恶意或错误认证;Relayer负责转发Home合约向许多Replica合约发送的update消息;Processor负责验证待处理消息的有效性并将其发送给最终的接收者。
2 _Nomad的互操作性
Nomad采取了 optimistic-rollup 跨链技术,这种optimistic的验证方式不同于其他需要保证大多数节点是诚实的外部验证方式(如:多签、PoS、预言机等),其仅需一个诚实的验证者即可保证整个系统的安全性。
为了实现optimistic验证,Nomad引入了Watchers负责标记链上的欺诈行为。
3 _Nomad如何实现跨链消息传递下图为使用Nomad进行消息传递的流程,以用户Alice使用Nomad Token Bridge将其以太坊账户上的1000 USDC发送到其在Moonbeam上的账户中为例(代币桥接)进行介绍:
1、Alice在以太坊上通过RPC接口(如:Token Bridge GUI或Etherscan)构造一笔交易,这笔交易会调用以太坊上的BridgeRouter合约中的send()函数发起一笔跨链代币桥接交易。其中,BridgeRouter合约由DApp开发人员遵照Nomad Router合约开发规范实现,是用户在原链上进行交互的入口点,必须实现消息的接收和发送功能。下面是Alice调用BridgeRouter合约中send函数的示例。代码地址:
https://etherscan.io/address/0x15fda9f60310d09fea54e3c99d1197dff5107248#code
其中:
-
_token:代币地址
-
_amount:代币数量
-
_destination:目标链所在域,即远程链上的BridgeRouter合约
-
_recipient:接收者地址
下面我们将对代码进行具体介绍。2、以太坊上的BridgeRouter合约将首先执行具体的代币发送逻辑,本例中为:进行输入参数的基本验证,包括:发送的代币数量不能为0,、接收者不能是0地址等。
首先获取跨链交易的目的BridgeRouter合约,如果未获取到则直接revert。接着检查要发送的token是本地链的还是远程链,如果来自本地链上的则将其存储在Router中保管,否则将该远程链上的映射币销毁。注意:BridgeRouter合约可以直接销毁非原生代币,这是因为非原生代币的合约最初就是其部署的。
对要发送的消息进行格式化,使其遵守BridgeMessage合约规范
业务逻辑执行完毕后,BridgeRouter合约会调用Home合约中的dispatch()函数,将要发送的消息写入队列。
3、开始执行Nomad Bridge的核心逻辑
Nomad Bridge通过Home合约对消息进行格式化和哈希处理,并将其插入到默克尔消息树中,其中Merkle树是Nomad的核心数据结构,包含了从该Home发送的所有消息。以下是dispatch()函数的源码:
-
_destinationDomain:目标链所在域,即目标BridgeRouter地址
-
_recipientAddress:接收人地址
-
_messageBody:被BridgeMessage格式化后的消息body
下面将对其进行详细介绍:1)首先校验消息的长度不能超过2K(即2*2**10),接着获取目标域的下一个nonce值并加1,目的是为了防止重放:
2)接着会对消息进行预处理,增加了localDomain、msg.sender、nonce值等数据,再重新进行格式化:
-
localDomain:原链上的BridgeRouter合约所在域
-
_nonce:目标域的nonce值
-
_destinationDomain:目标链上BridgeRouter合约所在域
-
_recipientAddress:接收者在目标链上的地址
-
_messageBody:原始的message消息
3)接着将处理后的消息作为叶子节点插入到消息Merkle tree中:
4)重新生成新的默克尔树的root值,并添加到root值队列中:
5)发送一个Dispatch事件,通知Updater有新的消息,等待其进行签名:
-
_messageHash:被插入默克尔树的message 叶子节点
-
leafIndex:叶子节点在默克尔树的索引,此处为count() - 1,因为新的叶子节点已经被插入到tree中
-
destinationAndNonce:目标域和目标域的nonce值,计算方式为:((destination << 32) & nonce)
-
committedRoot:最后一次签名更新中提交的root值
4、Updater对root值签名
当Updater监测到Dispatch事件后,Updater调用以太坊上Home合约中的update()函数,提交被Updater“公证”后的root值签名,同时更新Home合约中的committedRoot值,并且发布该签名。具体源码如下:
-
_committedRoot:当前被更新过的默克尔root值
-
_newRoot:新的需要被更新的root值
-
_signature:Updater需要对_committedRoot和_newRoot两个值同时进行签名
1)为了防止Updater提交虚假的更新消息,所以函数会首先校验其提交消息的合法性,即_newRoot是否包含在root值列中。如果该值不存在,将对Updater进行slash惩罚。
2)接着删除队列中所有包含在此次更新中的中间root值:
3)使用最新签名的root值更新Home合约中的状态变量committedRoot,并提交Update事件;
5、Relayers将Update消息发送到目标链
一旦Home合约提交了update消息,Relayers会将消息发送到所有的链上与该Home相关的Replica合约中。由于Relayers是不可信的,所以也没有任何特殊权限。它仅仅是调用任意Replica合约中的update()函数更新新的root值,使其与Home合约保持一致。注意:实际上,该函数可以被任何人调用,不只是Relayers。
该函数将首先校验提交的root值是否未更新,如果是则验证_newRoot值的有效性。验证通过,则设置新root值提交的时间(当前的区块时间戳+optimistic欺诈证明时间),最后更新root值。由于Nomad Bridge采取的是optimistic-rollup跨链技术,所以该函数被调用后将开启一个7天争议挑战期,在此期间Watcher可以对更新的root值提出质疑,具体内容见跨链桥系列第一篇文章。
扩展阅读:深度 | Web3世界的信任边界,跨链互操作性技术会影响区块链发展的未来吗?
6、Processor验证和执行Message
在争议期过后,同样不可信和无任何特殊权限的Processor,将调用Replica合约中的prove()函数,通过传入message对应的叶子节点信息、默克尔路径和叶子节点对应的索引去验证message信息的有效性。在本例中,Processor将调用Replica合约中的prove()函数首先证明Alice在以太坊发送的消息是否存在于Merkle树中,如果存在则调用process()函数,该函数会将消息转发到对应的BridgeRouter合约中,再调用其handle()函数执行具体的业务逻辑。
上述prove()函数会首先检查更新的消息是否还未执行,如果还未执行则根据提交的proof计算出对应的root值,将其与更新后的root值进行对比,如果一致代表校验通过。证明Alice确实在原链上发送了该条消息,接着将该验证通过的结果存入messages中,再调用process()函数执行该消息,即该message消息发送到目标链上的对应的BridgeRouter合约中。
该函数会首先校验消息是否是发送到本地BridgeRouter中的,如果是接着验证该消息是否已经被prove()函数证明过。由于process()函数涉及到转账等敏感业务逻辑,所以需要防止其被重入。接着修改消息执行状态为已处理,调用对应的DApp中的handle()业务逻辑,该接口由DApp实现。
7、执行目标DApp handle中的具体业务逻辑
一旦handle()函数在Moonbeam BridgeRouter合约上被调用,BridgeRouter会其所在链上执行业务逻辑。
4 _Nomad安全事件分析
2022年8月2日,据成都链安鹰眼-区块链安全态势感知平台舆情监测显示,跨链通讯协议Nomad遭遇攻击,损失约1.9亿美元。现在我们再来回顾一下。
相关攻击信息,部分攻击交易如下:
被攻击合约:0xB92336759618F55bd0F8313bd843604592E27bd8成都链安安全团队以其中一笔攻击交易(0x87ba810b530e2d76062b9088bc351a62c184b39ce60e0a3605150df0a49e51d0)进行分析:
前文的介绍中我们知道,完整的一次跨链消息传递过程为:
-
用户在原链上调用某一DApp的BridgeRouter合约中的send()函数,该函数会进行简单的参数校验
-
执行Home合约中的dispatch()函数,将其写入消息队列,并发送Dispatch事件
-
Updater监测到事件后,对root值进行签名,并调用Home合约的update()函数更新签名,并发送Update事件
-
Relayers调用Replica合约中的update()函数,将Update消息发送到目标链
-
Processor调用Replica合约中的prove()函数对消息进行校验
-
校验通过,Processor调用Replica合约中的process()函数执行对应业务逻辑
注意:由于Processor是无信任的,所以实际上任何人都可以调用process()函数
由上图调用栈可知,攻击者直接略过了前面跨链消息的传递,直接调用了某一Replica合约的process()函数,成功提取了该Replica合约对应BridgeRouter的金库代币。那么攻击者是如何绕过prove()检测的呢?前面我们分析过,Processor调用prove()函数验证通过后,会将root值写入messages变量中。所以,未经prove()验证的root值对应的messages[root]值为0。但是由下图调用栈可知,acceptableRoot(0)的结果竟然是true。
跟踪到acceptableRoot()函数中:
由上文Nomad源码分析可知,confirmAt[_root]的值用于检测跨链消息是否经过了optimistic欺诈证明时间。此处,由于函数返回true值,所以block.timestamp ≥ confirmAt[0] 且confirmAt[0] 不为0,这代表confirmAt[0]在某处被初始化。Replica合约中存在initialize()函数,具体源码如下:
综上,因为 _root 设置为零 (0x000000....),使得 confirmAt[_root] 等于 1,同时任意区块的timestamp都大于1,导致判断恒成立,攻击者就能提取资金。因此,任何攻击者只需要复制第一个黑客的交易并使用一个未曾使用过的攻击地址将其替换,然后点击通过Etherscan发送,就能盗取项目资金。同时由于存在问题的是Replica合约,所以其对应的所有BridgeRouter相关DApp都会受到影响,因此被盗资表现出多币种的特点。
好了,今天的分享就结束了,下一期,成都链安安全研究团队将介绍另一个跨链项目的安全研究,尽请期待。
作为一家致力于区块链安全生态建设的全球领先区块链安全公司,也是最早将形式化验证技术应用到区块链安全的公司,成都链安目前已与国内外头部区块链企业建立了深度合作;为全球2500多份智能合约、100多个区块链平台和落地应用系统提供了安全审计与防御部署服务。成都链安同时具备全链条打击虚拟货币犯罪和反洗钱技术服务能力,为公安等执法部门提供案件前、中、后期全链条技术支持服务1000+,包括数起进入混币器平台Tornado Cash的案件,成功协助破获案件总涉案金额数百亿。欢迎点击公众号留言框,与我们联系。
评论(0)
Oh! no
您是否确认要删除该条评论吗?