Creed
Creed
I was worried if I
posted this somewhere it would mostly go unnoticed. Also, I'm trying to stay
anonymous because I don't want to be accused of being the person who came up with
this exploit or be blamed by any company for any damages. It's an interesting
technical story so I thought I would share it.
I returned 9 BTC to reddit user fitwear who recently claimed were stolen from their
blockchain.info wallet.
I have evidence that some bitcoin address generation code in the wild is using
private keys that can easily be discovered on a regular basis. This is either
intentional or by mistake. Some wallets have been compromised by what is probably
an innocent looking piece of code. Furthermore, someone has been siphoning bitcoin
on a regular basis since 2014 from them. Whether they discovered this by accident
(like I did) or are the ones who installed the code themselves, I don't know. It
looks like either a clever exploit or a coding error. It could also be yet another
piece of malware, however as I explain below, I feel this is less likely the case.
In order to fully understand how this works and how I discovered it, please read
on.
Some Background
---------------
I've been following bitcoin since I first heard of it in 2011. One of the things
that fascinated me was the ability for someone to create private keys from just
about anything using Sha256 (i.e. Sha256(password/phrase)). This, of course, is
NOT a recommended way of obtaining a private key since if YOU can think of the
word/phrase, someone else can too and the likelihood of your bitcoins being stolen
is quite high. The most secure private keys are generated randomly. The probability
of someone else being able to generate the same sequence of 32 random bytes is so
close to 0, it is highly improbable anyone ever will (given the expected lifespan
of the universe).
If you peer into the blockchain, you will find that people have 'played' with the
chain by sending small amounts of bitcoins to addresses corresponding to private
keys generated using Sha256. For example, Sha256 of each word in the entire
/usr/dict/words file found on most UNIX systems has had a small amount sent to it.
There was a site called brainwallet.org that made it easy for you to convert a
phrase into a private key + public address. (The code is still available on GitHub
but has since been removed from the Internet). Try using phrases like "i find your
lack of faith disturbing", "these aren't the droids you're looking for" or "satoshi
nakamoto" as inputs to Sha256. You'll find the addresses corresponding to those
private keys have had small amounts sent to them (and transferred out). It's quite
obvious these were _meant_ to be found. It turns out there are a lot of these
addresses. (Keep looking and you will easily find some.) This is nothing new and
has been known to the bitcoin community for a while.
I always had the idea in the back of my mind to try and find other non-trivial
examples of 'discoverable' private keys. That is, something beyond
Sha256(word/phrase). So I decided to try and hunt for buried bitcoin treasure.
Perhaps I could find some bitcoin intentionally hidden by someone that hadn't yet
been discovered? In the first couple weeks of June 2017, I finally devoted some
time to the task. I honestly didn't expect to find much but I was amazed at what I
ended up discovering. I began by writing a program to scan every block in the
blockchain and record every public address that had ever been used. (Note: I
didn't only store addresses for which the balance was greather than zero, I stored
ALL of them which is why I believe I ended up accidentally discovering what I did.)
There were only about 290 million at the time so this wasn't a big deal.
The Experiments
---------------
Experiment 1
------------
My first experiment was to see if anyone used a block hash as a private key. That
would actually be a nifty way to 'compress' 32 bytes in your head. You would only
have to remember the block height (which is only maybe 6 digits) and the
corresponding larger 32 byte number would be saved for all time in the chain
itself!
Results: Success! I found 46 addresses that had some amount of bitcoin sent to them
between 2009 and 2016. As expected, these all had 0 balances either because the
owner had taken them back or they were discovered by someone else.
Here are two examples. You can use blockchain.info to see these hex values are
actually block hashes from early in the chain. This happened on/off up until mid-
2016.
1Buc1aRXCqdh6r7PRYWPAy3EtVFw5Ue5dk
000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd
1KLZnkqU94ZKpgtcWCRs1mhqtF23jTLMgr
000000004ebadb55ee9096c9a2f8880e09da59c0d68b1c228da88e48844a1485
Experiment 2
------------
Similar to my first experiment, I then searched for addresses that were generated
from the merkle root used as a private key. (BTW, I searched for both
compressed/uncompressed keys, so each 32 bytes resulted in two address look-ups
from my database).
Results: Yes! I found 6 addresses again up until mid-2016. Even though every
address I found had a 0 balance (again expected), I was having fun with my success!
Example:
13bkBdHRovsBkjM4BUsbcDNr9DCTDcpy9W
6c951c460a4cfe5483863adacafad59e5de7e55876a21857733ca94049d7d10c
Similar to merkle root and block hashes, transaction ids (hashes) also seem to have
been used as private keys. Still nothing alarming to me thus far.
Experiment 3
------------
I wondered at this point if anyone might have used repeated Sha256 on words. Why
stop at just one iteration when you can easily do one million? Also, it becomes
less likely to be discovered the more iterations you do. I found a bunch. Here
are a few:
Sha256('sender') x 2
18aMGf2AxQ3YXyNv9sKxiHYCXcBJeJv9d1
098f6d68ce86adb2d8ba672a06227f7d177baca3568092e4cda159acca5eb0c7
Sha256('receiver') x 2
1C3m5mFx6SjBCpw6qLqzM8izZArVYQ9B5u
6681b4b6aa44318e55a724d7135ff23d76eb75847802cd7d220ecaa8427b91d4
Sha256('hello') x 4
17UZ4iVkmNvKF9K2GWrGyMykX2iuAYbe1X
28b47e9b141279ea00333890e3e3f20652bbd7abc2b66c62c5824d4d6fe50ac9
Sha256('hello') x 65536
1Mi5mVANRNAetbJ21u2hzs28qCJC19VcXY
52fa8b1d9fbb264d53e966809ce550c3ab033248498da5ac0c5ab314ab45198e
13mcYPDDktHdjdq9LwchhU5AqkRB1FD6JE
6e8cdae20bef63d33cb6d5f1c6c9c954f3148bfc88ef0aa1b51fd8b12fa9b41c
People were obviously burying bitcoin in the chain. Whether they expected the coins
to be taken or not, we'll never know. But these methods were still highly
'discoverable' in my opinion.
Experiment 4
------------
My last experiment is the one that led me to believe someone was siphoning bitcoin
from some service on a regular basis and has been since 2014.
KyTxSACvHPPDWnuE9cVi86kDgs59UFyVwx2Y3LPpAs88TqEdCKvb
13JNB8GtymAPaqAoxRZrN2EgmzZLCkbPsh
The raw bytes for the private key look like this:
4300d94bef2ee84bd9d0781398fd96daf98e419e403adc41957fb679dfa1facd
Looks random enough. However, these bytes are actually sha256 of this public
address!
1LGUyTbp7nbqp8NQy2tkc3QEjy7CWwdAJj
I discovered this by performing Sha256 on all the public addresses I had collected
from the setup of my experiments and then seeing if those addresses (from the
generated private keys) were ever used. Bingo! Lots were coming up. I searched a
fraction of the chain and found dozens. I also found these addresses had bitcoin
sent to them very recently (within weeks/days of when I discovered them.)
In every case I looked at, the coins were moved away within minutes or seconds.
It was much more likely that a bot was waiting for those coins to show up. Also,
transactions are STILL happening to this day on those addresses! But how can that
bot know in advance that address was about to receive bitcoins?
A Scam or a mistake?
--------------------
It's actually quite clever. No one can know the destination address in advance.
You would have to keep performing Sha256 on all public addresses ever used to catch
that one in a million transaction. Someone would be able to capture those coins by
simply watching for a transaction into an address that corresponds to a private key
generated from Sha256 of one of the existing public addresses. Keeping such a
database is trivial and lookups are quick.
Transactions were STILL happening right up until a couple weeks before I made this
discovery! So I wrote a bot to try and 'catch' a transaction.
Mind Blown
----------
Within the FIRST 48 HOURS of my bot going live, on Jun 19, a whopping 9.5 BTC was
transferred into an address for which I had the private key. This was
approximately worth $23,000 USD at the time. I was shocked.
BUT... I had failed to test my program sufficiently and it failed to submit the
transaction! The 9.5 BTC was sitting there for almost 15 minutes before being
swept away by someone else. I honestly didn't think the first amount to cross my
radar would be so high. The other samples I found from past transactions were for
tiny amounts. It is quite possible that whoever moved them later out of the
poisoned address actually owned them. Maybe someone else's sweeper bot only takes
small amounts most of the time to avoid attention?
At this point, I was pretty confident I was on to something not yet discovered by
anyone else. I _could_ have taken those 9.5 BTC and if this was known to others.
Also, if you look into the history of that account, 12 BTC was transferred into it
(and out right away) only one month earlier. No one has claimed any theft (to my
knowledge) involving that address.
I fixed my program (actually tested it properly this time) and let it run again.
My program detected more transactions (2 within the next 48 hours). I coded my bot
to ignore anything less than .1 BTC so I didn't move them. I didn't want to tip
off the anyone that I knew what they were doing (if that was indeed the case).
Another 3-4 days passed and the next hit my bot detected was for roughly .03 BTC
(~$95USD). For some reason, this was not transferred out immediately like the
rest. By this time it was July 4th weekend. I let this one sit too and it took a
full 7 days before it was moved (not by me). It may have been the legitimate owner
or a bot. We'll never know.
I didn't realize it at the time but that last transfer was into an address for a
private key not generated from another public address like the first one. Instead,
this address was generated from a transaction id! I had forgotten that I seeded my
database with private keys generated with transaction ids as part of one of my
earlier experiments. I didn't label them so I didn't know which were from
Sha256(pub address) and which were from transaction ids. I found some hits at the
time but when I checked the balances for those accounts, they were all zero and I
didn't think anything of it. But now my database was detecting ongoing transfers
into THOSE addresses (transacton id based) too!
Okay, someone was possibly using information from the blockchain itself to ensure
private keys were discoverable for the addresses they were funelling bitcoin into.
The interesting thing is I found a link between the
12fcWddtXyxrnxUn6UdmqCbSaVsaYKvHQp address (via sha of a public address) AND the
1LUqqMzaigWJTzaP79oxsD6zKGifokrh7p transfer (via the tx id as a key). In the
history of both of these addresses, you can see the BTC eventually ended up into
this address: 1JCuJXsP6PaVrGBk3uv7DecRC27GGkwFwE
Also, the transaction id was for the previous transaction to the one that put the
BTC in the toxic (discoverable) address in the first place. Now it became even
more clear. The malicious code sometimes used a recent transaction id as the
private key for the doomed destination address. Follow the .03 BTC back and you
will see what I mean, you eventually get to the txid = private key for that
discoverable address.
I let my bot run longer. The next hit I got was for block hashes that were used as
private keys (see Experiment #1). Sure enough, this address also had links to the
1JCuJXsP6PaVrGBk3uv7DecRC27GGkwFwE collection address!
And remember my merkle root experiment? I believe those were also part of this.
However, I have not linked those to this one particular collection address yet. In
the end, I found a total of four different 'discoverable' private key methods being
used.
I made sure my database was filled with every block hash, merkle root, transaction
id and Sha256(public address) for private keys and let my bot run. Transactions
for all four types were showing up, again for tiny amounts which I ignored. By this
time, I was watching BTC getting taken in small amounts regularly. Sometimes, I saw
as many as 6 transactions fly by in one day.
On Nov 12, my program saw 9 BTC transferred into an address that my database had
the private key for. I had searched for that address too to see if anyone was
claiming ownership but I didn't see anything. I decided to send a small amount to
a well known puzzle address to give the transaction some public scrutiny in an
anonymous way (1FLAMEN6, I'm still trying to solve this BTW). Shortly after, I
became aware of fitwear's reddit post claiming theft after someone noticed the
prize amount had been topped off and linked the two events together.
I contacted fitwear privately and returned their coins minus the small amount I
sent to the puzzle address. Blockchain.info's original response to his support
ticket, was that his system must have been compromised. However, if you read his
post, he took every precaution including typing in the key for his paper wallet
instead of copy/paste and using 2FA.
In his case, in Aug 2017, he imported the private key for his
1Ca15MELG5DzYpUgeXkkJ2Lt7iMa17SwAo paper wallet address into blockchain.info and
submitted a test transaction. At some point between then and Nov 12, the
compromised 15ZwrzrRj9x4XpnocEGbLuPakzsY2S4Mit got into his online wallet as an
'imported' address.
Together, we contacted blockchain.info and I relayed the information I just
outlined above to them. Their security team investigated but found no evidence it
was their system that was at fault. I suppose it's possible his system was somehow
compromised back in August and managed to import a key into blockchain.info without
him knowing it. Or someone else logged into his account, imported the key, then
waited. I feel the malware/login explanations are much less likely because it
looks like code attempting to 'hide in plain sight' to me. You wouldn't need to
use Sha256(address) or block hash or txid or merkleroot if you were malware or an
unauthorized login. You would at least salt or obscure the key with some bit of
knowledge only you know so that only you could derive the private key (as mentioned
earlier). The fact that information from the blockchain itself is being used
indicates it may be some transaction processing logic. Also, fitwear took extreme
precautions (you can read his reddit post for details). The origin of these poison
destination addresses remains a mystery.
If it's the case that some wallet generation code is doing this, then it may be the
case that we're seeing 'change' transactions. When you create a wallet, there
maybe 20 addresses generated. They are all supposed to be random keys. If this
rogue code creates one of them in this manner (based on the public address string
of an earlier one), then at some point, your 'change' will get put back into it as
the wallet 'round-robins' through the list.
fitwear's 15Z address sat unused until Nov 12 when fitwear transferred his 9 BTC
into it using blockchain.info.
fitwear insists he did not import the key for that address. Did Blockchain.info
generate it or was it added by mallicious browser code? We may never know.
See below for the complete list of other Sha256 based addresses that suffer from
the same issue. I believe this is happening for others. It's likely, that the
small amounts usually taken are going unnoticed by the owners.
What does this mean for bitcoin? Nothing probably. I believe the bitcoin network
itself to be secure. However, as long as humans are involved in the services that
surround it (mining pools, exchanges, online/mobile wallets) there is always a
chance for fraud or error. The bitcoin network itself may be 'trustless', but
anything humans touch around its peripheries is certainly not. And you need to use
those services to get in/out of the network. So even with bitcoin, it still boils
down to trust.
Here are 100+ addresses that received bitcoins whose private keys are the bytes
resulting from Sha256 of another public address. Most of these came from a scan I
did of old transactions, not while my bot was running. Blockchain.info told me
they do not appear to have been generated by their system.
Also, the list of addresses I"m providing are only the subset that have already had
some BTC transacted through them. There are likely hundreds more lying dormant
inside people's wallets that have not been used yet.