Bitcoin Forum
June 25, 2026, 07:14:43 AM *
News: Latest Bitcoin Core release: 31.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: « 1 [2]  All
  Print  
Author Topic: A breakable P2SH address - Bitcoin testnet inside  (Read 711 times)
BrewMaster
Legendary
*
Offline

Activity: 2128
Merit: 1293


There is trouble abrewing


View Profile
August 04, 2020, 02:24:51 PM
 #21

1) Correct me if I'm wrong but unlocking scripts must, to the best of knowledge, be "push only", and if you include any other opcode you will get "64: scriptsig-not-pushonly" (I've hit this wall a number of times)
that is only if you want it to be standard.
unfortunately 90% of the things we read on forums, SE, documentation,... that say "must be" are talking about standard rules.
SCRIPT_VERIFY_SIGPUSHONLY  flag is only added to standard rules and doesn't exist during block verification.

to test this you have to mine the block yourself!

Quote
2) If you fiddle around with the locking script, its hash will change which will invalidate the transaction?
the transaction hash will change but it won't make the transaction invalid. because the transaction you are verifying is not using its own hash.

that is what malleability is. fiddling around with the transaction scripts to change its hash and cause troubles. most of the cases are already fixed and can no longer happen. they are explained in BIP-62.
for example OP_CHECKMULTISIG(VERIFY) OPs pop an extra item from the stack and is ignored so it could be anything. an attacker could easily change it to any other push and create any number of still valid transactions each with a different hash. with SegWit softfork this can no longer happen. the flag is SCRIPT_VERIFY_NULLDUMMY which you can see is used during verification too.

i should also mention that all bitcoin core nodes reject all non-standard transactions so malleability is not a problem because it is practically impossible to perform.

There is a FOMO brewing...
BTCW (OP)
Copper Member
Full Member
***
Offline

Activity: 196
Merit: 284

Click "+Merit" top-right corner


View Profile
August 04, 2020, 02:32:29 PM
 #22

1) Correct me if I'm wrong but unlocking scripts must, to the best of knowledge, be "push only", and if you include any other opcode you will get "64: scriptsig-not-pushonly" (I've hit this wall a number of times)
that is only if you want it to be standard.
unfortunately 90% of the things we read on forums, SE, documentation,... that say "must be" are talking about standard rules.
SCRIPT_VERIFY_SIGPUSHONLY  flag is only added to standard rules and doesn't exist during block verification.

to test this you have to mine the block yourself!

Quote
2) If you fiddle around with the locking script, its hash will change which will invalidate the transaction?
the transaction hash will change but it won't make the transaction invalid. because the transaction you are verifying is not using its own hash.

that is what malleability is. fiddling around with the transaction scripts to change its hash and cause troubles. most of the cases are already fixed and can no longer happen. they are explained in BIP-62.
for example OP_CHECKMULTISIG(VERIFY) OPs pop an extra item from the stack and is ignored so it could be anything. an attacker could easily change it to any other push and create any number of still valid transactions each with a different hash. with SegWit softfork this can no longer happen. the flag is SCRIPT_VERIFY_NULLDUMMY which you can see is used during verification too.

i should also mention that all bitcoin core nodes reject all non-standard transactions so malleability is not a problem because it is practically impossible to perform.

1) Yeah, I know about standardness. I "only" have access to Bitcoin Core, Electrum, and the online push raw tx tools, and while Blockcypher seems to be the most relaxed of them, not even that one allows non-push codes in the unlocking script. I am not a miner (on the mainnet, duh); if I were, we wouldn't sit here and have this conversation, I think Smiley (Satoshi's first versions allowed all opcodes in the unlocking script, but that's pretty crazy because you can use that to drain computational power of all nodes)

2) Gotcha. Thanks for pointing that out. Are you saying a complete redeem (unlocking+locking) script of "030151" would have unlocked my first UTXO, first address example in this thread? If so, cool. Gotta try out.

SendBTC.me <<< amazing imitative
BrewMaster
Legendary
*
Offline

Activity: 2128
Merit: 1293


There is trouble abrewing


View Profile
August 04, 2020, 03:02:58 PM
 #23

1) Yeah, I know about standardness. I "only" have access to Bitcoin Core, Electrum, and the online push raw tx tools, and while Blockcypher seems to be the most relaxed of them, not even that one allows non-push codes in the unlocking script. I am not a miner (on the mainnet, duh); if I were, we wouldn't sit here and have this conversation, I think Smiley (Satoshi's first versions allowed all opcodes in the unlocking script, but that's pretty crazy because you can use that to drain computational power of all nodes)
you can always mine in regtest mode. the difficulty is too low that you can mine thousands of blocks within seconds and it won't go up either.
but for now here is a test case that has OP_CHECKSIG inside scriptsig:
https://github.com/bitcoin/bitcoin/blob/b53af72b8276e8a23915d38fe459889cccb56f50/src/test/data/tx_valid.json#L169

Quote
2) Gotcha. Thanks for pointing that out. Are you saying a complete redeem (unlocking+locking) script of "030151" would have unlocked my first UTXO, first address example in this thread? If so, cool. Gotta try out.
the data part could be anything but you still need at least 2 items (since OP codes like NIP and SWAP need 2 items) and they could be anything even un-equal values since it seems like your redeemscript is dropping the comparison result from the stack anyways so it won't matter.
also the redeem script itself must be there too.

by the way 030151 is an invalid script because it has 2 bytes instead of 3 (0x03 + 0x0151)

There is a FOMO brewing...
BTCW (OP)
Copper Member
Full Member
***
Offline

Activity: 196
Merit: 284

Click "+Merit" top-right corner


View Profile
August 04, 2020, 07:05:06 PM
 #24

1) Yeah, I know about standardness. I "only" have access to Bitcoin Core, Electrum, and the online push raw tx tools, and while Blockcypher seems to be the most relaxed of them, not even that one allows non-push codes in the unlocking script. I am not a miner (on the mainnet, duh); if I were, we wouldn't sit here and have this conversation, I think Smiley (Satoshi's first versions allowed all opcodes in the unlocking script, but that's pretty crazy because you can use that to drain computational power of all nodes)
you can always mine in regtest mode. the difficulty is too low that you can mine thousands of blocks within seconds and it won't go up either.
but for now here is a test case that has OP_CHECKSIG inside scriptsig:
https://github.com/bitcoin/bitcoin/blob/b53af72b8276e8a23915d38fe459889cccb56f50/src/test/data/tx_valid.json#L169

Quote
2) Gotcha. Thanks for pointing that out. Are you saying a complete redeem (unlocking+locking) script of "030151" would have unlocked my first UTXO, first address example in this thread? If so, cool. Gotta try out.
the data part could be anything but you still need at least 2 items (since OP codes like NIP and SWAP need 2 items) and they could be anything even un-equal values since it seems like your redeemscript is dropping the comparison result from the stack anyways so it won't matter.
also the redeem script itself must be there too.

by the way 030151 is an invalid script because it has 2 bytes instead of 3 (0x03 + 0x0151)

Oops, byte padding above is of course 02 and not 03, apart from the little fact that 01 in there makes no sense; I meant "025151" (Note to self: preview and proofread before posting)

Alright, so show me your kung fu BrewMaster!

I threw together a new locking script (only difference is pushing different gibberish 8-byte strings twice, to get a unique address)

Code:
OP_SIZE
OP_SWAP
OP_SIZE
OP_NIP
8 0xd7a41d9c57b451da
OP_ROT
OP_ROT
OP_EQUAL
OP_ROT
OP_DROP
OP_SWAP
OP_DROP
OP_1
8 0x99b51d4455b651db
OP_DROP
OP_EQUAL

and sent 0.1 tBCT to it.

(The to me anonymous person who took it the first time suddenly returned it a while ago, tyvm.)

If you can spend it with a complete redeem script SHORTER than

"<1-byte size padding>025151<32-byte locking script>"

I will be impressed! Show me. (Just snatching it with the above code is "meh".)



Also everyone - challenge 2 is still on!
(It is admittedly harder, but by no means unsolvable, all data needed to break it has been mentioned in this thread.)



SendBTC.me <<< amazing imitative
BTCW (OP)
Copper Member
Full Member
***
Offline

Activity: 196
Merit: 284

Click "+Merit" top-right corner


View Profile
August 05, 2020, 01:40:20 AM
Last edit: August 05, 2020, 10:20:09 AM by BTCW
Merited by LoyceV (6), ABCbits (3)
 #25

Challenge 2 - we have a winner!

Wowzers!! Looks like someone cracked my challenge 2 (but is for some reason not interested in writing about it here?!).



This transaction is proof of sweeping 2MsucLKM489owxv6emXfCVRCZ3UFb7MnXCR

I suppose it's my job to disclose how it was constructed, and thus how it can be robbed.

To increase difficulty I decide to go with a multisig address (2-of-2 to be exact).

In order to create a multisig address (I will now mention HD and deterministic wallets, BIP32, xpriv, xpub and such terms here) you need several private keys. In this example, two private keys to be precise. What is a private key? Well, it is a random (HOPEFULLY) 256-bit/32-byte number, which is often written out as 64 character hexadecimal strings.

Remember my fake unlocking script in the first example? This:

Code:
32 0x2803d055a4a133bde555a39d37762c8354b6f7418817c5c4b516cf413b280209
32 0x3dbb8323f94bf9acd13a5f92e0d0a7e87f34e31b09a866fdc80437a57e24a114

So I took these pseudorandom numbers and converted them to Bitcoin-testnet private key (using my favorite tool)

This gave:

Key 1 of 2
Code:
Private key hex: 2803d055a4a133bde555a39d37762c8354b6f7418817c5c4b516cf413b280209
Compression: YES*
Testnet private key WIF: cNvV73g3NgnSRtX4jfENnDBgQNaVqg7YYYuNpS8SBm41UuZxmrAi
Testnet public key: 02fcc55dca84d81390bf05fe301c49771e4de96039acd54d1ab2fe49ce36bc041e
Testnet public address: mqNsE5yRBcRhfkKiFZqPxRfS6B7V2hqUtT

Key 2 of 2
Code:
Private key hex: 3dbb8323f94bf9acd13a5f92e0d0a7e87f34e31b09a866fdc80437a57e24a114
Compression: YES*
Testnet private key WIF :cPehe5iiYgmNCKTVyiytGVh3g1pyQMQDSSidaKJcTVPt8gm1bcgD
Testnet public key: 031033d9c6d66b3222df19cc5dfb7022b314bf035115f7cd76f72934863adebf69
Testnet public address: n3iBcnhmJ7oLk4gKjfJiFCk3hSb4LZJe3J

Great. A short comment on compressed vs uncompressed keys: Whenever I can, I always choose compressed; so should you. I then decided to throw them together in Bitcoin Core (google says it's impossible in Electrum, but I'm working on a work-around for it, almost done, watch this space).

In Bitcoin Core (remember to run in testnet mode) console, you first need to get hold your redeem script, and it can be done with

Code:
createmultisig 2 '["02fcc55dca84d81390bf05fe301c49771e4de96039acd54d1ab2fe49ce36bc041e","031033d9c6d66b3222df19cc5dfb7022b314bf035115f7cd76f72934863adebf69"]'

As can be seen, we are using two public keys and NOT private keys or public adddresses; very common mistakes), and it spits out

Code:
{
  "address": "2MsucLKM489owxv6emXfCVRCZ3UFb7MnXCR",
  "redeemScript": "522102fcc55dca84d81390bf05fe301c49771e4de96039acd54d1ab2fe49ce36bc041e21031033d9c6d66b3222df19cc5dfb7022b314bf035115f7cd76f72934863adebf6952ae",
}

There is our redeem script, that we will use in the second step, still in the console (here we feed it with everything: public addresses, private keys, redeem script)

Code:
importmulti '[{ "scriptPubKey": { "address": "2MsucLKM489owxv6emXfCVRCZ3UFb7MnXCR" }, "timestamp":"now", "keys": [ "cNvV73g3NgnSRtX4jfENnDBgQNaVqg7YYYuNpS8SBm41UuZxmrAi","cPehe5iiYgmNCKTVyiytGVh3g1pyQMQDSSidaKJcTVPt8gm1bcgD" ], "redeemscript": "522102fcc55dca84d81390bf05fe301c49771e4de96039acd54d1ab2fe49ce36bc041e21031033d9c6d66b3222df19cc5dfb7022b314bf035115f7cd76f72934863adebf6952ae"}]' '{"rescan": false}'

If done right it should reply with a "success!" message.

Now the address is in our wallet, but it is watch-only, since we haven't fed it with the private keys (I have no idea why the last command doesn't associate the provided private keys), so - still in console:

Code:
importprivkey cNvV73g3NgnSRtX4jfENnDBgQNaVqg7YYYuNpS8SBm41UuZxmrAi key1 false
importprivkey cPehe5iiYgmNCKTVyiytGVh3g1pyQMQDSSidaKJcTVPt8gm1bcgD key2 false

Then, for the finale, issue:

Code:
rescanblockchain

It will take several minutes of a fast computer with an SSD. Grab a coffee while waiting.

Done! You now have full control over 2MsucLKM489owxv6emXfCVRCZ3UFb7MnXCR and can spend from it like any other address in your wallet.

Prolog: I figured recycling two already mentioned 32-byte strings, using them as private keys, and joining them together in a multisig address was fun.



We good?

SendBTC.me <<< amazing imitative
A-Bolt
Legendary
*
Offline

Activity: 2383
Merit: 2602


View Profile
August 05, 2020, 09:46:24 AM
Last edit: August 05, 2020, 10:54:33 AM by A-Bolt
Merited by BTCW (2), ABCbits (1)
 #26

Wowzers!! Looks like someone cracked my challenge 2 (but is for some reason not interested in writing about it here?!).

Here I am. I created multisig address in a different way:

Code:
importprivkey cNvV73g3NgnSRtX4jfENnDBgQNaVqg7YYYuNpS8SBm41UuZxmrAi sig1 false
importprivkey cPehe5iiYgmNCKTVyiytGVh3g1pyQMQDSSidaKJcTVPt8gm1bcgD sig2 false

addmultisigaddress 2 "[\"mqNsE5yRBcRhfkKiFZqPxRfS6B7V2hqUtT\",\"n3iBcnhmJ7oLk4gKjfJiFCk3hSb4LZJe3J\"]"

rescan

Then I made spent tx in Bitcoin Core GUI.

BTCW (OP)
Copper Member
Full Member
***
Offline

Activity: 196
Merit: 284

Click "+Merit" top-right corner


View Profile
August 06, 2020, 11:49:14 AM
 #27


Alright, so show me your kung fu BrewMaster!

I threw together a new locking script (only difference is pushing different gibberish 8-byte strings twice, to get a unique address)

Code:
OP_SIZE
OP_SWAP
OP_SIZE
OP_NIP
8 0xd7a41d9c57b451da
OP_ROT
OP_ROT
OP_EQUAL
OP_ROT
OP_DROP
OP_SWAP
OP_DROP
OP_1
8 0x99b51d4455b651db
OP_DROP
OP_EQUAL

and sent 0.1 tBCT to it.

(The to me anonymous person who took it the first time suddenly returned it a while ago, tyvm.)

If you can spend it with a complete redeem script SHORTER than

"<1-byte size padding>025151<32-byte locking script>"

I will be impressed! Show me. (Just snatching it with the above code is "meh".)


OK, full disclosure, I couldn't wait more than two days, so I took it back. In your name, BrewMaster, so to speak! The unlocking code I used was

Code:
4 0x42726577 #ASCII to hex for "Brew"
6 0x4d6173746572 #ASCII to hex for "Master"

And as you had pointed out, this proves that my not-very-awesome script doesn't really compare input lengths as I thought it did, since 0x04 is obviously not equal to 0x06 - you were right all along. (However, I was never able to get anything that included changes to or completely omitting the locking code to work.)

Tx id: 42f6d6ba8317afcc7b6e54d6cc09839f7cc224ca9bf26c0c026432b1fa9c3f44

Raw rx:
Code:
010000000186683e20bde5167c89deb085f5ba00ac6f00b9592f5e21dde674df2f5cbcaf94010000002d0442726577064d617374657220827c827708d7a41d9c57b451da7b7b877b757c75510899b51d4455b651db7587ffffffff01b08e98000000000017a914628cde58e1bcd42efb72b1821ec9fdf49e0f1d498700000000

This was fun and instructive. Now on to new adventures.



Suggestions, anyone?

SendBTC.me <<< amazing imitative
Pages: « 1 [2]  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!