nomad漏洞分析

攻击信息

  • 部分攻击交易 0x96a2cfadb19cac9ba2a21c1f32b6f21b6132afe1b4f4698dee563ca01ec20e01 转移 USDC

0x811a54270e38154c30e65bdb8ee484883f5a9659dd16f1a335f9ff8f7eee342f 转移 WETH

0x12efbc03ecc8d56ebbadd637dbfc30c0d709b463e2c831034233427dfaecf777 转移 FRAX

0xc78bc10c77ca92693513e5b97b4a0063167ca8488b019f6b740bc9f8cad103bf 转移 CQT

0x8c65b2b25be2c929d86f1fb556aa0b981bd54c2ad54d8de63d3876c4c833293e 转移 DAI

0x5304e01a4cb926523f681bc34a8b71a1dfae35b5a5159f78aecc7f685f42422c 转移 CARDS

  • 被攻击合约

0xB92336759618F55bd0F8313bd843604592E27bd8 Replica

漏洞分析

漏洞关键点为process中的这一行

require(acceptableRoot(messages[_messageHash]), "!proven");

这里acceptableRoot的输入为0x0000000000000000000000000000000000000000000000000000000000000000

难道这个函数结果是否返回true?可以绕过require判断嘛?带着疑问跟进acceptableRoot函数

这里_root肯定是不满足这两个条件

bytes32 public constant LEGACY_STATUS_PROVEN = bytes32(uint256(1));

bytes32 public constant LEGACY_STATUS_PROCESSED = bytes32(uint256(2));

关键是这个_time只要不等于0就行。那么要跟进confirmAt[_root]

全局搜索confirmAt发现在initialize中有赋值操作。

那我们要看看这个_committedRoot是个啥? 时间回到41天之前,在这个交易中 Ethereum Transaction Hash (Txhash) Details | Etherscan

_committedRoot就是我们上面的000000。那么上面的_time满足条件。不为0。acceptableRoot也会返回true。从而绕过这个require

惊天魔盗,近2亿美金损失!Nomad Bridge攻击事件分析 (qq.com)

速评:连黑客技术都没用到 Nomad 就「倒下」了 (jinse.com)

Last updated