Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: BTCW on August 03, 2020, 11:12:18 AM



Title: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 03, 2020, 11:12:18 AM
Long story short, I created this not-very-standard P2SH public address: 2NA4ZpHbzfp7VkAXHjpZc8Ze6SpNfS7jSbF (https://www.blockchain.com/btc-testnet/address/2NA4ZpHbzfp7VkAXHjpZc8Ze6SpNfS7jSbF)

And gave it some history on the blockchain (hint!) and just funded it again with 0.11111111 tBTC

Show me you can break it and sweep the coins!

It's NOT of those "try and bruteforce my 32-byte private key" or the like. The solution is simple.

If no one has touched the coins in a day or so, I'll show you exactly how.

Do it!



Edit: The updated challenge is here (https://bitcointalk.org/index.php?topic=5266364.msg54931963#msg54931963)


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: stalker00075 on August 03, 2020, 12:10:25 PM
but tBTC has no price...


meaning to waste time


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 03, 2020, 12:59:08 PM
but tBTC has no price...


meaning to waste time

Who says this exact same setup doesn't exist on the mainnet? Testnet is great for exercises like this, so we can take what we learn and apply it to the mainnet after.

Edit/clarifiaction: Let's caluculate the "mainnet twin" to the address (Python):

Code:
>>> import binascii, hashlib, base58
>>> hash160 = binascii.hexlify(base58.b58decode_check(b'2NA4ZpHbzfp7VkAXHjpZc8Ze6SpNfS7jSbF')).decode()[2:]
>>> hash160
'b8761d30be6f2408882e0b458f8fdfc4c896ed45'
>>> base58.b58encode_check(binascii.unhexlify('05'+hash160)).decode()
'3JWMkYfy4Mc9YNtk4gwjWceqEUAViUiMF5'
>>> base58.b58encode_check(binascii.unhexlify('c4'+hash160)).decode()
'2NA4ZpHbzfp7VkAXHjpZc8Ze6SpNfS7jSbF'

In other words, if you can spend from 2NA4ZpHbzfp7VkAXHjpZc8Ze6SpNfS7jSbF on the testnet, you can use the exact same "recipe" to spend from 3JWMkYfy4Mc9YNtk4gwjWceqEUAViUiMF5 on the mainnet, should it ever pop up there.

Cool?


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: DaCryptoRaccoon on August 03, 2020, 01:29:26 PM
This is very interesting @BTCW.

I have a few transaction I would like to ask you about that you may know how I can resolve.

PM sent


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BrewMaster on August 03, 2020, 05:15:36 PM
Show me you can break it and sweep the coins!

It's NOT of those "try and bruteforce my 32-byte private key" or the like. The solution is simple.

well unless you consider cheating to be a "solution", it is not possible to break something like this even if you knew the number of OP codes inside the script or knew the ballpark of their type. it contains 14 OP codes that are never used (ROT, SWAP, NIP, SIZE, ...) and 2 random data pushes!


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 03, 2020, 05:58:16 PM
Show me you can break it and sweep the coins!

It's NOT of those "try and bruteforce my 32-byte private key" or the like. The solution is simple.

well unless you consider cheating to be a "solution", it is not possible to break something like this even if you knew the number of OP codes inside the script or knew the ballpark of their type. it contains 14 OP codes that are never used (ROT, SWAP, NIP, SIZE, ...) and 2 random data pushes!

It is easier than you think to break it. And someone just did:

https://www.blockchain.com/btc-testnet/tx/023f0dde4d0b11581cb81214462170995b85ec6be41c78c5fb44084c7d9e671a

I don't know whether it was someone reading here or not.

Edit: I will update with a more exhaustive answer and an even more elegant solution than simply copying the signatures from the first spending, as the "thief" in this case apparently did.


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 03, 2020, 10:33:58 PM
Alright, let's talk about Bitcoin scripts and its opcodes (https://en.bitcoin.it/wiki/Script#Opcodes).

A transaction is (partly - the most interesting part of it) an unlocking script and a locking script, which are combined - in that very order, evaluated (executed - run as a program), and must return "TRUE" (which technically means that the stack must contain a positive integer top value and nothing else).

A P2SH address is simply the base58check encoded version of the hashed locking script, so that it impossible to examine a "3-address" and determine its script (since it is hashed). This is where previous blockchain data comes in because my example address couldn't have been compromised if I hadn't prepared things for you and already spent from it once (https://www.blockchain.com/btc-testnet/tx/dc292511e0474034ae693b6d3aa05c474d17fcec7b8ba261671077a4bac9100c) before writing the OP.

Let's take it step by step.

While there are some common formats for P2SH scripts (such as "OP_HASH160 20 <a 20-byte hex string> OP_EQUAL") there is nothing that says that a P2SH address must adhere to any certain format. In fact, more complex scripts not only allowed but actually encouraged by Bitcoin. Multisig scripts, for example, can be very complex and contain a shitload of IF/THEN conditions. Remember however that when making a script, there must exist conditions for it (together with its inputs in the unlocking script) so that it may return "TRUE". If not, it is an unspendable address (and such addresses are curiously simple to create; you have been warned - don't unintentionally create Bitcoin black holes).

Let me lay out the locking script, so I can comment on it (and yes, I did use a few uncommon opcodes, but that's not illegal - they are standard by definition):

Code:
OP_SIZE
OP_SWAP
OP_SIZE
OP_NIP
8 0xd9ac1d9c37b651db
OP_ROT
OP_ROT
OP_EQUAL
OP_ROT
OP_DROP
OP_SWAP
OP_DROP
OP_1
8 0x99ac1d9c37b651db
OP_DROP
OP_EQUAL

It is quite messy, and intentionally so, but it can be deciphered. Basically, what it does it that is takes two inputs, calculates their sizes (and not their values!) and if they are equal, it will (again together with the unlocking code below) return "TRUE".

This locking script shuffles around stack values like crazy and adds instances of gibberish 8-byte strings twice, which are never evaluated but simply dropped. Also, since the script will be serialized (converted to a hexadecimal string), I was very happy to end up with an exactly 32-byte script, since I figured that strings of that length are easily mistaken for hash values and/or signatures. The serialized locking script is thus

Code:
0x827c827708d9ac1d9c37b651db7b7b877b757c75510899ac1d9c37b651db7587

and this is easily converted to testnet public address 2NA4ZpHbzfp7VkAXHjpZc8Ze6SpNfS7jSbF and mainnet public address 3JWMkYfy4Mc9YNtk4gwjWceqEUAViUiMF5 with a few lines of Python (see previous post by yours truly) or if you're even lazier (or smarter, depending on your your world-view) using a web service (one linked below).

So, the unlocking script then. Again, I went for 32-byte strings, for the same reason; easily mistaken for hashes that actually represent something. But I simply generated two random hexadecimal numbers with bash command "openssl rand -hex 32" (which - by the way - is an excellent one-liner for producing unbreakable private keys), so that:

Code:
32 0x2803d055a4a133bde555a39d37762c8354b6f7418817c5c4b516cf413b280209
32 0x3dbb8323f94bf9acd13a5f92e0d0a7e87f34e31b09a866fdc80437a57e24a114

Looks really serious, doesn't it?

Remember though, these numbers are completely random and are never evaluated! The only requirement by my script is that two inputs of equal length are provided. This means that another unlocking script that would have and will work equally well for this address is (this is what I hoped someone would realize):

Code:
OP_1
OP_1

Oh yeah, this will work too:

Code:
OP_4
OP_7

Same length, not values - remember?


If you want to see the unlocking and locking scripts together, how they are evaluated step by step and how this crazy combination eventually leads to "TRUE", here they are together (this page is in my humble opinion awesome for P2SH experiments):

https://bitcoin-script-debugger.visvirial.com/?input=32%200x2803d055a4a133bde555a39d37762c8354b6f7418817c5c4b516cf413b280209%2032%200x3dbb8323f94bf9acd13a5f92e0d0a7e87f34e31b09a866fdc80437a57e24a114%20OP_SIZE%20OP_SWAP%20OP_SIZE%20OP_NIP%208%200xd9ac1d9c37b651db%20OP_ROT%20OP_ROT%20OP_EQUAL%20OP_ROT%20OP_DROP%20OP_SWAP%20OP_DROP%20OP_1%208%200x99ac1d9c37b651db%20OP_DROP%20OP_EQUAL

Note especially the green "Result: OK".

The person (or bot? - I still don't know who cracked it) simply did a copy/paste of the combined unlocking and locking script from my first spending

Code:
63202803d055a4a133bde555a39d37762c8354b6f7418817c5c4b516cf413b280209203dbb8323f94bf9acd13a5f92e0d0a7e87f34e31b09a866fdc80437a57e24a11420827c827708d9ac1d9c37b651db7b7b877b757c75510899ac1d9c37b651db7587

and used it unchanged to create a new transaction (https://www.blockchain.com/btc-testnet/tx/023f0dde4d0b11581cb81214462170995b85ec6be41c78c5fb44084c7d9e671a). To view the raw transation, it can be done in Bitcoin Core console using "getrawtransaction 023f0dde4d0b11581cb81214462170995b85ec6be41c78c5fb44084c7d9e671a" or in Electrum console using "gettransaction('023f0dde4d0b11581cb81214462170995b85ec6be41c78c5fb44084c7d9e671a')", but remember to start them in testnet mode before trying.

In other words, the next time you want to snatch coins from these addresses, try the shorter redeem code:

Code:
23515120827c827708d9ac1d9c37b651db7b7b877b757c75510899ac1d9c37b651db7587

Unless you didn't already know OP_1 is "51" in hexadecimal, why the string begins with two instances of that.

Phew... that took some time to write up...

I hope you liked it, and in that casse feel free to pass over some testnet coins to 2N2EJxoRy5hRE74aV4NDiC22dcH3QEqzf5G, because I was just robbed of almost all I had there :)



Edit/additions:

1) To clarify further, what I tried to accomplish with three different 32-byte strings as the Sigcode

Code:
2803d055a4a133bde555a39d37762c8354b6f7418817c5c4b516cf413b280209
3dbb8323f94bf9acd13a5f92e0d0a7e87f34e31b09a866fdc80437a57e24a114
827c827708d9ac1d9c37b651db7b7b877b757c75510899ac1d9c37b651db7587

which are the values you see when you look at a transaction in a block explorer (https://www.blockchain.com/btc-testnet/tx/023f0dde4d0b11581cb81214462170995b85ec6be41c78c5fb44084c7d9e671a) was an attempted deception. I.e NOT "hey, this looks like a broken signature".

2) Speaking of signatures. I should have written earlier that my script does zero signature evaluation and there is no elliptic curve cryptography (ECC) anywhere, why the address is another "anyone-can-spend" now that the required inputs have been disclosed, so any old redeem code that has worked will work again.




Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BrewMaster on August 04, 2020, 05:21:15 AM
It is easier than you think to break it. And someone just did:

i don't know if you don't know the meaning of the word "break" or just misusing it but this is not what "breaking" means. breaking would be if and only if the only thing that was revealed were the hash of the script and nothing else.
as i said there is absolutely no way of breaking it when it is only the hash. but when you have already revealed the script here (https://www.blockchain.com/btc-testnet/tx/dc292511e0474034ae693b6d3aa05c474d17fcec7b8ba261671077a4bac9100c) (which anyone can spend) all it takes is a copy and paste of it into a new transaction spending the new output(s).


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: TheArchaeologist on August 04, 2020, 06:21:32 AM
I am not sure what you tried to accomplish with this "breakable P2SH address"  challenge. That would imply you could either reverse the hash so the input of the hash would become apparent or bruteforce the script content so it would hash to the same value and in turn to the same address of the "challenge".

Instead you created a unguessable complicated anyone-can-spend script,  and since you know what the script was you used it to unlock it in a testnet transaction. Then the solution to your "challenge" is to simply copy and paste the unlocking script from the previous transaction to re-use. So the content of the script itself is completely irrelevant, this would work for any script that is made up of anyone-can-spend content.

All in all there was nothing to break in your "challenge" in the first place.


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 04, 2020, 09:13:59 AM
It is easier than you think to break it. And someone just did:

i don't know if you don't know the meaning of the word "break" or just misusing it but this is not what "breaking" means. breaking would be if and only if the only thing that was revealed were the hash of the script and nothing else.
as i said there is absolutely no way of breaking it when it is only the hash. but when you have already revealed the script here (https://www.blockchain.com/btc-testnet/tx/dc292511e0474034ae693b6d3aa05c474d17fcec7b8ba261671077a4bac9100c) (which anyone can spend) all it takes is a copy and paste of it into a new transaction spending the new output(s).

I tried to disguise an anyone-can-spend P2SH address as well as I could so that a spending on the blockchain (the first) would contain three 32-byte strings as the sigscript. That was all.

After someone else redeemed the coins, I later showed that my much shorter unlocking code "OP_1 OP_1" can be used, tx here (https://www.blockchain.com/btc-testnet/tx/e6561858d5e50f173bae82de206633abbfc5decdf8e3853b50d0ecd3c2c21d92).

I'm honestly not convinced someone would have noticed anything if I hadn't written about it here. In fact, thus is very testable: I'll make another similar but not identical "crazy" script, fund it, spend from it, fund it again, but write nothing about it for several days. And see what happens.

I'm not sure I follow your reasoning around the word "breaking". R- and S-reuse, for example, the good old classic bad (static nonce) signature that leads to private key leakage, is that "breaking" or "f-ck obvious"?









Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 04, 2020, 09:19:32 AM
I am not sure what you tried to accomplish with this "breakable P2SH address"  challenge. That would imply you could either reverse the hash so the input of the hash would become apparent or bruteforce the script content so it would hash to the same value and in turn to the same address of the "challenge".

Instead you created a unguessable complicated anyone-can-spend script,  and since you know what the script was you used it to unlock it in a testnet transaction. Then the solution to your "challenge" is to simply copy and paste the unlocking script from the previous transaction to re-use. So the content of the script itself is completely irrelevant, this would work for any script that is made up of anyone-can-spend content.

All in all there was nothing to break in your "challenge" in the first place.

I promise to be more pedagogical in coming write-ups (if there will be any). In this case, the challenge could have been "using different signatures" and the simplest answer would be "OP_1 OP_1".



Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BrewMaster on August 04, 2020, 09:25:57 AM
I tried to disguise an anyone-can-spend P2SH address as well as I could so that a spending on the blockchain (the first) would contain three 32-byte strings as the sigscript. That was all.
well the moment you posted the link to that address here (the first line of this topic) that disguise stopped working.

Quote
After someone else redeemed the coins, I later showed that my much shorter unlocking code "OP_1 OP_1" can be used, tx here (https://www.blockchain.com/btc-testnet/tx/e6561858d5e50f173bae82de206633abbfc5decdf8e3853b50d0ecd3c2c21d92).
you found one case of transaction malleability.
it doesn't matter what you place before your redeem script, it can even be empty or it can contain lots of OP codes, it still evaluates the same.
by the way it has nothing to do with "breaking the redeem script".

Quote
I'm honestly not convinced someone would have noticed anything if I hadn't written about it here.
you are probably right but only because it is "testnet" and it has no value. doing the same on mainnet would surely lead to an immediate double spending of the same coins by multiple transactions, more if the value is high (like 0.1BTC which is worth $1100+).

Quote
I'm not sure I follow your reasoning around the word "breaking". R- and S-reuse, for example, the good old classic bad (static nonce) signature that leads to private key leakage, is that "breaking" or "f-ck obvious"?
well there is no signature involved anywhere in your transaction as there is no OP_CHECK(MULTI)SIG(VERIFY) OP codes anywhere in it. we are talking about an arbitrary script that anyone can spend and is also revealed already.


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: TheArchaeologist on August 04, 2020, 09:36:44 AM
I promise to be more pedagogical in coming write-ups (if there will be any). In this case, the challenge could have been "using different signatures" and the simplest answer would be "OP_1 OP_1".
Maybe you should try to understand these thing a bit better yourself before trying to educate others. There are none, 0, zilch signatures involved in your "challenge".


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 04, 2020, 09:37:56 AM

you found one case of transaction malleability.
it doesn't matter what you place before your redeem script, it can even be empty or it can contain lots of OP codes, it still evaluates the same.
by the way it has nothing to do with "breaking the redeem script".

This isn't correct. I designed the locking script so it requires exactly two pushes of equal string length. An empty unlocking script will fail. Also, "lots of OP codes" will fail too.


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 04, 2020, 09:44:51 AM
I promise to be more pedagogical in coming write-ups (if there will be any). In this case, the challenge could have been "using different signatures" and the simplest answer would be "OP_1 OP_1".
Maybe you should try to understand these thing a bit better yourself before trying to educate others. There are none, 0, zilch signatures involved in your "challenge".

You quoted me faster than I could edit my post. I shouldn't have used the word "signatures", it is misleading. As already said, this is an anyone-can-spend as there is no signing going on anywhere.

Again, all I did was to try and create a transaction that looked like it required signatures.

I hear you loud and clear. You don't like write-ups of this kind. Will refrain from posting further.


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BASE16 on August 04, 2020, 12:16:17 PM
A script can be anything.
Anything is quite a broad thing, since it includes everything.

Here is a small 1 BTC challenge for you to solve: https://bitaps.com/mnemonic/challenge (https://bitaps.com/mnemonic/challenge)

Those aren't test coins  :)


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 04, 2020, 12:54:51 PM
A script can be anything.
Anything is quite a broad thing, since it includes everything.

Here is a small 1 BTC challenge for you to solve: https://bitaps.com/mnemonic/challenge (https://bitaps.com/mnemonic/challenge)

Those aren't test coins  :)

Nice bounty program. That address was funded six weeks or so ago, so I guess I wasn't in mind then. By the way, a point of the elliptic curve can be almost anything (well, within the secp256k1 parameters, an insanely large but not infinite space), but a script cannot "include everything", since it is a program that must run and evaluate to "TRUE".



Title: Re: A breakable P2SH address - Bitcoin testnet inside [updated]
Post by: BTCW on August 04, 2020, 01:04:33 PM
A new challenge



You asked for it, and you will have it. This time around:

  • Includes signatures
  • Not an anyone-can-spend address

Check out 2MsucLKM489owxv6emXfCVRCZ3UFb7MnXCR (https://www.blockchain.com/btc-testnet/address/2MsucLKM489owxv6emXfCVRCZ3UFb7MnXCR)

It has been funded once with 0.1 tBTC, spent from once, and is funded again with 0.1 tBTC

ALL INFORMATION NEEDED TO BREAK IT IS IN THIS THREAD

I will prove it by writing out the solution here, if no one has swept it within a day or so. I someone sweeps it sooner (and doesn't write anything here), I will publish the solution asap.

Go!





Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BrewMaster on August 04, 2020, 02:03:11 PM
...
This isn't correct. I designed the locking script so it requires exactly two pushes of equal string length. An empty unlocking script will fail. Also, "lots of OP codes" will fail too.

it is not "string" length despite what the wiki says, it is byte length and what i meant was that you can change the 2 initial data that are being pushed to the stack to be literary anything. then you can also add some other garbage code there for example the second thing you posted can be modified to this that even has an OP_CHECKSIG inside and it still passes:
Code:
OP_5 0x03ffffff OP_CHECKSIG OP_NOT OP_1 OP_1 <redeem_script>
and it still has nothing to do with breaking the redeem script :P


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 04, 2020, 02:14:22 PM
...
This isn't correct. I designed the locking script so it requires exactly two pushes of equal string length. An empty unlocking script will fail. Also, "lots of OP codes" will fail too.

it is not "string" length despite what the wiki says, it is byte length and what i meant was that you can change the 2 initial data that are being pushed to the stack to be literary anything. then you can also add some other garbage code there for example the second thing you posted can be modified to this that even has an OP_CHECKSIG inside and it still passes:
Code:
OP_5 0x03ffffff OP_CHECKSIG OP_NOT OP_1 OP_1 <redeem_script>
and it still has nothing to do with breaking the redeem script :P

Hm, two questions:

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)

2) If you fiddle around with the locking script, its hash will change which will invalidate the transaction?



Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BrewMaster on August 04, 2020, 02:24:51 PM
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.


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 04, 2020, 02:32:29 PM
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 :) (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.


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BrewMaster on August 04, 2020, 03:02:58 PM
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 :) (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)


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 04, 2020, 07:05:06 PM
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 :) (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 (https://www.blockchain.com/btc-testnet/tx/94afbc5c2fdf74e6dd215e2f59b9006fac00baf585b0de897c16e5bd203e6886).

(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.)




Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 05, 2020, 01:40:20 AM
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 (https://www.blockchain.com/btc-testnet/tx/577df74f64cd59d264c6bbba133d935f846a84b6ede5d2e052f05d745919c2e5) 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 (https://github.com/matja/bitcoin-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?


Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: A-Bolt on August 05, 2020, 09:46:24 AM
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.



Title: Re: A breakable P2SH address - Bitcoin testnet inside
Post by: BTCW on August 06, 2020, 11:49:14 AM

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 (https://www.blockchain.com/btc-testnet/tx/94afbc5c2fdf74e6dd215e2f59b9006fac00baf585b0de897c16e5bd203e6886).

(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 (https://www.blockchain.com/btc-testnet/tx/42f6d6ba8317afcc7b6e54d6cc09839f7cc224ca9bf26c0c026432b1fa9c3f44)

Raw rx:
Code:
010000000186683e20bde5167c89deb085f5ba00ac6f00b9592f5e21dde674df2f5cbcaf94010000002d0442726577064d617374657220827c827708d7a41d9c57b451da7b7b877b757c75510899b51d4455b651db7587ffffffff01b08e98000000000017a914628cde58e1bcd42efb72b1821ec9fdf49e0f1d498700000000

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



Suggestions, anyone?