闪电网络安全漏洞技术细节及发现过程
日前,开发者Rusty Russell首次对外披露了闪电网络安全漏洞及对应解决方案的技术细节。
以下是技术细节内容:
接受通道的闪电网络节点必须检查funding交易输出是否确实打开了提议的通道,否则攻击者可声称打开一个通道,然后要么不向对等节点(peer)支付,要么不进行全额支付。
一旦交易达到最小深度,其就可从通道中支出资金。只有当受害者试图关闭通道,以及其拥有的任何承诺或相互成交交易都无效时,他们才会注意到这种恶意行为。
而闪电网络客户端并不一定会执行这种检查操作:
c-lightning: v0.7.1以及更高版本的客户端正确地做到了这一点,而以前版本的c-lightning客户端却没法办到。(CVE-2019-12998)
- 连接对等节点,并用任何交易id声称打开一个通道,就可利用这种漏洞。
scriptpubkey
,v0.6.x版本客户端部分强制执行资助
ScriptPubkey
,但v0.6.0之前版本的客户端则完全没有进行相关验证。(CVE-2019-12999)
-
对所有以前版本的lnd客户端,攻击者都可能通过不正确的数量进行攻击。在v0.7.0版本,攻击者必须使用正确的
scriptpubkey
,这会烧掉funding输出中的币。 -
而对于v0.6.0版本之前的客户端,攻击者通过不正确的
scriptpubkey
都可实现攻击。在v0.6.x客户端中,如果在funding交易达到所需的确认数,在任意一个全节点后端上运行txindex=0
,且节点处于离线(offline)状态时,此漏洞也可能会被利用。 - 利用错误outpoint攻击neutrino客户端(通常是移动端或笔记本电脑)用户,需攻击者将其假outpoint与BIP 158 筛选程序中的真实outpoint脚本碰撞。用于创建筛选程序的siphash密钥是从blockhash派生而来的。因此,攻击者在不提前知道区块哈希的情况下,是无法直接进行攻击的。此外, neutrino客户端节点通常不会监听或不具备公告地址,这意味着攻击者必须等至接收到入站连接后才能执行攻击。
-
攻击Electrum客户端用户(移动端),则要求用户主动连接到恶意闪电网络节点,并且攻击者使用正确的
scriptpubkey
,这会烧掉 funding输出中的币。由于Eclair移动端客户端不会中继支付,攻击者在没有带外(offband)交互(例如,向用户出售某物,并使用假通道中的资金进行支付)的情况下,是无法进行提款操作的。
解决方案
一旦观察到funding交易,对等节点(peer)必须检查
`funding_created`
[1] 中所述的outpoint是否为
`open_channel`
[3]中描述金额的funding交易输出[2] 。
背景
要打开一个闪电网络通道,funding对等节点发送带有提议
`funding_satoshis`
(金额)的
`open_channel`
。被资助者则用
`accept_channel`
回复,提供其希望用于这笔funding交易的密钥。
然后出资人创建这笔funding交易,并发送交易id以及
`funding_created`
消息中的输出编号。
其中节点A是“出资人”,节点B是“被资助者”
有了这些信息,“被资助者”可在第一笔“承诺交易”上创建签名,并将其发送到一则
`funding_signed`
消息中,以便在出现问题时,资助者可取回他们的资金。这样,出资人就可以安全地签署并广播这笔opening交易。经过一定数量的确认(由“被资助者”设定)后,通道就开始运作(`funding_locked`)了。
规范清楚地描述了检查所交换的各种签名,是否确实允许创建有效承诺交易[4]的要求,并描述了等待确认的要求[5]。
但是,它并不要求接收者实际检查交易是否是出资人承诺的交易:包括金额和实际的
scriptpubkey
。
漏洞发现过程
Rusty Russell (Blockstream)在为规范本身进行协议测试(增加了多个新的提议功能[6])时发现了这一漏洞。
在编写测试时,通道开启者(opener)在
`funding_created`
消息中提供了不正确的
`funding_output_index`
,Russell意识到C-Lightning客户端不会拒绝它,因为C-Lightning只检查
`funding_txid`
的确认计数,甚至连
`funding_output_index`
是否存在都不会进行检查!
而这个要求在规范中是没有被提到的,因此Rusty立即向其它被广泛使用的客户端(eclair 和 lnd)的作者揭示了这一问题。经过调查后,他们发现的确是存在这样的问题。
于是,几个团队一起做出决定,先在新版本客户端中悄悄地解决这些问题,然后再经过8周(大多数用户完成升级后),就可揭示问题本身,接着再过四周后,他们就全面披露漏洞。
值得庆幸的是,这一长期存在的漏洞并没有被广泛利用,其确实提供了一个测试整个闪电网络生态系统通信和升级方法的机会。
漏洞时间表
2019-06-27: Rusty Russell发现漏洞,并通知LND和Eclair客户端作者;
2019-06-28: CVE漏洞编号被分配完毕;
2019-07-02: lnd v0.7.0-beta客户端发布;
2019-07-03: Eclair 0.3.1客户端发布;
2019-07-04: c-lightning 0.7.1 客户端发布;
2019-07-06: Rusty Russell等人开始向其他客户端(rust-lightning, ptarmigan, BLW)作者披露漏洞;
2019-07-30: lnd v0.7.1-beta 客户端发布;
2019-08-17: [根据部署状态/问题查看下一个日期];
2019-08-30: 对外披露CVE漏洞存在,劝告使用旧版本客户端的用户进行升级;
2019-09-07: 首次发现有人企图利用这种漏洞;
2019-09-27: 全面披露CVE漏洞细节;
2019-09-27: 根据规范要求提交PR;
[1] https://github.com/lightningnetwork/lightning-rfc/blob/v1.0/02-peer-protocol.md#the-funding_created-message
[2] https://github.com/lightningnetwork/lightning-rfc/blob/v1.0/03-transactions.md#funding-transaction-output
[3] https://github.com/lightningnetwork/lightning-rfc/blob/v1.0/02-peer-protocol.md#the-open_channel-message
[4] https://github.com/lightningnetwork/lightning-rfc/blob/v1.0/02-peer-protocol.md#requirements-2
[5] https://github.com/lightningnetwork/lightning-rfc/blob/v1.0/02-peer-protocol.md#the-funding_locked-message
[6] https://github.com/ElementsProject/lightning-rfc-protocol-test