Transaction

7bb1f97b1e98cc9a6abf971a648cb648575156f4ca7105900574b05b41fa31e3
( - )
262,162
2019-05-15 18:12:37
1
5,046 B

3 Outputs

Total Output:
  • j"19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAutMJ--- title: BCH升级攻击分析 date: 2019-05-16 1:46:14 author: 梆梆安全 刘一鸣 --- ## BCH升级攻击分析 BCH的5月15日升级遭到攻击,导致节点报出too many sigops错误。 经分析,攻击载荷为一个精确构造的P2SH Transaction,利用了BCH去年11月升级引入的OP_CHECKDATASIG操作码。 攻击导致了矿工节点无法打包,BCH方面通过类似于空块攻击的方式,紧急挖出十个空块以触发滚动检查点保证升级。攻击发生约1小时后,BCH矿池上线紧急修复后的代码成功继续出块。 不过同时也有人观察到,在 582698 区块高度,有矿工挖出了哈希结尾为 6bf418af 的区块,大小139369字节。但随后该区块被 10 分钟后BTC.top 挖出的哈希结尾为 449e2bb4 区块所重组。或许是一次误伤,不过可见BCH对于升级防守之严密。 ### 攻击原理分析 #### 攻击载荷 捕捉到的攻击载荷TXID为`4c83ab55623633c86ec711b3d68ccdea506b228178ff1533f287ab744b006c44` 其内容见附件。 该攻击载荷由1334个Input构成,每一个Input均是P2SH格式。 其内容为 > OP_FALSE OP_IF OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_CHECKDATASIG OP_14 OP_CHECKDATASIG OP_ENDIF OP_TRUE 可见其中包含15个OP_CHECKDATASIG 该攻击载荷利用了一个CORE曾经帮ABC修复,但未完全修复的漏洞,制造了组块和验证之间的差异,从而导致矿工组出的区块不被节点接受。 #### 漏洞背景 OP_CHECKDATASIG是一种椭圆曲线签名校验指令(SigOP),这类指令由于需要进行椭圆曲线运算,执行开销远高于其他指令。因此在节点代码中,对于这类指令的数量做出了限制,以避免拒绝服务攻击。 [相关代码位置](https://github.com/Bitcoin-ABC/bitcoin-abc/blob/f27da0752c0a3b7382df54a65ca3cf1c3629aad4/src/consensus/consensus.h#L27):/src/consensus/consensus.h#L27 ~~~c++ static const uint64_t MAX_TX_SIGOPS_COUNT = 20000; ~~~ 即,单个Transaction中SigOP的数量不能超过20000。 #### 漏洞原理 细心的话,你已经发现了,攻击载荷的SigOP数量为 1334 * 15 = 20010,这个攻击载荷TX会被节点拒绝,报错即是`too many sigops`,这是导致节点拒绝包含该TX的区块的原因。 [相关代码位置](https://github.com/Bitcoin-ABC/bitcoin-abc/blob/f27da0752c0a3b7382df54a65ca3cf1c3629aad4/src/validation.cpp#L1936):/src/validation.cpp#L1936 ~~~c++ if (nSigOpsCount > nMaxSigOpsCount) { return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops"); } ~~~ 然而在组块时为什么没有拒绝这个TX呢?我们可以在Bitcoin-ABC的补丁中发现端倪。 补丁位置:<https://reviews.bitcoinabc.org/D3053> [相关代码位置](https://github.com/Bitcoin-ABC/bitcoin-abc/blob/f27da0752c0a3b7382df54a65ca3cf1c3629aad4/src/validation.cpp#L592):/src/validation.cpp#L592 ~~~c++ // 原代码 int64_t nSigOpsCount = GetTransactionSigOpCount(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS); // 补丁代码 int64_t nSigOpsCount = GetTransactionSigOpCount(tx, view, STANDARD_CHECKDATASIG_VERIFY_FLAGS); ~~~ 所在的函数为:AcceptToMemoryPoolWorker 可见原代码组块过程中在计算Transaction中的SigOP数量时,错误地使用了`STANDARD_SCRIPT_VERIFY_FLAGS`,而非`STANDARD_CHECKDATASIG_VERIFY_FLAGS`。 这两个标志有什么区别呢? 在policy中我们可以找到他们。 [相关代码位置](https://github.com/Bitcoin-ABC/bitcoin-abc/blob/f27da0752c0a3b7382df54a65ca3cf1c3629aad4/src/policy/policy.h#L108):/src/policy/policy.h#L108 ~~~c++ static const uint32_t STANDARD_CHECKDATASIG_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_CHECKDATASIG; ~~~ 所以我们可以见到,当仅使用了`STANDARD_SCRIPT_VERIFY_FLAGS`时,计算脚本中SigOP数量时,是不包含OP_CHECKDATASIG的。 所以这个包含20010个SigOP的攻击载荷,在组块时,统计出来的SigOP数量为,零。 因此,攻击载荷会在矿工组块的时候被包含进区块中,然而,由于其他代码正确地统计了SigOP,节点会拒绝该区块,这导致了BCH无法出块。 ### 总结 攻击者利用了BCH引入OP_CHECKDATASIG时产生的,又未完全修复的漏洞,巧妙地构造了攻击载荷。攻击者应该高度了解客户端代码,并熟悉OP_CHECKDATASIG漏洞。 UTF-8BCH升级攻击分析.md| Çã$&zرÌ?èÚlØQ:š‚ó-Æò[@ⴎ9·ðbitpaste prerender
    https://whatsonchain.com/tx/7bb1f97b1e98cc9a6abf971a648cb648575156f4ca7105900574b05b41fa31e3