大数跨境

监守自盗?Wintermute黑客入侵分析

监守自盗?Wintermute黑客入侵分析 FastDaily
2022-09-30
2
导读:黑客很可能是Wintermute团队的内部成员。

本文属于老雅痞原创文章,转载规矩不变,给我们打声招呼~

转载请微信联系:yaoyaobigc,更多DAO、Web3、NFT、Metaverse资讯请关注老雅痞👇

导读


今日FastDaily共推送3篇文章。

本研究将通过分析智能合约本身、其交互和被认为是黑客发起的交易来驳斥关于Wintermute黑客攻击的观点。在下面的分析中,我们将看到执行这一黑客行为所需的知识排除了黑客是一个随机的外部实体的可能性。


体育是大生意,又是快到世界杯了,气氛已经到这了,不聊聊粉丝球迷token就不礼貌了。推荐阅读本文,我们的原创分析文章给你捋一捋Web3的世界,体育经济怎么玩。


TokenScript是一个以多种方式提高区块链代币功能、安全性和可用性的框架。第二条可以帮助你了解这个希望帮助Token摆脱既定框架的应用。


周五的大佬问DAO海报新鲜出炉!本周我们打算聊一聊Game怎么Fi,欢迎大家来玩。参加方法很简单,找到文中的活动海报,扫码,添加到我的会议就行,周五晚9点,到点儿记得来腾讯会议,我们不见不散~~


RR丨编译

信息来源自medium ,略有修改,作者Librehash



关于Wintermute黑客攻击目前普遍的说法是,调用了“被攻击的”Wintermute智能合约的EOA本身是因为该团队使用了一个有问题的在线虚构地址生成工具而被入侵的。其想法是,通过恢复EOA的私钥,攻击者能够在应该具有管理访问权限的Wintermute智能合约上进行调用。

 

本研究将通过分析智能合约本身、其交互和被认为是黑客发起的交易来驳斥这一观点。在下面的分析中,我们将看到执行这一黑客行为所需的知识排除了黑客是一个随机的外部实体的可能性。

 

换句话说,EOA发起的相关交易清楚地表明,黑客很可能是Wintermute团队的内部成员。


 

在分析Wintermute被黑客攻击后发布的一些报告时,有人声称被攻击的EOA (0x0000000fE6A514a32aBDCDfcc076C85243De899b)能够通过0x178979ae方法针对Wintermute智能合约执行交易。



由于某种原因,我们在这里检查的Wintermute智能合约没有上传的、经过验证的代码。



这本身就表明了项目透明度的问题。人们会期望任何部署到区块链上的负责管理用户/客户资金的智能合约都是公开验证的,以便让公众有机会检查和审计Solidity代码。


在任何一种情况下,我们都可以通过Solidity对智能合约的字节码进行反编译。为此,我们不打算使用Etherscan提供的工具。相反,我们将选择' dedaub '提供的智能合约工具。



由于我们没有已部署的智能合约的原始来源,所以我们从字节码反编译中得到的最好结果是通过字节码指令解释被粗略翻译的4字节十六进制函数签名。


切换到由dedaub提供的“函数”面板,我们可以快速筛选出反编译的字节码,找到据称被入侵的EOA所调用的函数。



下面是这部分反编译字节码的截图:



具体来说,如果我们访问该代码,导致许多人相信EOA具有管理功能的问题区域是在该定义函数下面的一行:

 

function 0x178979ae(uint256 varg0, uint256 varg1, uint256 varg2) public nonPayable {

    require(msg.data.length - 4 >= 96);

    require(varg0 == address(varg0));

    require(varg2 <= 0xffffffffffffffff);

    require(4 + varg2 + 31 < msg.data.length);

    require((?).length <= 0xffffffffffffffff, 65);

    v0 = new bytes[]((?).length);

    require(!((v0 + (0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 & ((?).length + 31 & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0) + 32 + 31) < v0) | (v0 + (0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 & ((?).length + 31 & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0) + 32 + 31) > 0xffffffffffffffff)), 65);

    require(4 + varg2 + (?).length + 32 <= msg.data.length);

    CALLDATACOPY(v0.data, 4 + varg2 + 32, (?).length);

    MEM[32 + (v0 + (?).length)] = 0;

if (0xff & _setCommonAdmin[msg.sender]) {

 

在上面的代码摘录中,最后一个是我们要仔细研究的内容。

 

据说变量_setCommonAdmin被设置为包含EOA 0x0000000fE6A514a32aBDCDfcc076C85243De899b。幸运的是,通过使用dedaub智能合约工具,我们可以对其进行测试。

 

然而,首先我们需要仔细检查反编译的代码,看看该变量的任何值是否已被存储在智能合约本身中(每当创建这类性质的变量时,通常都会出现这种情况)。

 

我们很幸运,看起来是这样的。



我们分离出来的具体代码行如下:


mapping (uint256 => [uint256]) _setCommonAdmin

 

代码注释指出该变量的值在智能合约中被设置为STORAGE[0x2]。因此,让我们检查一下,当我们将所谓受到攻击的EOA输入到智能合约存储的0x2部分时,会得到什么结果。



输入EOA值(0x0000000fE6A514a32aBDCDfcc076C85243De899b)将得到一个“boolean”值。这意味着在输入此值后,我们将得到整数'0'或'1'。如果结果为'0',则表示false;如果结果为'1',则表示为true。本质上,false意味着_setCommonAdmin变量没有将有问题的EOA存储为其值。'1'或' true '则表示相反的结果。

 

让我们看看下面的结果:



正如我们在上面的截图中看到的,得到的boolean值是' 0 ' 或false。这意味着EOA的地址没有定义为_setCommonAdmin变量的值。

 

此外,值得注意的是,代码中有用于存储_signers、owner_8和owner_3的变量。因此,智能合约被设计为允许“普通管理员”单方面操作的可能性似乎微乎其微。

 

再深挖一点

 

让我们来看看其中一笔交易。

 

TX ID: 0xd2ff7c138d7a4acb78ae613a56465c90703ab839f3c8289c5c0e0d90a8b4ce16

 

该交易显示,从Wintermute智能合约地址向0x0248智能合约(据说是由Wintermute黑客创建和控制的)转移了1348万USDT。

 

但是,如果我们观察一下这笔交易的跟踪执行,就会发现这笔转账比仅仅从一个智能合约向另一个智能合约发送资金要复杂一些。



我们要做的第一件事是分解EOA发送到0x0000000ea智能合约的calldata。

 

下面是该交易的calldata:

 

0x178979ae0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c42e95b6c8000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000c40d07f649000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000003b6d03400248f752802b2cfb4373cc0c3bc3964429385c2600000000000000000000000000000000000000000000000000000000

 

下面是上述calldata的分解:

 

  1. 0x178979ae-这是Wintermute智能合约调用的初始方法

  2. 1111111254fb6c44bac0bed2854e76f90643097d-这是1inch v4: Router的智能合约地址,它负责协调Wintermute智能合约和0x0248智能合约之间的swap。

  3. c40d07f6490-这是从一个智能合约传输到另一个智能合约的十进制金额的十六进制表示

  4. 0x00000000000000003b6d03400248f752802b2cfb4373cc0c3bc3964429385c26-在ethtx.info的交易执行跟踪中,我们可以看到这个值被分配给了参数,pool被附加到了unoswap函数。仔细观察,我们可以看到值中嵌入了0x0248f752802b2cfb4373cc0c3bc3964429385c26合约地址。

 

考虑到上面内容,让我们看一看负责处理从Wintermute智能合约到0x0248合约的资金协调/交换的中间智能合约。

 

该合约地址为:0x1111111254fb6c44bac0bed2854e76f90643097d

 

下面是EOA、Wintermute智能合约、1inch v4: Router和0x0248智能合约地址之间交互的可视化图。



该合约中的函数将提供充分的证据,证明由EOA执行的交易很可能是由该团队自身进行的。

 

该智能合约代码遵循了EIP-1271标准,该标准提供了一种验证智能合约签名的方法。通过检查AggregationRouterV4智能合约代码,我们可以看到,如果调用者没有验证他们的权限,资金就不能被移动。

 

在AggregationRouterV4智能合约中,当调用者是另一个智能合约时,验证签名的函数如下:

 

interface IERC1271 {

    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);

}

 

在代码的后面,我们可以看到需要对AggregationRouterV4智能合约上的调用进行验证(从_validate函数获得'success' /boolean值'1')。

 

代码如下:

 

function _validate(address signer, bytes32 orderHash, bytes calldata signature) private view {

    if (ECDSA.tryRecover(orderHash, signature) != signer) {

  (bool success, bytes memory result) = signer.staticcall(

   abi.encodeWithSelector(IERC1271.isValidSignature.selector, orderHash, signature)

  );

  require(success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector, "LOP: bad signature");

}

 

回到Wintermute智能合约,我们可以看到合约本身中已经定义了一个isValidSignature。



从以下未经验证的合约字节码的反编译ABI:

 

function isValidSignature(bytes32 varg0, bytes varg1) public nonPayable {

    require(msg.data.length - 4 >= 64);

    require(varg1 <= 0xffffffffffffffff);

    require(4 + varg1 + 31 < msg.data.length);

    require((?).length <= 0xffffffffffffffff, 65);

    v0 = new bytes[]((?).length);

    require(!((v0 + (0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 & ((?).length + 31 & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0) + 32 + 31) < v0) | (v0 + (0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 & ((?).length + 31 & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0) + 32 + 31) > 0xffffffffffffffff)), 65);

    require(4 + varg1 + (?).length + 32 <= msg.data.length);

    CALLDATACOPY(v0.data, 4 + varg1 + 32, (?).length);

    MEM[32 + (v0 + (?).length)] = 0;

    v1 = 0xdf2(v0, varg0);

    return v1 & 0xffffffff00000000000000000000000000000000000000000000000000000000;

}

 

该智能合约还清楚地将_signers定义为一个独立的变量,合约的存储空间中包含与之关联的值。



此外,在Solidity中用于' transfer '的4字节keccak256 abi编码是0xa9059cbb,这是在函数0x394b1de1中指定的(EOA未将其调用到Wintermute智能合约)。

 

作为参考(对于那些好奇交易的签名被包含在哪里的人来说),看看我们在这里观察到的主要交易的原始TX十六进制就知道了。



进一步的可疑活动

 

让我们回到Etherscan,特别是看一下所谓的被破坏的智能合约——0x00000000ae347930bd1e7b0f35588b92280f9e75

 

我们将改变Etherscan的范围,使它只显示使用该智能合约中涉及USDT代币的所有交易。

 

这会给我们带来一个非常有趣的结果:



正如我们在上面的截图中看到的,据称被入侵的Wintermute智能合约(0x0000000ae)收到了Kraken和币安热钱包的两笔存款。我们可以有把握地假设,这种转账一定是由该团队控制的交易所账户发起的。

 

在Wintermute智能合约收到超过1300万USDT资金后不到一分钟,所有Tether都被从钱包手动转移到了0x0248智能合约中。正如我们前面看到的,这次转账是由0x0000000fe普通钱包地址发起的。

 

这一系列事件使我们提出以下问题:

 

  1. 该团队从两个不同的交易所(币安和Kraken)向他们的智能合约发起了两次取款,这距离他们被入侵的时间不到2分钟,这是否合理?

  2. 如果我们对第一个问题的回答是“否”,那么攻击者是否有可能不仅入侵了该团队的智能合约,还入侵了他们的交易所账户?如果是这样,攻击者是如何得知这些交易所账户的存在的?


除了上面提出的两个问题,我们还必须问自己,Wintermute是如何被攻破的,以及黑客如何掌握我们上面看到的智能合约之间的协调的方法的。

 

这些都是该团队完全没有回答的问题。相反,Evgeny在Twitter上默认了虚拟地址生成器工具私钥泄露的理论(以一种相当不令人信服的方式)。



其他推文都相当不连贯。例如:



Evgeny在黑客入侵之后给出的解释是匆忙且草率的,这给人的印象是他和/或Wintermute团队对他们能够在几乎没有审查的情况下潜在地完成1.6亿美元以上的抢劫感到松了一口气。


如果Wintermute团队愿意反驳这篇报道,欢迎任何回应。希望回应能解决本分析中提出的一些问题和担忧。


【声明】内容源于网络
0
0
FastDaily
日更新闻
内容 2683
粉丝 0
FastDaily 日更新闻
总阅读593
粉丝0
内容2.7k