Uniswap 重入漏洞披露

  • Dedaub
  • 发布于 2022-12-17 11:27
  • 阅读 11

Dedaub 团队发现了 Uniswap UniversalRouter 中的一个重入漏洞,该漏洞允许恶意接收者在交易过程中重新进入合约并窃取资金。通过提交漏洞报告,Dedaub 团队获得了 Uniswap 的漏洞赏金。该漏洞的根本原因是 UniversalRouter 在处理多个连续操作时,未对接收者进行可信度验证,导致恶意接收者可以利用重入漏洞窃取不应属于他们的资金。

YANNIS SMARAGDAKIS

Uniswap 重入漏洞披露

Dedaub 团队提供

Uniswap 重入漏洞披露

Uniswap 重入 | Uniswap Labs 最近为其智能合约的漏洞报告宣传了一项高达 300 万美元的奖励计划,尤其是新的 UniversalRouterPermit2 功能。我们提交了一份漏洞报告并收到了赏金——谢谢!据我们所知,我们的报告是 Uniswap 采取行动的唯一一份(即,显然是唯一一份导致对智能合约代码的提交修复UniversalRouter 的新部署 的报告)。

对这个问题的解释非常简单,所以我们首先提供漏洞报告的原文。

显然,UniversalRouter 在交易之间不应持有任何余额,否则这些余额可能被任何人清空(例如,通过使用 Commands.TRANSFERCommands.SWEEP 调用 dispatch)。

当与不受信任方在用户交易过程中获得控制权的任何可能性结合时,此属性非常危险。例如,在 Uniswap 池中存在受污染的 ERC20 代币,或者来自代币转账的回调(例如,721s)时,可能会发生这种情况。例如,简单的攻击场景:用户将资金发送到 UniversalRouter 并使用 3 个命令调用它:

1) Commands.V3_SWAP_EXACT_IN,交换为特定代币

2) Commands.LOOKS_RARE_721(或大量触发接收者回调的命令中的任何一个),购买 NFT,将其发送给 recipientX

3) 将购买后剩余的金额转移给原始调用者。

在这种情况下,recipientX 可以轻松地重新进入合约(通过在其 onERC721Received 处理程序中调用 transfersweep)并耗尽全部金额,即步骤 3 的金额。

本质上,UniversalRouter 是一种用于所有类型的代币转账、交换和 NFT 购买的脚本语言。通过提供正确的命令序列,可以连续执行多个操作。这些命令可能包括转移到不受信任的接收者。在这种情况下,很自然地期望转移应该只将调用参数指定的金额发送给接收者,而不能多发送。

但是,这并不总是会发生。如果在转移过程中的任何时候调用了不受信任的代码,该代码都可以重新进入 UniversalRouter 并声明 UniversalRouter 合约中已有的任何代币。例如,之所以存在这些代币,可能是因为用户打算稍后购买 NFT,或者将代币转账给第二个接收者,或者因为用户交换了比需要的金额更大的金额,并打算在 UniversalRouter 调用的末尾将剩余的金额“转移”给自己。并且不乏可能调用不受信任的接收者的场景:WETH 解包触发回调,有些代币会执行回调,并且代币本身可能是不受信任的,当其函数被调用时会执行任意代码。

我们的概念验证演示了一个简单的场景:

附加了两个文件。一个是你的 foundry 测试文件 universal-router/test/foundry-tests/UniversalRouter.t.sol 的替换(略有添加)。另一个应该放到“mock”子目录中。如果然后你运行你的标准 forge test -vvv,你将看到相关测试的输出:

======

[PASS] testSweepERC1155Attack() (gas: 126514)

Logs:

1000000000000000000

======

最后一行是来自攻击者的 console.log,显示她获得了 erc20 代币的余额,尽管她只被发送了一个 ERC1155 代币。

测试用例很简单:

function testSweepERC1155Attack() public {
 bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.SWEEP_ERC1155)));
 bytes[] memory inputs = new bytes[](1);
 uint256 id = 0;
 inputs[0] = abi.encode(address(erc1155), attacker, id, 0);

 erc1155.mint(address(router), id, AMOUNT);
 erc20.mint(address(router), AMOUNT);

 router.execute(commands, inputs);
}

也就是说,攻击者正在被发送一个 erc1155 代币数量,但路由器也有一个 erc20 代币数量。(实际上,这可能是由于其他转移,稍后发生。)攻击者设法窃取了 erc20 数量。

我们建议的补救措施很简单:

… 添加一个 Uniswap 重入锁,尽管不优雅:在调度命令的过程中不调度命令。

我们立即得到确认,该问题正在被检查,并将被评估以获得奖励。几周后,我们收到了赏金评估:

我们想奖励你一次性的 40,000 美元赏金(以 USDC 支付),以表彰你的贡献。该金额包括报告的 30,000 美元赏金,以及在当前奖金期间报告该问题的 33% 奖金。我们将该问题归类为中等严重程度,并感谢你帮助我们提高用户和整个 web3 生态系统的安全性。

进一步的沟通表明,该漏洞被评估为具有高影响和低可能性:用户直接将 NFT 发送给不受信任的接收者的可能性(尽管存在于 UniversalRouter 单元测试中)被认为是“用户错误”。因此,只有更复杂(且可能性更小)的场景才被认为是 Uniswap 重入的有效场景,从而导致“低可能性”评级。

我们要感谢 Uniswap Labs 的赏金,并很高兴能够提供帮助!

  • 原文链接: dedaub.com/blog/uniswap-...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Dedaub
Dedaub
Security audits, static analysis, realtime threat monitoring