争分夺秒的策略:关于AnySwap救援及其启示

AnySwap智能合约攻击紧急救援行动的关键洞察与DeFi安全经验教训。

争分夺秒的策略:关于AnySwap救援及其启示

1月18日,我们的监控系统检测到针对AnySwap项目(也称为Multichain)的攻击。该漏洞源于anySwapOutUnderlyingWithPermit()函数存在缺陷,其验证机制可以被绕过以提取已授权的代币。

尽管项目已经采取了不同的措施(例如,向用户发送交易,如图1所示)来通知受影响的用户,但仍有部分用户未能及时采取行动(即撤销授权)来保护其资金。因此,攻击者可以持续发动攻击以获取受害者的资金。

图1:项目通过以太坊消息通知受害者

为了保护潜在的受害者,经过深思熟虑,我们的团队决定对以太坊上的AnySwap易受攻击的合约(0x6b7a87899490EcE95443e979cA9485CBE7E71522)执行紧急救援。具体来说,我们可以将易受攻击账户的资金转移到我们的白帽钱包,这是一个位于以太坊上的多重签名钱包(0xd186540FbCc460f6a3A9e705DC6d2406cBcc1C47)。

为了使我们的白帽救援透明化,我们将我们的意图记录在一个PDF文件中,并与社区分享文件哈希。这可以区分我们的紧急救援和攻击,同时不泄露细节(因为漏洞仍然可以被利用)。我们从2022年1月21日开始,到2022年3月11日结束了紧急救援,并发布了相应的公开消息,如下所示:

图2:我们执行救援的公告
图3:停止救援的公告

紧急救援并非易事。事实上,要成功进行救援,存在着技术和非技术方面的挑战。随着紧急救援的结束,我们可以全面回顾整个过程,并分享我们学到的经验教训。我们相信这次经历可以为DeFi生态系统的安全提供一些启示。

主要收获(TL;DR)

  • 不同参与者之间存在竞争,包括白帽和攻击者。Flashbots的支付费用随着时间的推移迅速增加。
  • Flashbots并非总是奏效。相反,一些攻击者通过采用一些复杂的策略,转向使用普通内存池来成功发动攻击。
  • 一些攻击者通过归还部分被盗资金而被“洗白”,其余部分作为赏金。这种现象虽然不是第一次出现,但在社区中颇具争议,因为这种激励机制可能对真正的白帽不公平。
  • 为了赢得社区的信任,白帽最好提前公开其行动,而不泄露任何详细的敏感信息
  • 社区可以共同努力,更有效、更高效地进行救援。例如,建立协调机制以减少/避免白帽之间的竞争。

接下来,我们将首先介绍此期间救援的整体情况。然后,我们将阐述我们的救援方式以及需要解决的挑战。之后,我们将讨论从救援中吸取的一些教训。最后,我们将提供一些可能对保障生态系统安全有意义的想法/建议。

0x1 救援与攻击

0x1.1 总体结果

本报告中观察和调查的攻击和救援活动持续了数月,从区块14028474(2022年1月18日)到区块14421215(2022年3月20日)。

执行救援和攻击的账户总结在下表中。为简洁起见,仅给出地址的前四位以代表一个EOA。 一个账户要么是救援账户,要么是攻击账户。值得注意的是,账户的类型是根据Etherscan.io的标签或我们观察到的转移目的地地址来确定的。

总共有9个救援账户,共计救援了483.027693 ETH(支付费用295.970554 ETH,占总金额的61.27%),以及21个攻击账户,共计获利1433.092224 ETH(支付费用148.903707 ETH,占总金额的10.39%)。值得注意的是,损失是粗略估计,因为存在一些复杂的交互。例如,一个攻击账户在与AnySwap协商后可能转变为救援账户,这一点我们将在后面讨论。表格的最后一列显示了支付给矿工的费用,这些费用用于赢得Flashbots的竞争。

编号 账户 类型 受害者数量 损失金额(ETH) 费用金额(ETH)
1 0x14ca** 救援账户 50 432.958062 287.849654
2 0x9a65** 救援账户 23 22.569429 0.000000
3 0x9117** 救援账户 14 18.897622 7.213585
4 0x17d2** 救援账户 3 3.552833 0.000000
5 0x6360** 救援账户 21 3.540061 0.907168
6 0x0edd** 救援账户 7 1.498706 0.000000
7 0x281e** 救援账户 1 0.006000 0.000000
8 0xd83b** 救援账户 1 0.004000 0.000000
9 0x8af3** 救援账户 6 0.000980 0.000147
10 0x4986** 攻击账户 332 456.004547 0.000000
11 0xfa27** 攻击账户 42 433.438935 46.636389
12 0x48e9** 攻击账户 66 312.014657 0.000000
13 0x5738** 攻击账户 67 83.589240 62.587238
14 0x34b2** 攻击账户 7 63.599821 20.642705
15 0xd374** 攻击账户 86 45.452703 12.824763
16 0x1fe7** 攻击账户 9 12.817241 0.000000
17 0x98f5** 攻击账户 20 8.381273 0.000000
18 0x455d** 攻击账户 11 5.047377 0.544263
19 0x1b45** 攻击账户 6 4.942442 3.074813
20 0x3ec7** 攻击账户 6 3.705686 0.741137
21 0xbca4** 攻击账户 1 2.784250 1.392125
22 0xb0ab** 攻击账户 18 0.834068 0.296000
23 0x0a5b** 攻击账户 1 0.286750 0.143375
24 0x2d3a** 攻击账户 2 0.080090 0.000000
25 0x835d** 攻击账户 5 0.063945 0.000000
26 0x1dbd** 攻击账户 1 0.027431 0.012893
27 0x813d** 攻击账户 1 0.019528 0.008007
28 0x85dd** 攻击账户 6 0.002240 0.000000
29 0x2394** 攻击账户 1 0.000000 0.000000
30 0x6360** 攻击账户 2 0.000000 0.000000

0x1.2 竞标Flashbots的费用趋势

如前所述,白帽需要与攻击者竞争以发送交易。因此,支付给矿工的费用百分比(在Flashbots交易中)可能反映了竞争的程度。为了量化这一点,我们调查了每个区块的费用百分比(分别包括攻击交易和救援交易)。

图4显示了我们迄今为止观察到的趋势(从区块14028474到区块14369199)。 最初的几次攻击交易均不涉及任何费用,这意味着在此期间的竞争很少(甚至没有)。这是合理的,因为这些早期攻击可能不为外界所知。

事实上,第一次涉及费用的攻击(10%)发生在区块14029765。 从那时起,随着更多参与者的加入,费用百分比迅速增加。 例如,在区块14072385,百分比达到80%,并在区块14129449很快达到91%。

简而言之,这种趋势表明,通过增加支付给矿工的费用来进行竞标,无疑是一场军备竞赛。

图4:攻击和救援的费用百分比

0x2 我们的救援与挑战

0x2.1 救援方式

进行救援的基本思路非常直接。具体来说,我们需要监控已授权WETH给易受攻击合约的账户。当有任何WETH转移到账户时,我们可以通过利用易受攻击的AnySwap合约将其直接转移到我们的多重签名钱包。关键要求是:

  • R1:有效定位向受害者账户转入代币的交易。我们将其称为转账交易
  • R2:正确地构建执行救援的交易。我们将其称为救援交易
  • R3:成功地抢跑攻击者(及任何其他第三方)发送的交易。我们将其称为攻击交易

R1和R2对我们来说都不是障碍。具体来说,我们已经构建了一个内部系统来监控内存池,这使我们能够及时定位转账交易。同时,我们还开发了一个工具来自动构建交易。

然而,R3仍然是一个挑战。人们可能期望Flashbots能用于赢得竞争。然而,要达到目标并非易事。首先,攻击者也可能使用Flashbots。作为一个费用竞价系统,成功率可能取决于支付给矿工的费用。需要确定设置费用的策略。其次,由于竞争激烈,使用Flashbots可能不是一个好选择。因此,我们也通过普通交易使用内存池。为确保成功,需要考虑将交易放置在正确位置的策略。最后,我们还与其他白帽竞争,他们的行为在某些情况下似乎是可疑的

0x2.2 我们参与的竞争

总的来说,我们尝试保护了171位潜在受害者,其中10位在我们将要执行救援之前通过撤销授权自行保护了自己。对于剩余的161位有效受害者,由于竞争,我们只成功救援了14位。失败案例总结如下表,涉及3个救援账户和16个攻击账户。

编号 账户 类型 受害者数量 损失金额(ETH) 费用金额(ETH) 平均费用百分比
1 0x14ca** 救援账户 44 431.651020 286.891724 66.46%
2 0x9a65** 救援账户 7 11.321441 0.000000 0.00%
3 0x6360** 救援账户 3 3.300000 0.891000 27.00%
4 0x48e9** 攻击账户 35 301.681589 0.000000 0.00%
5 0x5738** 攻击账户 58 78.482472 58.851862 74.99%
6 0x34b2** 攻击账户 2 53.591712 17.685265 33.00%
7 0xd374** 攻击账户 6 23.658698 10.073638 42.58%
8 0x4986** 攻击账户 16 22.900105 0.000000 0.00%
9 0x1fe7** 攻击账户 6 12.057241 0.000000 0.00%
10 0x1b45** 攻击账户 5 4.402442 3.010013 68.37%
11 0xbca4** 攻击账户 1 2.784250 1.392125 50.00%
12 0x98f5** 攻击账户 8 2.339543 0.000000 0.00%
13 0x455d** 攻击账户 3 0.741817 0.175454 23.65%
14 0xfa27** 攻击账户 3 0.320288 0.032590 10.18%
15 0x0a5b** 攻击账户 1 0.286750 0.143375 50.00%
16 0x3ec7** 攻击账户 1 0.245000 0.049000 20.00%
17 0xee7e** 攻击账户 1 0.190000 0.096900 51.00%
18 0x835d** 攻击账户 3 0.024533 0.000000 0.00%
19 0xb0ab** 攻击账户 1 0.000618 0.000000 0.00%

因此,确实有一些经验教训值得与社区分享。

0x3 我们学到的一些经验教训

0x3.1 如何确定支付给Flashbots矿工的费用?

总而言之,我们被12名竞争对手击败,其中包括2名救援账户和10名使用Flashbots的攻击账户。

我们设置矿工费用的策略相当保守。具体来说,我们的目标是以尽可能少的费用来保护受害者。因此,除非有成功的攻击交易已经设定了费用,否则我们不会主动使用/提高费用。例如,如果一个攻击者将费用设定为基金的10%,那么我们可能会使用11%来进行下一次救援,以与该攻击者竞争。然而,结果表明,该策略未能奏效,因为攻击者(甚至一些白帽)经常(如果不是总是)积极提高费用以击败他人,如下所示:

  • 图5显示,攻击者0x5738**在区块14071986将费用百分比设定为70%。
  • 图6显示,白帽0x14ca**在区块14072255将费用百分比设定为79%。
  • 图7显示,白帽0x14ca**在区块14072385将费用百分比设定为80%。
  • 图8显示,白帽0x9117**在区块14072417将费用百分比设定为81%。
  • 图9显示,攻击者0x5738**在区块14073395将费用百分比设定为86%。
图5:攻击者0x5738设定的70%费用
图6:白帽0x14ca**设定的79%费用
图7:白帽0x14ca**设定的80%费用
图8:白帽0x9117**设定的81%费用
图9:攻击者0x5738**设定的86%费用

简而言之,这似乎是一个零和博弈,需要模拟不同参与者的行为才能获胜。

然而,在实践中,很难找到更好/最优策略,同时尽可能降低成本。

0x3.2 如何在内存池中找到正确的位置?

现在看来,救援似乎依赖于费用竞标Flashbots的军备竞赛。 然而,我们发现,由于与其他与救援和攻击无关的参与者之间的激烈竞争,使用Flashbots并非万能药。在这种情况下,即使是攻击交易设定的最高费用也不能保证赢得使用Flashbots的机会。

另一种选择是,一笔普通交易在内存池中占据正确的位置也有机会实现目标。正确的位置意味着救援/攻击交易应放置在转账交易之后,并且位置应非常接近转账交易(越近越好)。请注意,使用此策略,攻击者0x48e9**获得了312.014657 ETH,而无需向Flashbots矿工支付任何费用。

以下四张图展示了攻击者获得的最大的两个利润:

  • 图10显示,一个受害者在区块14051020的第65个位置存入了50 ETH,图11显示,攻击者在同一区块的第66个位置获得了这50 ETH。
  • 图12显示,一个受害者在区块14052155的第161个位置存入了200 ETH,图13显示,攻击者在同一区块的第164个位置获得了这200 ETH。
图10:受害者0x3acb**发送的转账交易(位置65)
图11:攻击者0x48e9**发送的攻击交易(位置66)
图12:受害者0xbea9**发送的转账交易(位置161)
图13:攻击者0x48e9**发送的攻击交易(位置164)

显然,这种复杂的策略非常有用且富有启发性,值得我们付出更多关注和努力去学习。

0x4 其他一些想法

0x4.1 白帽黑客还是攻击?

在识别白帽黑客时,它们可能不像人们预期的那样直接。

例如,地址0xfa27被Etherscan.io标记为Multichain Exploiter 4 (Whitehat)。实际上,最初它被标记为Multichain Exploiter 4。在攻击者和AnySwap项目进行了几轮谈判后,攻击者被说服归还了部分被盗资金。

  • 在交易0x3c3d**中,AnySwap联系了攻击者:

首先,感谢您获得了weth。我当时并不知道这次攻击,直到weth从未到达我的钱包时才意识到情况。考虑到涉及的金额,您是否愿意接受50 ETH作为合理的报酬? 这是我的交易: 0x2db9a6a51604e2be8b2c3469773afb201f0b48a318fb7e5f5e49175e818df5ba 0xe50ed602bd916fc304d53c4fed236698b71691a95774ff0aeeb74b699c6227f7

  • 在交易0xd360**中,攻击者回复道:

请通过发送一笔交易来验证。我将把剩余的258 ETH还给您。39 ETH已支付给矿工,因为有其他攻击者,所以我不得不支付这笔费用来保住资金。

  • 在交易0x354f**中,AnySwap在收到资金后表示感谢:

已收到,感谢您的诚实。

显然,这位攻击者被“洗白”了,并且从攻击中还获得了一些利润。 类似的情况过去已经发生过几次,并且在社区中仍然存在争议,因为这种激励机制可能不公平。

0x4.2 白帽黑客之间的竞争?

有必要建立一个协调机制来减少/避免白帽之间的竞争。这种竞争不可避免地导致救援力量的浪费。 在此次救援中,有54位受害者(价值4.5亿ETH的资金)由另外三位白帽保护,而我们也试图进行救援。

白帽之间的竞争不仅浪费了救援力量,还增加了执行救援的成本。例如,如图7和图8所示,两笔不同白帽的救援交易花费的费用分别为80%和81%。

不幸的是,除非存在协调机制,否则白帽不会退让。否则,就不可能消除竞争。

0x4.3 如何进行更好的救援

一方面,为了赢得社区的信任,白帽最好提前公开其行动,而不泄露任何详细的敏感信息。 由于救援通常是一场反复的拉锯战,与一次性阻止特定攻击不同,有足够的时间进行公开。当然,关于漏洞的详细信息不应被泄露。

为了实现这一点,详细信息不会在第一时间披露,而是在完成救援后向社区披露,就像我们为AnySwap救援所做的一样。但是,包含白帽意图的文档的哈希可以与社区共享。

另一方面,社区可以做更多的事情来更有效、更高效地执行救援,包括但不限于:

  • Flashbots/矿工可以为认证的白帽提供绿色通道。绿色通道可以提供高优先级来抢跑攻击者的交易,并避免白帽之间的竞争。
  • 被攻击的项目应承担Flashbots/矿工的费用。
  • 项目方可以为用户应用便捷快速的通知机制。
  • 项目方可以在代码中应用紧急机制。

关于BlockSec

BlockSec是一家开创性的区块链安全公司,成立于2021年,由一群全球知名的安全专家组成。公司致力于提升新兴Web3世界的安全性和可用性,以促进其大规模采用。为此,BlockSec提供智能合约和EVM链安全审计服务,用于主动安全开发和威胁拦截的Phalcon平台,用于资金追踪和调查的MetaSleuth平台,以及用于Web3开发者高效浏览加密世界的MetaSuites扩展。

迄今为止,公司已服务超过300家知名客户,如MetaMask、Uniswap Foundation、Compound、Forta和PancakeSwap,并在两轮融资中获得了来自Matrix Partners、Vitalbridge Capital和Fenbushi Capital等知名投资者的数千万美元投资。

官方网站:https://blocksec.com/ 官方Twitter账号:https://twitter.com/BlockSecTeam

Sign up for the latest updates