Grand Theft Read.Cash Earlier today, the people behind Read.Cash drafted a proposal for a smart contract allowing password-based wallet recovery. I think this has both positive and negative aspects. I like the general idea of ... https://read.cash/@Read.Cash/recoverable-bitcoin-cash-wallets-2918c893
The tools Bitcoin ABC (required, blockchain history not needed) https://www.bitcoinabc.org/ text editor (required) Electron Cash (optional) https://electroncash.org/ Mission Impossible theme music (optional) The plan **Step 1.** Use Electron Cash to generate a receiving address for the booty. Upon success, Electron Cash will automatically initiate CashShuffle for the perfect getaway. I generated `bitcoincash:qpq9y25eejhx7pdk53eul93r563v68jz4s4stdkf5j`. Alternatively, use the wallet within Bitcoin ABC, but then the treasure remains traceable. https://electroncash.org/ https://cashshuffle.com/ **Step 2.** Bitcoin ABC comes with an optional command-line utility `bitcoin-tx` to construct transactions. You can find it in the `bin` directory. Summon its manual: https://www.bitcoinabc.org/ $ bitcoin-tx -? Bitcoin ABC bitcoin-tx utility version v0.20.6-unk Usage: bitcoin-tx [options] <hex-tx> [commands] Update hex-encoded bitcoin transaction or: bitcoin-tx [options] -create [commands] Create hex-encoded bitcoin transaction Options: -? This help message -create Create new, empty TX. -json Select JSON output -txid Output only the hex-encoded transaction id of the resultant transaction. Chain selection options: -testnet Use the test chain Commands: delin=N Delete input N from TX delout=N Delete output N from TX in=TXID:VOUT(:SEQUENCE_NUMBER) Add input to TX locktime=N Set TX lock time to N nversion=N Set TX version to N outaddr=VALUE:ADDRESS Add address-based output to TX outdata=[VALUE:]DATA Add data-based output to TX outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS] Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. Optionally add the "S" flag to wrap the output in a pay-to-script-hash. outpubkey=VALUE:PUBKEY[:FLAGS] Add pay-to-pubkey output to TX. Optionally add the "S" flag to wrap the output in a pay-to-script-hash. outscript=VALUE:SCRIPT[:FLAGS] Add raw script output to TX. Optionally add the "S" flag to wrap the output in a pay-to-script-hash. sign=SIGHASH-FLAGS Add zero or more signatures to transaction. This command requires JSON registers:prevtxs=JSON object, privatekeys=JSON object. See signrawtransactionwithkey docs for format of sighash flags, JSON objects. Register Commands: load=NAME:FILENAME Load JSON file FILENAME into register NAME set=NAME:JSON-STRING Set register NAME to given JSON-STRING **Step 3.** Figure out what coin you want to steal. In this case, the mission is output 1 (count from zero) of transaction b48e260f36142340cc1652bbc2da5028303e21f469d169393d3b08f234165dfc, worth 0.02290635 BCH. https://blockchair.com/bitcoin-cash/transaction/b48e260f36142340cc1652bbc2da5028303e21f469d169393d3b08f234165dfc **Step 4.** Create the transaction, ignoring the amount of the output for a moment: $ bitcoin-tx -json -create in=b48e260f36142340cc1652bbc2da5028303e21f469d169393d3b08f234165dfc:1 outaddr=0:qpq9y25eejhx7pdk53eul93r563v68jz4s4stdkf5j { "txid": "d0dc399a668008fa6a0bebc0680ba16d3ca33187fa0ea37adf7a5a367f330dbd", "hash": "d0dc399a668008fa6a0bebc0680ba16d3ca33187fa0ea37adf7a5a367f330dbd", "version": 2, "size": 85, "locktime": 0, "vin": [ { "txid": "b48e260f36142340cc1652bbc2da5028303e21f469d169393d3b08f234165dfc", "vout": 1, "scriptSig": { "asm": "", "hex": "" }, "sequence": 4294967295 } ], "vout": [ { "value": 0.00000000, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 40522a99ccae6f05b6a473cf9623a6a2cd1e42ac OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": [ "16s6gJN1t7yPZGfzUFvMo9xkFvN7MzjkHH" ] } } ], "hex": "0200000001fc5d1634f2083b3d3969d169f4213e302850dac2bb5216cc402314360f268eb40100000000ffffffff0100000000000000001976a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac00000000" } **Step 5.** You see the `scriptSig` field of the input, the signature script that authorises spending the input, is still missing. Since the coin we're stealing is a Pay-to-Script-Hash (P2SH) coin, the signature script consists of the unhashed P2SH script (`b251f93c45baea5c72bae18311c75eccad404291 OP_OVER 'read.cash' OP_EQUAL OP_NIP OP_NIP`), preceded by all other input data to this P2SH script itself (again the password 'read.cash'): Password length (9) push operation: 09 Password: 726561642e63617368 Unhashed P2SH script length (35) push operation: 23 Unhashed P2SH script: 14b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777 Full signature script: 09726561642e636173682314b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777 **Step 6.** Our signature script is 46 bytes long, or 47 bytes including a 1-byte length indicator prefix (`2e`). This must replace the 0-byte signature script with 1-byte length indicator (`00`) in our transaction template. The transaction will therefore grow from 85 bytes to 131 bytes. With the minimum fee rate of 1 sat/b, we thus need to attach a fee of 0.00000131 BCH, so we can claim 0.02290504 BCH for ourselves. Generate a new transaction template accordingly: $ bitcoin-tx -json -create in=b48e260f36142340cc1652bbc2da5028303e21f469d169393d3b08f234165dfc:1 outaddr=0.02290504:qpq9y25eejhx7pdk53eul93r563v68jz4s4stdkf5j { "txid": "0229cef50d62eff07dd7133ce9db29364c46866b0b46f8437f58bf3e2012318e", "hash": "0229cef50d62eff07dd7133ce9db29364c46866b0b46f8437f58bf3e2012318e", "version": 2, "size": 85, "locktime": 0, "vin": [ { "txid": "b48e260f36142340cc1652bbc2da5028303e21f469d169393d3b08f234165dfc", "vout": 1, "scriptSig": { "asm": "", "hex": "" }, "sequence": 4294967295 } ], "vout": [ { "value": 0.02290504, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 40522a99ccae6f05b6a473cf9623a6a2cd1e42ac OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": [ "16s6gJN1t7yPZGfzUFvMo9xkFvN7MzjkHH" ] } } ], "hex": "0200000001fc5d1634f2083b3d3969d169f4213e302850dac2bb5216cc402314360f268eb40100000000ffffffff0148f32200000000001976a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac00000000" } **Step 7.** To complete the transaction, the signature script must be inserted into the transaction template manually. To do so, copy and paste the hexadecimal representation of the transaction into a text editor. Use the transaction format documentation to decode it and find the right place for inserting the signature: https://bitcoin.stackexchange.com/a/72708 https://en.bitcoin.it/wiki/Transaction Version number (2): 02000000 Number of inputs (1) as varint: 01 Parent transaction: fc5d1634f2083b3d3969d169f4213e302850dac2bb5216cc402314360f268eb4 Parent transaction output index (1): 01000000 Signature script length (0) as varint: 00 Remainder of transaction: ffffffff0148f32200000000001976a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac00000000 **Step 8.** Replace the zero-length signature script with the actual signature script constructed earlier: Version number (2): 02000000 Number of inputs (1) as varint: 01 Parent transaction: fc5d1634f2083b3d3969d169f4213e302850dac2bb5216cc402314360f268eb4 Parent transaction output index (1): 01000000 Signature script length (46) as varint: 2e Signature script: 09726561642e636173682314b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777 Remainder of transaction: ffffffff0148f32200000000001976a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac00000000 Full transaction: `0200000001fc5d1634f2083b3d3969d169f4213e302850dac2bb5216cc402314360f268eb4010000002e09726561642e636173682314b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777ffffffff0148f32200000000001976a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac00000000` **Step 9.** Verify that the resulting transaction looks alright: $ bitcoin-tx -json 0200000001fc5d1634f2083b3d3969d169f4213e302850dac2bb5216cc402314360f268eb4010000002e09726561642e636173682314b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777ffffffff0148f32200000000001976a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac00000000 { "txid": "b73ad30dcba9ed29512ae2c8ea23d6c6bfd8786042e1347938b96e1b296b1f2c", "hash": "b73ad30dcba9ed29512ae2c8ea23d6c6bfd8786042e1347938b96e1b296b1f2c", "version": 2, "size": 131, "locktime": 0, "vin": [ { "txid": "b48e260f36142340cc1652bbc2da5028303e21f469d169393d3b08f234165dfc", "vout": 1, "scriptSig": { "asm": "726561642e63617368 14b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777", "hex": "09726561642e636173682314b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777" }, "sequence": 4294967295 } ], "vout": [ { "value": 0.02290504, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 40522a99ccae6f05b6a473cf9623a6a2cd1e42ac OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": [ "16s6gJN1t7yPZGfzUFvMo9xkFvN7MzjkHH" ] } } ], "hex": "0200000001fc5d1634f2083b3d3969d169f4213e302850dac2bb5216cc402314360f268eb4010000002e09726561642e636173682314b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777ffffffff0148f32200000000001976a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac00000000" } **Step 10.** Start the Bitcoin ABC node. Open the debug window via the help menu and go to the console tab. Read the scammer warning and laugh evilly, because this time you are the criminal. Then, summon the command list: $ help == Blockchain == (...) == Control == (...) == Generating == (...) == Mining == (...) == Network == (...) == Rawtransactions == combinepsbt ["psbt",...] combinerawtransaction ["hexstring",...] converttopsbt "hexstring" ( permitsigdata ) createpsbt [{"txid":"id","vout":n},...] [{"address":amount},{"data":"hex"},...] ( locktime ) createrawtransaction [{"txid":"id","vout":n},...] [{"address":amount},{"data":"hex"},...] ( locktime ) decodepsbt "psbt" decoderawtransaction "hexstring" decodescript "hexstring" finalizepsbt "psbt" ( extract ) fundrawtransaction "hexstring" ( options ) getrawtransaction "txid" ( verbose "blockhash" ) sendrawtransaction "hexstring" ( allowhighfees ) signrawtransactionwithkey "hexstring" ["privatekey1",...] ( [{"txid":"id","vout":n,"scriptPubKey":"hex","redeemScript":"hex"},...] sighashtype ) testmempoolaccept ["rawtxs"] ( allowhighfees ) == Util == (...) == Wallet == (...) **Step 11.** Find the transaction broadcast command `sendrawtransaction` and look up how it works: $ help sendrawtransaction sendrawtransaction "hexstring" ( allowhighfees ) Submits raw transaction (serialized, hex-encoded) to local node and network. Also see createrawtransaction and signrawtransactionwithkey calls. Arguments: 1. "hexstring" (string, required) The hex string of the raw transaction) 2. allowhighfees (boolean, optional, default=false) Allow high fees Result: "hex" (string) The transaction hash in hex Examples: Create a transaction > bitcoin-cli createrawtransaction "[{\"txid\" : \"mytxid\",\"vout\":0}]" "{\"myaddress\":0.01}" Sign the transaction, and get back the hex > bitcoin-cli signrawtransactionwithwallet "myhex" Send the transaction (signed hex) > bitcoin-cli sendrawtransaction "signedhex" As a json rpc call > curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "sendrawtransaction", "params": ["signedhex"] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/ **Step 12.** Now go for it. Don't let your dreams be dreams. Join the dark side. Commit the crime: $ sendrawtransaction 0200000001fc5d1634f2083b3d3969d169f4213e302850dac2bb5216cc402314360f268eb4010000002e09726561642e636173682314b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777ffffffff0148f32200000000001976a91440522a99ccae6f05b6a473cf9623a6a2cd1e42ac88ac00000000 Alea iacta est. If the heist succeeds, Electron Cash will quickly detect an incoming transaction. But since the transaction has no cryptographic signature, the booty can still be stolen by a miner even more evil than you - until the transaction is confirmed. Electron Cash will then CashShuffle the proceeds to make it untraceable. Just make sure to avoid spending the shuffled coins together. https://blockchair.com/bitcoin-cash/transaction/b73ad30dcba9ed29512ae2c8ea23d6c6bfd8786042e1347938b96e1b296b1f2c https://honest.cash/v2/BigBlockIfTrue/blockchain-analysis-versus-cashshuffle-tracking-the-300-bch-donation-to-bitcoin-unlimited-5153 Proof of success Message: `All Read.cash's $5 are belong to BigBlockIfTrue!` Address: `qpq9y25eejhx7pdk53eul93r563v68jz4s4stdkf5j` Signature: `IDuoVZb/0Qm+TAaKMdvf4wbR0WvW/iq1zwN3VwYqf4xSDVY9kxfN3cu3pJ2rnbufmvbjntP9T+eAQ1suPPZIHDw=`
9 comments
Signature verified! Well done! :) The heist: https://explorer.bitcoin.com/bch/tx/b73ad30dcba9ed29512ae2c8ea23d6c6bfd8786042e1347938b96e1b296b1f2c
Wait, what are the negatives? I see only positives here - heist accomplished, we can see read.cash's password recovery works great, and ... uh oh, people are probably working on a brute force recovery cracker based on your instructions ... ok, I see the possible negative now :-p But future users of the scheme ought to be using a password manager, to generate strong recovery passwords instead of simple ones like "read.cash".
I mention it actually in the article: > The constantly happening brute-force means though, that the "recovery" word should still be at least a bit harder than "mom" to avoid accidental recoveries (which again is more of a nuisance, rather than a security problem). > Maybe the wallet can add something like the birthdate to the recovery word of the user to avoid "accidental" recoveries. (Which are again only are an inconvenience, not a security problem) Also worth noting that "read.cash" heist address wasn't protected with CHECKDATASIG, so the money could be **taken** by attacker. Not the case with CHECKDATASIG protected addresses. > Even though it doesn't even make sense to spend the time guessing your recovery word, since all it can do is send the money to your another trusted account (a minor inconvenience at best). So I don't think we need "strong" passwords, but rather a bit of password-stretching, like "add your birthday", the wallet can also add its name. Should be more than enough, since the hacker won't achieve anything except causing a minor inconvenience to the user. But I'm also curious what downsides BigBlockIfTrue sees.
> But I'm also curious what downsides BigBlockIfTrue sees. Me too, I don't see any real negatives (if using CHECKDATASIG protection). I wouldn't downplay unwanted recovery activation as merely a 'nuisance' as you did in your original article, but it's certainly not a big funds loss risk (other than recovery destination wallet being inaccessible for some reason). And it can be mitigated with something like your "birthday" suggestion.
Thank you! > nuisance Sure, but how would you describe it. Yeah, it's a hassle that you'd have to re-do the ritual of returning funds, but in the grand scheme of things - it's not a big deal at all. Maybe, 'inconvenience'?
I posted a more serious response to the proposal [here](https://read.cash/@Read.Cash/recoverable-bitcoin-cash-wallets-2918c893#comment-46bbd9ce). :)
cool! congratulations on your successful heist! Now don't spend the booty too visibly or else they will catch you that way ;-) with the tools you mentioned, how did you compile the script (b251f93c45baea5c72bae18311c75eccad404291 OP_OVER 'read.cash' OP_EQUAL OP_NIP OP_NIP) to 14b251f93c45baea5c72bae18311c75eccad4042917809726561642e63617368877777?
Actually the script was already given in the example transaction included in the mission briefing, so there was no need to compile it. I used the `decodescript` command in the Bitcoin ABC console to make it readable. To encode/decode scripts manually you can use the [opcode list on the Bitcoin wiki](https://en.bitcoin.it/wiki/Script#Opcodes).
Very useful information. It is technically detailed and well structured for easy understanding. Thank you for the information