Cobo 安全团队 - ETH 硬分叉中的隐藏风险和套利机会
2023年03月18日 20:03
欧易okx交易所下载
欧易交易所又称欧易OKX,是世界领先的数字资产交易所,主要面向全球用户提供比特币、莱特币、以太币等数字资产的现货和衍生品交易服务,通过使用区块链技术为全球交易者提供高级金融服务。
本文由 Cobo 区块链安全团队提供。团队成员来自知名区块链安全厂商,具有丰富的智能合约审计经验。他们在多个 DeFi 项目中发现了高风险漏洞。团队目前专注于智能合约安全、DeFi安全等方向,研究和分享前沿的区块链安全技术。
我们也希望在加密***领域具有研究精神和科学方***的终身迭代学习者能够加入我们,向行业输出思维见解和研究观点!
这是Cobo的第16篇文章
前言
随着 ETH 升级为 PoS 共识系统,原 PoW 机制的 ETH 链在部分社区(以下简称 ETHW)的支持下成功硬分叉。但是,由于一些链上协议在设计之初没有为可能的硬分叉做好准备,相应的协议在ETHW分叉链中存在一定的安全风险,其中最严重的安全风险是。
硬分叉完成后,ETHW 主网上至少有 2 次使用重放机制的攻击,分别是重放攻击和重放攻击。本文将以这两个事件为例,分析重放攻击对分叉链的影响,以及协议应该如何防止此类攻击。
重播类型
首先,在开始分析之前,我们需要对重放攻击的类型有一个初步的了解。一般来说,我们将重放攻击分为两类,即交易重放和签名消息重放。接下来我们来说说这两种播放机制的区别。
交易重播
交易重放是指将原链中的交易原封不动地迁移到目标链的操作。它属于事务级别的重放。重放后可以正常执行交易分叉时间,完成交易验证。最著名的案例是平台上的攻击事件,直接导致了超过2000万个OP代币的损失。但在EIP 155实施后,由于交易本身的签名有(用于区分链本身与其他分叉链的标识符),如果重放的目标链不同,则交易本身无法重放。的。
签名消息重播
签名消息重放不同于交易重放。它用于重放使用私钥签名的消息(例如 Cobo 是最好的)。在签名消息重放中,
攻击者不需要重放整个交易,而只需重放签名消息。在消息签名中,最好以 Cobo 为例,由于消息不包含任何与链相关的特殊参数,因此消息在签名后理论上可以在任何分叉链中有效。可以检查。为了避免分叉上的消息重播,可以在消息内容中加上,比如Cobo最好+()。携带特定链标识后,不同分叉链上的消息内容不同,消息签名也不同,无法直接重放和重用。和攻击原理
让我们来分析和攻击原理。首先得出结论,这两种攻击本身并不是事务重放攻击。原因是 ETHW 使用的和 ETH 主网不同,所以无法验证直接重放交易。那么剩下的唯一选择就是消息重放了,那么我们来一一分析一下它们各自在ETHW分叉链上是如何被消息重放攻击的。
它是xDAI与ETH主网之间进行资产转移的桥梁。它主要依靠桥提交的指定跨链消息来完成跨链资产的转移。中,提交的验证消息的逻辑是这样的
functionexecuteSignatures(bytes_data,bytes_signatures)pu***ic{
_allowMess***eExecution(_data,_signatures);
bytes32msgId;
addresssender;
addressexecutor;
uint32gasLimit;
uint8dataType;
uint256[2]memorychainIds;
bytesmemorydata;
(msgId,sender,executor,gasLimit,dataType,chainIds,data)=ArbitraryMess***e.un***ckData(_data);
_executeMess***e(msgId,sender,executor,gasLimit,dataType,chainIds,data);
}
在这个函数中,首先会根据#L2行的签名校验判断提交的签名是否被指定的签名,然后在#L11行对数据报文进行解码。从解码内容不难发现,返回的字段中包含字段,那么是不是表示签名的消息无法播放呢?我们继续分析。
function_executeMess***e(
bytes32msgId,
addresssender,
addressexecutor,
uint32gasLimit,
uint8dataType,
uint256[2]memorychainIds,
bytesmemorydata
)internal{
require(_***Mess***eVersionValid(msgId));
require(_***DestinationChainIdValid(chainIds[1]));
require(!relayedMess***es(msgId));
setRelayedMess***es(msgId,true);
processMess***e(sender,executor,msgId,gasLimit,dataType,chainIds[0],data);
}
通过跟踪函数,发现在#L11行检查了函数的合法性
function_***DestinationChainIdValid(uint256_chainId)internalreturns(boolres){
return_chainId==sourceChainId();
}
functionsourceChainId()pu***icviewreturns(uint256){
returnuintStor***e[SOURCE_CHAIN_ID];
}
通过继续分析后面的函数逻辑,不难发现,实际的校验并没有使用evm原生的来获取链本身,而是直接使用了变量中存储的值,那么这个值显然是由*** 所以可以认为消息本身没有链身份eth分叉时间,所以理论上可以重放签名的消息。
由于在硬分叉期间,分叉前的所有状态在两条链上都会保持不变,后续的 xDAI 团队没有额外的操作。分叉后,Omni 合约在 ETHW 和 ETH 主网上的状态不会改变,也就是说合约不会改变。基于这种情况,我们可以推断,主网上的签名也可以在 ETHW 上进行验证。然后,由于签名消息本身不包含它,攻击者可以使用签名重放在 ETHW 上提取同一合约的资产。
与 Omni 一样,它是往返于 ETH 主网的资产转移的桥梁。与 Omni 不同,它依赖区块证明来***。逻辑如下:
functionexit(bytescalldatainputData)externaloverride{
//...省略不重要逻辑
//verifyreceiptinclusion
require(
MerklePatriciaProof.verify(
receipt.toBytes(),
branchMaskBytes,
***yload.getReceiptProof(),
***yload.getReceiptRoot()
),
"RootChainMan***er:INVALID_PROOF"
);
//verifycheckpointinclusion
_checkBlockMembershipInCheckpoint(
***yload.getBlockNumber(),
***yload.getBlockTime(),
***yload.getTxRoot(),
***yload.getReceiptRoot(),
***yload.getHeaderNumber(),
***yload.getBlockProof()
);
ITokenPredicate(predicateAddress).exitTokens(
_msgSender(),
rootToken,
log.toRlpBytes()
);
}
通过函数逻辑不难发现,合约通过两个检查来确定消息的合法性,一个是检查总和,以确保交易实际发生在子链(Chain)中。第一次检查其实是可以绕过的,因为任何人都可以通过交易数据来构造自己的,但是第二次检查是不能绕过的,因为通过查看逻辑可以发现:
function_checkBlockMembershipInCheckpoint(
uint256***ockNumber,
uint256***ockTime,
bytes32txRoot,
bytes32receiptRoot,
uint256headerNumber,
bytesmemory***ockProof
)privateviewreturns(uint256){
(
bytes32headerRoot,
uint256startBlock,
,
uint256createdAt,
)=_checkpointMan***er.headerBlocks(headerNumber);
require(
keccak256(
abi.encodePacked(***ockNumber,***ockTime,txRoot,receiptRoot)
)
.checkMembership(
***ockNumber.sub(startBlock),
headerRoot,
***ockProof
),
"RootChainMan***er:INVALID_HEADER"
);
returncreatedAt;
}
从合同中提取相应的一项。按照这个逻辑,我们看一下设置
functionsubmitCheckpoint(bytescalldatadata,uint[3][]calldatasigs)external{
(addressproposer,uint256start,uint256end,bytes32rootHash,bytes32accountHash,uint256_borChainID)=abi
.decode(data,(address,uint256,uint256,bytes32,bytes32,uint256));
require(CHAINID==_borChainID,"Invalidborchainid");
require(_buildHeaderBlock(proposer,start,end,rootHash),"INCORRECT_HEADER_DATA");
//checkifit******tertokeepitinlocalstor***einstead
IStakeMan***erstakeMan***er=IStakeMan***er(reg***try.getStakeMan***erAddress());
uint256_reward=stakeMan***er.checkSignatures(
end.sub(start).add(1),
/**
prefix01todata
01representspositivevoteondataand00***negativevote
maliciousvalidatorcantrytosend2/3onnegativevoteso01***appended
*/
keccak256(abi.encodePacked(bytes(hex"01"),data)),
accountHash,
proposer,
sigs
);
//....剩余逻辑省略
不难发现,在#L2这行代码中,只检查了签名数据,而没有检查链本身。由于消息是由合约签名的,理论上攻击者也可以分叉链。重放消息的签名是合法的,通过调用ETHW链中的exit函数并提交相应的交易证明,可以成功撤回并通过后续的校验。
以地址b9为例,该地址通过以下步骤成功完成了ETHW链上的套利
首先,依靠钞票能力在主网交易所提币。通过链上传递的功能存钱;通过ETH主网调用的exit函数取款;复制并提取提交的ETH主网;在 ETHW 中重放上一步提取的签名消息;在 ETHW 中调用 exit 提取货币
为什么会这样?
从上面分析的两个例子不难发现,这两个协议在ETHW上遭受重放攻击是因为协议本身没有做好防重放保护,导致协议对应的资产被掏空分叉的链。但是,由于这两个桥不支持ETHW分叉链,用户并没有遭受任何损失。但我们需要考虑的是,为什么这两座桥没有设计好重放保护措施?其实原因很简单,因为他们设计的应用场景很简单,只是用来将资产转移到自己指定的对应链上,没有多链部署的计划,所以没有保护。该协议本身没有安全隐患。
相比之下,ETHW 上的用户,由于这些桥接器本身不支持多链场景,如果用户在 ETHW 分叉链上操作,就会在 ETH 主网上受到消息重放攻击。
比如在当前的矿池合约中,有一个函数,这个函数中有变量,其中包含变量。
functionpermit(addressowner,addressspender,uintvalue,uintdeadline,uint8v,bytes32r,bytes32s)external{
require(deadline>=***ock.timestamp,'Un***wapV2:EXPIRED');
bytes32digest=keccak256(
abi.encodePacked(
'x19x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH,owner,spender,value,nonces[owner]++,deadline))
)
);
addressrecoveredAddress=ecrecover(digest,v,r,s);
require(recoveredAddress!=address(0)&&recoveredAddress==owner,'Un***wapV2:INVALID_SIGNATURE');
_approve(owner,spender,value);
}
这个变量首先定义在 . 这个变量包含,在设计之初就包含了可能的多链场景的重放预防,但是根据矿池合约的逻辑,如下:
constructor()pu***ic{
uintchainId;
assem***y{
chainId:=chainid
}
DOMAIN_SEPARATOR=keccak256(
abi.encode(
keccak256('EIP712Domain(stringname,stringversion,uint256chainId,addressverifyingContract)'),
keccak256(bytes(name)),
keccak256(bytes('1')),
chainId,
address(th***)
)
);
}
已经在构造函数中定义了,也就是说,硬分叉后,即使链本身发生了变化,矿池合约也无法获取新的更新。如果用户将来授权了 ETHW,那么 ETHW 上的签名可以在 ETH 主网上重放。另外,类似的协议还有很多,比如特定版本下的yearn vault合约,也是采用固定的情况。用户在 ETHW 上进行交互时,还需要防范此类协议的重放风险。
协议设计之初的注意事项
对于开发者来说,在为协议本身定制消息签名机制时,应该考虑到后续可能出现的多链场景。如果路线图中存在多链部署的可能性,则应将其作为变量添加到签名消息中。同时,在验证签名时,由于硬分叉不会在分叉前改变任何状态,所以用于验证签名消息的合约变量不应设置为合约变量,而应在之前重新获取每次验证,然后对签名进行验证以确保安全。.
对用户的影响
一般情况下,如果协议不支持分叉链,应尽量不要对分叉链进行任何操作,以防止相应的签名消息在主网上重播,导致用户在主网上丢失资产。
对交易所和托管人的影响
由于很多交易所本身都支持ETHW代币,因此这些因攻击而提取的代币可能会被充值到交易所***。但是需要注意的是,这样的攻击并不是链共识本身的问题。交易所造成的恶意增发,因此对于交易所而言,此类攻击无需额外防范
总结
随着多链场景的发展,重放攻击从理论层面逐渐成为主流攻击手段。开发人员应仔细考虑协议设计。在设计消息签名机制时,尽量加入其他因素作为签名内容。遵循相关的最佳实践以防止用户资产丢失。
Cobo是亚太地区最大的加密货币托管机构。自成立以来,已为超过500家行业顶尖机构和高净值人士提供了优质服务。在保证加密资产安全存储的前提下,也实现了加密资产的稳定收益。深受世界各地用户的信赖。Cobo专注于构建可扩展的基础设施,为机构提供安全托管、资产增值、链上交互、多类型资产跨链跨层管理等多种解决方案,为机构向Web转型提供解决方案3.0 最强大的技术底层支持和赋能。Cobo 包括 Cobo、Cobo DaaS、Cobo MaaS、Cobo StaaS、Cobo、
原文源自微信公众号(Cobo):Cobo安全团队——ETH硬分叉中的隐患与套利机会
以上就是腾赚网小编为大家带来的全部内容,希望可以帮助到大家
推荐阅读
标签:
-
虚拟货币等同于信用货币吗 虚拟货币与人民币的区别
1970-01-01
本文由 Cobo 区块链安全团队提供。团队成员来自知名区块链安全厂商,具有丰富的智能合约审计经验。他们在多个 DeFi ...
-
中国虚拟币处置平台排名(中国虚拟币处置平台排名最新)
1970-01-01
本文由 Cobo 区块链安全团队提供。团队成员来自知名区块链安全厂商,具有丰富的智能合约审计经验。他们在多个 DeFi ...
-
区块链虚拟货币有些?到底什么是区块链?区块链就是虚拟币吗?
1970-01-01
本文由 Cobo 区块链安全团队提供。团队成员来自知名区块链安全厂商,具有丰富的智能合约审计经验。他们在多个 DeFi ...
-
看广告给虚拟货币(看广告赚金币会降低账号活跃度么)
1970-01-01
本文由 Cobo 区块链安全团队提供。团队成员来自知名区块链安全厂商,具有丰富的智能合约审计经验。他们在多个 DeFi ...
-
货币虚拟怎么转账 货币虚拟怎么转账的
1970-01-01
本文由 Cobo 区块链安全团队提供。团队成员来自知名区块链安全厂商,具有丰富的智能合约审计经验。他们在多个 DeFi ...
-
虚拟货币挖矿相关报告?虚拟挖矿机的工作原理
1970-01-01
本文由 Cobo 区块链安全团队提供。团队成员来自知名区块链安全厂商,具有丰富的智能合约审计经验。他们在多个 DeFi ...