SharkTeam:Move语言安全性分析及合约审计要点之重放攻击
SharkTeam在之前的“十大智能合约安全威胁”系列课程中,根据历史发生的智能合约安全事件,总结分析了在智能合约领域中出现较多、危害最大的前10大漏洞。这些漏洞之前通常出现在Solidity智能合约中,那么对于Move智能合约来说,会不会存在相同的危害呢?
SharkTeam【Move语言安全性分析及合约审计要点】系列课程将带您逐步深入,内容包括权限漏洞、重入漏洞、逻辑校验漏洞、函数恶意初始化、回退攻击、提案攻击、合约升级漏洞、操纵预言机、三明治攻击、重放攻击。本章内容【重放攻击】。
重放攻击(Replay Attack,又称为重播攻击、回放攻击)是传统网络中的一种恶意或欺诈的重复或延迟有效数据的攻击手段。这可以由重放攻击的发起者或由拦截数据并重新传输数据的对手来执行,以达到欺骗系统的目的。这是“中间人攻击”的一个较低级别版本,主要用于身份认证过程,破坏认证的正确性。
在区块链中,同样存在着重放攻击。区块链中,身份认证的过程就是数字签名验证的过程,每一次的身份认证都需要一次新的数字签名。攻击者可能利用已被使用过的数字签名进行身份认证,并成功通过,我们称这种攻击手段为区块链中的重放攻击。下文中我们仅讨论区块链中的重放攻击及其对Move生态的影响。
根据重放的签名数据以及攻击层面的不同,我们将重放攻击分为交易重放和签名重放。
交易重放指重复利用交易及其签名,将原链上的交易一成不变放到目标链上,重放过后交易在目标链上可以正常执行并完成交易验证。交易重放是区块链层面的攻击,是一种同生态的跨链(比如Solidity生态的Ethereum、BNB Chain、HECO Chain等)攻击手段。
签名重放指重复利用交易数据中的私钥签名进行重放,重放过程中无需像交易重放那样去重放整个交易,而是重放相应的数据及其签名。签名重放是智能合约层面的攻击,可以在同一条链内的重放,可以是同一生态跨链攻击,也可以是签名兼容的不同生态公链(比如Solidity生态的Ethereum、Rust生态的Solana、Move生态的Aptos等)的跨链攻击。签名重放更多是同一生态的跨链攻击;同一条链内重放比较少;而不同生态的跨链重放攻击需要的条件最苛刻,可能性最小,但也不能保证绝对不会发生。对于黑客,无论是项目的设计者、开发者,还是审计者,都不可放松警惕之心。
2022年6月9日,黑客通过交易重放攻击成功盗取了Optimism基金会向Wintermute授予的2000万枚OP代币。交易重放攻击过程如下:
(1)5月27日,Optimism基金会向Wintermute在Optimism/L2上面的多签合约地址转入2000万OP代币。该多签合约地址是Wintermute在Ethereum/L1上的多签合约地址,并已经部署了多签合约。然而,Wintermute并没有在Optimism/L2上面部署相应的多签合约。
(2)6月1日,攻击者部署了攻击合约。
(3)6月5日,攻击者通过重放Ethereum/L1上的交易创建了Gnosis Safe: Proxy Factory 1.1.1合约,其地址与Ethereum/L1上一样;然后攻击者通过攻击合约部署了多签合约0x4f3a,该合约同样与Wintermute在Ethereum/L1能够的多签合约地址相同,但合约所有权归攻击者所有。此时,该多签合约中已被转入了2000万OP代币。
(4)攻击者通过其部署的多签合约0x4f3a将100万OP转到攻击者地址,将100万OP兑换成了720.7 Ether。
整个攻击过程之所以能够成功,关键在于攻击者利用Solidity中合约创建的漏洞,通过重放攻击创建了与Ethereum/L1上的Wintermute多签合约具有相同地址的多钱合约,该多签合约的所有权归攻击者所有。
在Gnosis Safe: Proxy Factory 1.1.1合约中,其中创建代理合约函数createProxy的代码如下:
Gnosis Safe: Proxy Factory 1.1.1合约使用的Solidity版本是0.5.3,通过new来创建合约。这里的new创建合约使用的操作码是CREATE而不是CREATE2。
使用CREATE操作码创建合约,合约地址是creator(合约创建者地址,即使用CREATE操作码的当前合约地址)以及nonce来计算的。在Ethereum/L1上面,创建多签合约0x4f3a的creator就是Gnosis Safe: Proxy Factory 1.1.1的地址,攻击者在Optimism/L2通过重放交易来创建于Gnosis Safe: Proxy Factory 1.1.1合约的主要目的就是为了保证在Optimism/L2上创建合约0x4f3a的creator与在Ethereum/L1上一致。然后通过交易重放保持nonce也与Ethereum/L1上一致。因此,攻击者就可以通过智能合约(合约0xe714)调用createProxy函数来创建出与Ethereum/L1具有相同地址(0x4f3a)的多签合约。
(5)6月5日,多签合约0x4f3a在接收到2000万OP后,将100万OP转账给黑客地址0x60b2,然后将100万OP兑换成了720.7 Ether。
(6)6月9日,合约0x4f3a将其中的100万OP转账给了账户地址0xd8da, 其他的1800万OP仍然在合约0x4f3a中。
总结来说,本次安全事件是交易重放、Solidity新旧版本差异以及主侧链交易签名验证等综合因素造成的。
Solidity操作码CREATE与CREATE2简介如下:
(1)CREATE操作码创建合约,新的合约地址计算如下:
Hash(creator, nonce)
通过new使用CREATE创建新合约:
Contract x = new Contract{value: _value}(params)
其中的value是可选的,指发送的以太币。
(2)CREATE2操作码创建合约,新的合约地址计算如下:
Hash(“0xff”, creator, salt, bytecode)
通过new使用CREATE2创建新的合约:
Contract x = new Contract{salt: _salt, value: _value}(params)
其中的value是可选的,指发送的以太币。
2022年9月18日,攻击者通过Gnosis链的omni桥转移了200 WETH,然后在PoW链上重放了相同的消息,获得了额外的200 ETHW。
在同一条链中,我们通过nonce来对交易进行排序,避免交易被重放。在不同的链上,我们会根据chainid进行识别链的类型,比如以太坊主网的chainid是1,ETHW主网的chainid是10001。交易中嵌入chainid,可以避免交易的跨链重放。而对于签名来说,一般用于跨链验证的签名中也会包含chainid,避免签名的跨链重放。
以太坊在硬分叉之前强行执行EIP-155,这就说明ETH PoS链上交易不能在PoW链上重放。因此,该交易重放并不是链本身的漏洞。分析Omni Bridge源码,发现在Omni Bridge验证chainid的逻辑中,chainid来源于unitStorage中存储的值,而不是通过操作码 CHAINID(0x46)直接读取的链上chainid。
在以太坊硬分叉后,该状态变量存储的chainid并没有更新为新的chainid,因此,硬分叉前后的签名是可以被重放的。攻击者利用该漏洞进行签名重放,获得了额外的200万ETHW。
通过回顾已发生的攻击事件,无论是交易重放,还是签名重放,发生的根本原因都是签名的验证机制中缺乏唯一性验证。只需要在签名和验证机制中增加唯一性标识符就可以预防重入攻击。
根据重放攻击的不同层面,唯一性标识符包括3种,即
(1)公链层面的唯一性标识chainid(公链ID),验证chainid可以预防跨链的重放攻击(参考EIP-155);
(2)交易层面的唯一性标识nonce(交易序列号),验证nonce可以预防同链的重放攻击;
(3)合约层面的唯一性标识,即自定义业务标识,比如自定义序列号,验证自定义业务标识可以预防合约中业务方面的签名重放攻击。
对于合约层面,除了在签名和验证机制中增加唯一性标识符之外,可以增加签名验证记录,比如使用mapping来记录每一个唯一性签名的验证结果。
重放攻击是基于签名机制的攻击手段。与仅支持ECDSA一种签名方案的以太坊不同,Move生态支持多种签名机制,尤其是合约层面,支持区块链常用的签名算法,包括基于Secp256k1椭圆曲线的ECDSA签名方案(以太坊唯一签名方案)、基于Ed25519椭圆曲线的单签方案和k-of-N多签方案、BLS12-381聚合签名方案,甚至还包含Groth16等零知识证明方案。
Aptos公链交易签名支持基于Ed25519椭圆曲线的EdDSA单签方案和k-of-N多签方案,默认选择单签方案。而合约层面支持4种签名机制的验证:
(1)基于secp256k1椭圆曲线的ECDSA签名验证
(2)基于Ed25519椭圆曲线的EdDSA签名验证
(3)基于Ed25519椭圆曲线的k-of-N EdDSA多签签名验证
(4)bls12-381聚合签名、多签签名和单签签名的验证
Sui公链Move合约同样支持上面的4种签名验证,此外还支持范围证明验证以及Groth16零知识证明的验证。
Move公链支持多种签名验证机制更便于实现合约层面的资产跨链转移,有利于Move生态的发生。在使用签名实现跨链时也要严防签名重放攻击,尤其是链上与链下数据的交互以及业务合约层面的签名与验证,更需要谨慎对待,避免出现同链或跨链的合约层面的业务数据签名的重放攻击。