EVM 任意调用审计要点

本文探讨了智能合约审计中任意调用(Arbitrary Calls)的风险,指出合约若存在任意调用,则不应包含 transfer/transferFrom/approve 等操作,否则可能导致代币被盗。文章还列举了需要检查的要点、安全假设以及应对措施,强调了防范利用任意调用漏洞的重要性。

Image

任意调用审计技巧

总体思路:如果一个合约有任意调用,它通常不应包含 transfer/transferFrom/approve 调用。如果合约中存在这样的调用,则意味着 合约 存储了 tokens 或对它们的授权。因此,它们可以通过对 token 合约的任意 调用来窃取。

以下是我们的审计笔记,从中你将学习到我们是如何想到这种检测器的,以及它实际上是什么。务必仔细学习它们!

任意调用分解

  • 调用自定义地址;

  • 调用任意 calldata。

你需要检查什么

  • 你可以插入 token 的地址并调用 transfer/transferFrom/approve 函数;

  • 你可以获得特权访问权限;

  • 你可以执行一个 重入攻击

  • 其他(订单填充、奇怪/非典型的 staking 等)

安全假设

  • Solidity 为 调用 其他合约中的函数提供了便捷的高级语法,但只有在编译时知道目标合约的 接口 时,此高级语法才可用,在此处阅读更多

  • 恶意合约可能会提取合约对任意 地址 的外部调用后的余额,从而导致资金损失。由于此缺陷,攻击者 可以利用合约的 能力 来发挥自己的优势,并运行 恶意 或未经授权的代码,这些代码可以从合约中提取资产或破坏合约的工作机制,在此处阅读更多

需要特别注意

  • 在我们的审计中,我们看到了不同的方法,例如 ActionOnBehalfOf——它们需要各种批准,但允许你管理其他人的 staking 资金。这是一件非常罕见的事情,需要特别注意!

  • 除了通常的 transfer、transferFrom、approve 之外,还需要将 call 脚本/场景检查到同一个合约中;例如,在其中一个项目的代码中,有 token staking (transferFrom(msg.sender, address(this), x)),但是当 withdrawal 时,可以指定接收者并 withdraw 到那里!

  • 代表合约本身调用。例如,你可以进入“受保护的”代码(绕过访问控制)3+4。你可以调用自己来使 msg.sender == this。例如,transferFrom(msg.sender, this, N);

  • Transfer 和 approve 可能允许从合约的余额中 withdraw tokens。而 transferFrom 可能允许你窃取其他人的 tokens(使用对此合约的授权)。

你应该做什么

  • 如果可能,不要使用 任意 调用;

  • 如果有任意调用,合约不应存储 token approve;

  • 最好创建一个层,将 approve 提供给该层,并将必要的 tokens 传递给路由器;

  • 可以选择使该层 可暂停 或添加 selfdestruct;

  • 尽量减少“最后一刻”的编辑!

  • 尝试过滤用户提供的函数签名!

调用“自定义”地址

  • 通过 C1 合约中的任意调用,可以调用 C2,C2 关心是 C1 调用了它。这绕过了 C2 中的 msg.sender 检查。例如,假设有一个由两个合约 C1 和 C2 组成的系统:

a) C1.foo() 进行任意调用(除了可能还有其他操作); b) C1.bar() 进行各种检查并调用 C2.xyz (); c) C2.xyz() 做一些非常重要的事情,并且受到 onlyC1 的保护,然后来自 C1.bar () 的检查可以通过 C1.foo ()-> C2.xyz () 绕过(onlyC1 不会注意到这个技巧;

  • 如果合约 A 在合约 A 上有资产(ether 或 tokens),并且合约 A 对“用户”合约 B 进行 delegatecall,则合约 B 可以从合约 A 的资产负债表中 withdraw 资产;

  • 我们不能排除没有 tokens,但有原生货币的情况。如果项目位于特定的链上,其中原生货币是预编译的合约(例如 Moonbeam 和 MOVR & GLMR tokens),那么也可以对其执行 delegatecall。漏洞示例

  • 在合约代码中使用 fallback()-function 应该非常小心。因此,存在没有 revert 和条件的 fallback()-function 允许为此合约执行任何签名不在合约源代码中的函数(可能是恶意的);

  • 潜在的 DoS:该地址可以简单地丢弃或“吃掉”所有 gas,调用合约不应因此而以某种方式滞后或冻结(与状态机模式相关)。也与 .send().transfer() 相关。;

  • 对欺骗地址的 Delegatecall 可以删除调用合约或完全破坏存储;

  • 从 0.5 开始,编译器会插入对被调用地址的检查(它是 合约而不是 EoA)。但是对于底层调用(.call、.delegatecall 等)和汇编,没有这样的检查。调用非合约地址不会产生任何错误,但逻辑甚至不会启动。

最初发布于 此处

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

0 条评论

请先 登录 后评论
officer_cia
officer_cia
江湖只有他的大名,没有他的介绍。