分析基本法–如何快速上手一个被黑事件

区块链安全 1年前 (2023) admin
377 0 0

前言

昨天,一个风和日丽的中午,突传 cowSwap 被黑,作为奋斗在一线的辛勤打工仔,以必须先让老板跑了再说宗旨。自然是需要第一时间介入分析加各种预警。无奈手头工作太多,时间又紧迫,被迫祭出很久没用的快速分析大法来快速上手事件分析。本文分享一些用于快速分析事件的思路,希望大家下次遇到同样问题的时候可以及时快速响应。

How to 时间

分析基本法--如何快速上手一个被黑事件

首先,一般安全事件的第一来源都是一些安全公司。通过安全公司的简单介绍,其实就可以大概知道这件事情的来龙去脉。以这次为例。我第一时间接收到的消息是来自 PeckShield, 从推文的介绍来看,这次被黑原因就是因为 CowSwap  GPV2Settlement 合约将 DAI 无限授权给了一个叫 SwapGuard 的合约,然后该合约得到授权后利用授权转走了 GPV2Settlement 的钱。OK 那么我们看到这段描述。我们就大概清楚了。是合约授权给合约导致了资金损失。所以到这里分析方向就变成了 为什么合约会授权给这个合约?。知道方向之后,很明显就自然能想到2个可能的解。分别是 

  1. 合约有一个专门的函数用于设置授权的,可能 cowSwap 合约的管理员设置了一个恶意的合约但是不知道

  2. 合约存在任意调用接口,通过这个接口把代币授权给了外部合约

知道解了之后,我们就要开始分析究竟是哪一个。通过 Peckshield 官方,提供了一个 GPV2Settlement 授权给外部合约的调用图,是这样的 

分析基本法--如何快速上手一个被黑事件

从图中我们不难发现其实这个授权操作的入口函数其实是在  GPV2Settlement  settle 函数中。到这里,如果不看代码,就可以得出推论 — 合约有一个专门的函数用于设置授权的,可能 cowSwap 合约的管理员设置了一个恶意的合约但是不知道,特别是在 settle 函数这个名字上,也会让人觉得:没错,就是这样。

但是做安全工作要的就是细致严谨,我们翻一下这个函数的逻辑, 如下:

function settle(
IERC20[] calldata tokens,
uint256[] calldata clearingPrices,
GPv2Trade.Data[] calldata trades,
GPv2Interaction.Data[][3] calldata interactions
) external nonReentrant onlySolver {
executeInteractions(interactions[0]);

(
GPv2Transfer.Data[] memory inTransfers,
GPv2Transfer.Data[] memory outTransfers
) = computeTradeExecutions(tokens, clearingPrices, trades);

vaultRelayer.transferFromAccounts(inTransfers);

executeInteractions(interactions[1]);

vault.transferToAccounts(outTransfers);

executeInteractions(interactions[2]);

emit Settlement(msg.sender);
}

从函数逻辑中,貌似继续维持上面轻而易举得出的结论好像也是可以的,就是一个设置函数嘛。。但是这里注意到了一个点,就是 vaultRelayer.transferFromAccounts(inTransfers);。当你看到这个逻辑的时候同时结合这是一个 DEX Router,就可以清楚的明白这里是一个兑换函数。

OK,那么到这里,先前得出的结论就已经被否决了,最后就只剩下–合约存在任意调用接口,通过这个接口把代币授权给了外部合约 这个结论了。再次分析函数逻辑,发现 executeInteractions 子函数。根据结论反推,这个子函数很可能可以执行任意代码,直接看逻辑

function executeInteractions(GPv2Interaction.Data[] calldata interactions)
internal
{
for (uint256 i; i < interactions.length; i++) {
GPv2Interaction.Data calldata interaction = interactions[i];

// To prevent possible attack on user funds, we explicitly disable
// any interactions with the vault relayer contract.
require(
interaction.target != address(vaultRelayer),
"GPv2: forbidden interaction"
);
GPv2Interaction.execute(interaction);

emit Interaction(
interaction.target,
interaction.value,
GPv2Interaction.selector(interaction)
);
}
}

分析了函数逻辑后,可以发现 executeInteractions 没有对 interactions 数据做任何检查。然后直接就到了 GPv2Interaction.execute(interaction);。基本可以确定就是任意调用的问题了,但是其实这里还需要再去看 GPv2Interaction  execute 函数确认真的没有任何检查,结论才是靠谱的。但是这里为了节约篇幅,我直接告诉你就是靠谱的 😀

OK。一波操作下来,问题就已经快速定位完了,整个过程用了不到10分钟,多快好省。接下来就是报告给老板了 ;D

一些收尾问题

除了定位问题之外,还要评估影响和把整个攻击流程走通,上面虽然定位到了问题的原因,但其实还剩下2个问题

  1. settle 函数是有调用者限制的

  2. 被黑的资金从那里来,为什么合约里头有钱?

篇幅原因,这里简单讲讲思路。

回答第一个问题有利于评估影响,即攻击会不会持续。答案也很简单,就是直接看这个 onlySolver 的限制,是 EOA 地址还是多签,EOA的话比较难搞,因为涉及到私钥被黑的问题。如果是多签的话,就好点。这里 solver 是一个 EOA 地址,由于我之前有了解过一点 cowSwap ,结合一些前置知识,我知道这个 solver 其实只是用于转发交易兑换数据而已,所以其实只要 solver 服务下线,攻击就停止了。

回答第二个问题有助于走通整个攻击流程,即黑的是什么钱?答案的话其实需要一点联想。已知这是一个 DEX Router合约,求解为什么 DEX Router 合约里头有钱?答案也是显而易见,就是兑换时收的手续费。怎么证明这个猜想呢?也很简单,直接去找经过合约的兑换交易,放到交易分析器里头,看看兑换子流程中资金从开始兑换到真正去到对应的 DEX (e.g. Uniswap) 的时候,资金是否存在减少,如果少了,那么就肯定是收了手续费了

结尾

以上就是一些快速分析的经验分享,晚上的时候,cowSwap 自己也发时候分析了,只能说和我的分析,大差不差了 😀


分析基本法--如何快速上手一个被黑事件



分析基本法--如何快速上手一个被黑事件


原文始发于微信公众号(蛋蛋的区块链笔记):分析基本法–如何快速上手一个被黑事件

版权声明:admin 发表于 2023年2月8日 下午6:44。
转载请注明:分析基本法–如何快速上手一个被黑事件 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...