The transactions that we broadcasted to the Bitcoin network while testing the Copay bug, made our wallet bitcoins spendable by anyone even after installing the patched version of Copay. We found this to be a very interesting Bitcoin security issue, and wanted to share it with the community in the form of a puzzle to be solved.
We believe that one way to keep Bitcoin security evolving is to motivate more information security researchers to look at it, learn its inner workings, find holes, and publish the results.
To make this Bitcoin puzzle more attractive to security researchers we contacted the organizers of the Ekoparty conference. Ekoparty is the biggest information security conference in Latin America, where Sergio Lerner presented about Bitcoin multiple times.
After talking with the Ekoparty organizers, we announced a challenge inviting players to take all the bitcoins from our wallet in order to win a VIP ticket to Ekoparty (and the bitcoins).
Three hackers solved the challenge, in chronological order: Jon Cave, Sebastián Fernandez and Lucas Lavarello. This challenge was the first contact for the three of them with the inner workings of a Bitcoin transaction. They learned very quickly and shared their experience in very good write-ups published in their blogs.
They transferred bitcoins from our multi-signature wallet to their own addresses without ever posessing any of our private keys, using only information publicly available in the blockchain. How was this possible?
You can read the solutions written by the winners: Jon, Sebastián and Lucas. In the initial announcement we said that the VIP ticket was for the best write-up. Lucas worked harder and wrote in English and Spanish but Ekoparty has tickets for the three. Congratulations!
The SIGHASH_SINGLE Bug
A design weakness in a multi-signature wallet is a good example of a case where an adversary can choose the hash type to be used by a victim to sign a Bitcoin transaction. The Copay vulnerability described in our previous article is a real life example of this possibility, please leave a comment if you imagine any other possible case.
The SIGHASH_NONE hash type can be used to force the signer to involuntarily produce what is analogous to a blank check, but the SIGHASH_SINGLE type can be used to make the victim produce something analogous to a rubber stamp. This 'rubber stamp' signature can be used to validate any transaction from the victim's address without knowing the private key. Producing this reusable signature is equivalent to leaking the private key. This isn't a feature designed by Satoshi Nakamoto, it is a consequence of a bug in his code.
We knew about this bug and wanted to use it in the demonstration of the Copay vulnerability but later we decided to use SIGHASH_NONE because it was easier to implement and explain. However our first testing transactions, in the Bitcoin live network, used SIGHASH_SINGLE; this is the reason why reusable signatures for each key of our multi-signature wallet were exposed in the blockchain.
The SignatureHash function of the script.cpp file is where the bug is located.
This function is critical to Bitcoin security, it is used to calculate the hash of the transaction data to be signed.
SignatureHash return value type is uint256. The function is expected to return a 256 bit hash, but for two erroneous input cases, the function returns the number 1.
This number one expanded to a 256 bit number is what is signed in these particular cases, making the signature valid but independent of the transaction data.
This fixed hash value is returned when the function is parsing a transaction input, which uses a SIGHASH_SINGLE signature, and the given input's index is greater or equal to the total number of outputs in the current transaction. For example, if a transaction with two inputs and only one ouput is signed using the hash type SIGHASH_SINGLE, the signature for the second input will be reusable.
The first report of this bug we can find is a mail from Matt Corallo to the Bitcoin Development mailing list two years ago.