[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Full-disclosure] Fun with Bitcoin, or how an exploit can hide in plain sight



So most people on here have probably heard of Bitcoin from somewhere,
and most of you have probably got tired of it - but bear with me
because this is kind of entertaining. For those of you that have been
stuck in a darkened room with a disassembler and no internet access
for the past few months, Bitcoin's a clever digital currency that
manages to solve the problem of someone spending the same money twice
without needing any kind of central trusted authority. It does this by
using a variant of hash-cash to make rewriting the history of past
transactions expensive.

Now this means that someone with more than half the total compute
power can launch certain attacks - they're listed on the Bitcoin wiki
at https://en.bitcoin.it/wiki/Weaknesses#Attacker_has_a_lot_of_computing_power
- but even they aren't meant to have total control. In particular,
they're not meant to be able to spend other people's money because
doing so requires a signature from their private key:

"The attacker can't: Send coins that never belonged to him"

For several months that claim has been *false* as a result of this
commit by the lead Bitcoin developer:
https://github.com/bitcoin/bitcoin/commit/b14bd4df58171454c2aa580ffad94982943483f5

Now, while obviously that commit is doing something slightly risky,
there's a nice reassuring comment from him in the code explaining
exactly why it's not actually a security risk:

// Skip ECDSA signature verification when connecting blocks
(fBlock=true) during initial download
// (before the last blockchain checkpoint). This is safe because block
merkle hashes are
// still computed and checked, and any change will be caught at the
next checkpoint.

It's a very convincing explanation to anyone that understands Bitcoin.
You can only really add a blockchain checkpoint if all the nodes agree
that the chain up to that point is valid - otherwise things will break
in a fairly spectacular and obvious way - so a whole bunch of other
Bitcoin nodes run by many independent people will already have
verified the ECDSA signatures. There's even a good justification for
making the change. Initial blockchain downloads are far too slow which
discourages new users, and ECDSA signature verification is one of the
slowest parts.

Unfortunately the comment is fatally wrong. Even more scarily, there's
no reason at all to suspect this from the commit diff, which is
probably why no-one noticed anything was amiss when it was committed.
If you take a look at the actual definition of IsInitialBlockDownload
there's actually *two* situations which it considers part of the
initial download. One of them is indeed being before the last
blockchain checkpoint:

if (pindexBest == NULL || nBestHeight <
Checkpoints::GetTotalBlocksEstimate()) return true;

The other involves the timestamp included within the last block and
how recently it was received:

return (GetTime() - nLastUpdate < 10 && pindexBest->GetBlockTime() <
GetTime() - 24 * 60 * 60);

So, if we receive a block less than 10 seconds after the previous one
and the previous block had a timestamp more than 24 hours in the past,
we don't bother to verify any of the ECDSA signatures in it and will
allow it to include transactions that spend random people's Bitcoins!

A powerful attacker could definitely exploit this; timestamps in the
future are rejected and Bitcoin won't generally accept a version of
history in which time goes backwards, but otherwise a 51% attacker can
choose whatever timestamps they like and can delay releasing their
version of the chain to meet the "less than 10 seconds" requirement.
It's a very expensive attack but far from impossible.

By full-disclosure standards this is actually old news; I disclosed it
semi-publicly to the Bitcoin developers about a month ago and they
committed a fix back then, and there's even been a Bitcoin release
0.5.2 since then which includes the fix (though only because one of
the other developers stubbornly insisted on creating a bugfix release
for other reasons - the head developer was strongly against it). All
previous 0.5.x releases were vulnerable and 0.6 hasn't been released
yet. I only just got around to looking into how the vulnerability got
in originally though and it doesn't appear anyone's really talked
about it.

This isn't a formal advisory either, more an example of how a
vulnerability can easily be introduced by a seemingly innocuous commit
and why the Bitcoin code needs more scrutiny.

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/