寻找漏洞:发现并报告Premia Finance中的300万美元漏洞

  • zellic
  • 发布于 2023-09-16 15:10
  • 阅读 10

这篇文章讨论了如何发现和修复区块链项目中的安全漏洞,特别是Premia Finance的一个例子。文章深入探讨了寻找目标、研究方法、发现和修复漏洞的过程,强调了了解项目机制的重要性和不同协议的风险评估。

我是 Ayaz Mammadov,Zellic 的安全工程师。我经常遇到代码中的漏洞。有一天,我在空闲时间浏览项目时,发现了 Premia Finance 的一个有趣的问题——一个未捕获的错误,可能导致数百万美元的资金损失。

虽然现在已经解决,但这个故事为安全工程师发现错误的过程提供了一个有趣的示例。从寻找目标到探索代码库,我们将讨论发现和暴露漏洞所需的步骤,以及 Premia Finance 的漏洞是如何被捕获的。

寻找目标

寻找目标时,有几个因素需要考虑。

平台、生态系统和语言。 这些是寻找目标时最重要的考虑因素。使用不同语言的新平台和不太成熟的平台提供了更多发现安全缺陷的机会——开发者的知识和信心尚未强大,导致更大的出错空间。此外,在较不成熟的平台上寻找漏洞时,竞争较少(由于信息有限和进入门槛高)。拥有丰富领域经验的安全研究人员在新平台上找到错误时具有显著优势。然而,在新平台上也存在劣势:可用项目数远少于其他平台,并且这些项目的总价值锁定(TVL)通常较小。

TVL 范围。 项目的 TVL 越大,漏洞的严重程度往往越高。除了那些明显导致资金损失的关键问题外,即使是被偶尔忽略为用户错误或不太可能发生事件的较不严重的漏洞,其影响也可能深远而分散。当涉及到其他非标准合约/代币(例如 ERC-777)时,情况尤其如此,因为这些代币具有未被考虑到的特殊功能。大型项目通常还会获得来自不同审计公司的更多审计和漏洞悬赏系统,这大大减少了可轻易发现的漏洞。然而,小型项目可能没有审计员的漏洞悬赏。

项目类型及其机制。 加密技术出现在许多领域,无论是视频游戏、赌场、市场/DeFi、NFT 市场、托管系统、混合器、钱包等。在这里,安全研究人员的个人偏好最为重要,因为对特定项目常见陷阱及其与知名 DeFi 项目(例如 Compound、Uniswap)的互动的经验和知识至关重要。这里的权衡显而易见,因为与金融相关的协议通常包含更高的 TVL。相反,其他加密项目可能会包含较低的 TVL,但更多的链上代码行和更高的复杂性,这使得寻找安全缺陷变得更容易。

“Forktasticity”。 这是一个未被公开讨论的话题;它描述了一个项目的分叉程度及其作为其他项目基础的可能性。人们可能会注意到,许多去中心化应用(dApps)是其他热门协议(例如 Compound、AAVE、Uniswap)的变种。这些项目可能只有少数更改,如果安全研究人员已熟悉原始协议及变更可能带来的副作用,则其更改便可以迅速覆盖。相反,它们通常也包含经过广泛审查的代码,不大可能存在问题。这些项目还暴露了机会:当一个漏洞影响一个协议时,通常也会影响其许多分叉。警觉并关注最近新闻的安全研究人员,或者使用像 Zellic 的 Forky↗(即将推出)这样的工具,通常可以利用早鸟的优势来保护其他协议。

发现漏洞的的方法论

探索代码主要有三种方式:关注广度、关注深度和关注速度。

广度优先的安全研究风格依赖于常见的、容易发现的问题,这些问题以类似的方式表现出来。这种方法的优势在于安全研究人员可以快速浏览更多代码,而不必过多考虑开发阶段所采取的基本意图、效果和架构决策。这种类型的安全研究也是无上下文的,意味着它可以在不做笔记、不组装内容时进行。这种安全研究的优势在于可以在任何时间使用,当精力不足和没有多少空闲时间时也可以随时进行。但缺点是,在安全且受欢迎的协议中,很难找到深入的漏洞。

深度优先的安全研究风格则倾向于揭示协议的每个细节及其内部运作,系统性地检查每一行代码并考虑各种后果和可能的利用。这理想上应该是唯一的安全研究风格,因为如果有效实施,能揭示深层、难以捕捉的漏洞。然而,这种风格也存在明显的缺点:如果所研究的协议不够大或不常见,而找不到结果,那么深入思考协议所花费的努力就没有太大价值。这种安全研究风格更适合大项目(例如 Compound、AAVE),因为即使找不到问题,从进行研究中获得的知识也可以很容易地应用于分叉和其他协议。当安全研究人员不可避免地发现之前已经阅读过的代码时,他们将能够更快适应。

最后,可以采用基于速度的方法,安全研究人员注意社交媒体(如 Twitter/Telegram)上的账户,这些账户报告影响流行协议的问题。这些信息可以用于针对类似的分叉或项目,为它们量身定制漏洞。这要求安全研究人员保持最新并保持警觉。

发现协议

寻找协议有多个来源,从网站到社交媒体,再到新闻来源。我个人使用像 DeFiLlama↗ 这样的网站浏览 DeFi 协议,因为它们提供了项目基础上的 TVL 值和平台的信息。其他重要的信息,如以前的审计记录或文档链接,也可以迅速找到。网站 DappRadar↗ 是一个备选方案。许多即将发布的项目不会在任何聚合器上列出,但需要通过社交媒体,如 Twitter 和 Telegram 发掘。

发现漏洞

在空闲时间,我决定打开 DeFiLlama↗。我偏好查看 TVL 超过五百万美元并包含漏洞悬赏的项目。漏洞悬赏是双赢的局面——它们确保协议的安全,同时支持安全研究人士的工作和努力。

我浏览了一些项目,快速查看它们的描述并对项目结构进行了非常简短的概览,以确定我的兴趣。然后,我偶然发现了 Premia Finance。在发现一个新项目时,我查看了它的文档,鸟瞰一下如何运作以及协议的目的。在这种情况下,它是一个基于期权的市场。

首先要查看的是项目结构以确定某些信息:

  • 代码是原创的,还是一个分叉?如果是后者,是否是更改过的分叉代码?

  • 用户调用的最顶层函数是什么?(通常,这些函数是外部的/公共的,但并不总是因为它可以由另一个合约调用,所以要做好交叉引用的尽职调查。)

  • 是否有常见的共享实现(ERC-20 等)?

  • 是否有已经确立实现的事物的自定义实现(自定义 onlyOwnernonReentrant 等)?

漏洞

在探索项目时,我遇到了一个名为 sendFrom 的函数,负责在链之间发送抵押用户的代币。

用户可以授予另一个用户额度,使其能够在不同链之间管理他们的代币。负责这个的函数是_debitFrom_debitFrom 检查调用 sendFrom 的用户是否已被分配了来自 from 地址的额度,如果是,则燃烧要在链上转移的代币。否则,它会 revert。

function _debitFrom(
  address from,
  uint16,
  bytes memory,
  uint256 amount
) internal virtual override {
  address spender = msg.sender;

  if (from != spender) {
    unchecked {
      mapping(address => uint256)
        storage allowances = ERC20BaseStorage.layout().allowances[\
          spender\
        ]; // (1)

      uint256 allowance = allowances[spender]; // (2)
      if (amount > allowance) revert OFT_InsufficientAllowance();

      _approve(
        from,
        spender,
        allowances[spender] = allowance - amount
      );
    }
  }

  _burn(from, amount);
}

问题出现在额度检查中——具体是被检查的额度。当简化时,被检查的额度是 allowances[msg.sender][msg.sender](见(1)和(2)行)。结果,任何用户都可以授予自己额度,从而任意导致将其他用户的代币跨链转移到任意地址。总之,任何用户都可以通过跨链转移窃取其他用户的资金。

影响

在发现这个漏洞时,有价值三百万美元的 Premia 代币跨多条链进行了抵押。所有这些被抵押代币都有被盗的风险。

修复

通过使用 from 地址而非 spender 正确检索 allowances 变量来修复函数。

function _debitFrom(
    address from,
    uint16,
    bytes memory,
    uint256 amount
) internal virtual override {
    address spender = msg.sender;

    if (from != spender) {
        unchecked {
            mapping(address => uint256)
                storage allowances = ERC20BaseStorage.layout().allowances[\
                    from\
                ];

            uint256 allowance = allowances[spender];
            if (amount > allowance) revert OFT_InsufficientAllowance();

            _approve(
                from,
                spender,
                allowances[spender] = allowance - amount
            );
        }
    }

    _burn(from, amount);
}

在这个修复后,如果恶意用户供应了一个未授予额度的 from 地址,检查将确认这一点,因为它将使用 from 地址的额度,而不是 msg.sender 的额度。

结论

我们希望这篇文章关于寻找目标的不同方法、某些协议/项目的优缺点、寻找这些协议的不同来源,以及我们发现的一个示例漏洞是有趣且信息丰富的。

这个故事旨在帮助研究人员优化他们的漏洞猎寻过程。我们鼓励所有安全研究人员积极出击——去保护野外的协议吧!

披露时间线

  • 2023年7月12日——我们与 Premia Finance 团队取得了联系。

  • 2023年7月13日——他们确认了问题并开始修复工作。

  • 2023年7月25日——漏洞悬赏得到了奖励。

  • 2023年7月31日——漏洞被修复,漏洞可以公开披露。

非常感谢 Premia Finance 团队迅速回复我们并及时处理沟通。

关于我们

Zellic 专注于保护新兴技术。我们的安全研究人员在从财富 500 强到 DeFi 巨头的最有价值目标中发现了漏洞。

开发者、创始人和投资者信任我们的安全评估,以快速、有效且无关键漏洞地交付产品。凭借我们在现实世界的攻防安全研究中的背景,我们发现了他人忽视的东西。

联系我们↗,让我们的审计服务超越其他服务。真正的审计,而非橡胶印章。

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

0 条评论

请先 登录 后评论
zellic
zellic
Security reviews and research that keep winners winning. https://www.zellic.io/