
Technische Analyse von CVE-2008-0166 in Bitcoin 2009-2012, Untersuchung von OpenSSL 0.9.8c PRNG-Schwachstellen, Windows-Entropieausfällen und Schlüsselraum-Rekonstruktion.
Autor: Analyse basierend auf bitcoin-code-r252 (0.1.5 / 0.2.0 / 0.3.24) und dem ursprünglichen make-OpenSSL-0-9-8c-vulnerable-again.diff (THC) Datum: 2026-09-10
Bitcoin 0.1.5 (Januar 2009) lief ausschließlich unter Windows und verwendete OpenSSL
0.9.8c für die EC-Schlüsselgenerierung (EC_KEY_generate_key). Im Jahr 2008
wurde CVE-2008-0166 im OpenSSL-Paket von Debian entdeckt, doch unter Windows
hatte das Problem eine andere Ursache — nicht ein fehlendes /dev/urandom, sondern
die Implementierung von RandAddSeed() im Bitcoin-Quellcode selbst.
In bitcoin-code-r252 (tags-0.1.5) lautet die RNG-Initialisierungssequenz
(util.cpp):
CInit::CInit() {
RAND_screen(); // (a) screen bitmap scrape
RandAddSeed(true); // (b) QPC + PerfMon
}
RandAddSeed (util.cpp:57-92):
QueryPerformanceCounter -> RAND_add(&PerformanceCount, 8, 1.5)RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", ..., buf=250000)
-> if ERROR_SUCCESS: SHA256(pdata) -> RAND_add(&hash, 32, entropy)Schlüsselgenerierung (key.h:75-78):
CKey::MakeNewKey() {
EC_KEY_generate_key(pkey); // internally: RAND_bytes(32)
}
Wichtig: Die Versionen 0.1.5 bis 0.3.24 hatten keinen Keypool. GetRand()
verwendet RAND_bytes(8) für andere Zwecke (Netzwerk-Nonces, IRC-Nicknames) und
stört dadurch den PRNG-Zustand zwischen aufeinanderfolgenden GenerateNewKey()-Aufrufen.
Version 0.4.0 (September 2011) führte TopUpKeyPool() mit einem Standard-
Pool von 100 Schlüsseln ein (GetArg("-keypool", 100)).
Die Gruppe THC (The Hackers Choice) entwickelte thc-btc-rng-bruteforce
unter Verwendung eines modifizierten OpenSSL 0.9.8c. Drei kritische Änderungen:
THC_hitme() (md_rand.c:133-180)THC_hitme(0): setzt state_num, state_index, entropy,
initialized, stirred_pool, md_count[0..1], md[], state[] auf null
— vollständiger PRNG-Reset.THC_hitme(pid): speichert pid in der statischen Variable thc_pid.ssleay_rand_add() — Pufferinhalt ignoriert (Zeile 344)- MD_Update(&m, buf, j);
+ //MD_Update(&m, buf, j); // commented out!
RAND_add erhöht weiterhin state_index um num und inkrementiert
md_count[1], aber der Pufferinhalt hat keine Auswirkung auf den PRNG-Zustand.
ssleay_rand_bytes() — PID-Substitution (Zeilen 550-561)getpid()-Aufruf entfernt.curr_pid = thc_pid — konstanter Wert aus THC_hitme.MD_Update(&m, &curr_pid, sizeof(curr_pid)) injiziert
PID als einzige externe variable Eingabe.Im gepatchten OpenSSL hängt der PRNG-Zustand ausschließlich ab von:
THC_hitme)RAND_add-Aufrufe (num-Parameter, nicht Pufferinhalt)RAND_bytes-Aufrufe vor der SchlüsselgenerierungIn OpenSSL 0.9.8c wird BN_ULONG durch opensslconf.h definiert:
#ifdef SIXTY_FOUR_BIT_LONG -> BN_ULONG = unsigned long (64-bit)
#ifdef THIRTY_TWO_BIT -> BN_ULONG = unsigned long (32-bit)
Unter 64-Bit-Linux verwendet OpenSSL standardmäßig SIXTY_FOUR_BIT_LONG, wodurch
sizeof(BN_ULONG) von 4 auf 8 Bytes geändert wird. Dies beeinflusst:
static long md_count[2] (8 vs. 16 Bytes)1FkLYqPpfKPAR6EZh2RC6sDwTUA6Axb1XQ1JbxBrkBiSwpJUJN2bXrYJc51pH5rjrzTDBitcoin 2009 lief auf Windows XP 32-Bit, daher erfordert die korrekte
Schlüsselrekonstruktion eine Kompilierung mit erzwungenem THIRTY_TWO_BIT (bearbeiten
Sie include/openssl/opensslconf.h vor dem Build).
In einem Beitrag vom 27. September 2012 (topic=113496) beschrieb Sergio Lerner:
(a) RandAddSeed() ruft QueryPerformanceCounter() auf — erfordert
QWORD-Ausrichtung seines Arguments. Der gcc-Compiler unter Windows konnte
die Stack-Variable möglicherweise nicht auf 8 Bytes ausrichten, was zu einem stillen Fehler führte.
(b) RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", ...) verwendet einen
festen Puffer von 250.000 Bytes. Unter Windows XP betrugen die Performance-Daten
~280 KB — die Funktion gab ERROR_MORE_DATA zurück und wurde nie erneut
mit einem größeren Puffer aufgerufen. debug.log enthielt keine Warnung.
Wenn beide Mechanismen fehlschlugen, war die einzige Entropiequelle RAND_screen()
(Screen-Bitmap). Im gepatchten OpenSSL ist sogar RAND_screen irrelevant,
da der Pufferinhalt ignoriert wird.
Lerner empfahl, diese Fehler in debug.log zu protokollieren — dieser Fix wurde
in spätere Bitcoin-Core-Versionen aufgenommen.
Verifiziert in bitcoin-code-r252 (Tags: 0.1.5, 0.2.0, 0.3.0) und dem bitcoin/bitcoin-Repository (Tags: 0.3.24, 0.4.0, 0.5.0, 0.6.0):
| Version | Datum | Init RNG (Windows) | Keypool |
|---|---|---|---|
| 0.1.5 | 2009-01 | RAND_screen + RandAddSeed(true) | none |
QPC->RAND_add(8) + perfmon->SHA256->RAND_add(32) | |||
| 0.2.0 | 2009-12 | RAND_screen (__WXMSW__ only) | none |
QPC->RAND_add(8), perfmon separate every 10 min | |||
| 0.3.0 | 2010 | same | none |
| 0.3.24 | 2011-07 | perfmon every 10 min, RegQueryValueExA | none |
| 0.4.0 | 2011-09 | same | TopUpKeyPool 100 |
| 0.5.0 | 2011-12 | same | 100 |
| 0.6.0 | 2012-03 | same | 100 |
RAND_screen() wurde auf allen Windows-Versionen bis 2012 verwendet.SHA256(pdata) -> RAND_add(32), spätere Versionen
übergaben rohe pdata an RAND_add (unterschiedliche num-Größe ist im
gepatchten OpenSSL relevant, da nur die Größe, nicht der Inhalt, den Zustand beeinflusst).Der Schlüsselraum für den Angriff (im gepatchten OpenSSL):
PID (1..32767)
x poll (count of RAND_add calls in init, modeling Toolhelp32 on WinXP)
x keypool position (1 for pre-0.4.0, 100 for 0.4.0+)
x profile (RAND call sequence for each Bitcoin version)
x architecture (le32 / le64)
Die Parameter tick, screen, cursor, hwnd, queue sind
in diesem Modell irrelevant, da der RAND_add-Pufferinhalt ignoriert wird.
Die ursprünglichen THC-Autoren schrieben: „We did not find any." — sie fanden keine Schlüssel auf der Blockchain. Die Analyse bestätigt ihre Feststellung: Die Wahrscheinlichkeit, dass ein anfälliger Schlüssel on-chain existiert, hängt vollständig davon ab, ob tatsächlich eine Bitcoin-Wallet auf einem Windows-XP-System mit dem defekten OpenSSL und still fehlschlagendem perfmon/QPC generiert wurde.
[1] Sergio Lerner, „Possible new vulnerability: poor entropy in Windows generated keypairs", Bitcointalk 2012-09-27: link
[2] Bitcoin StackExchange — „Was Satoshi using Windows or Linux?": link
[3] THC, thc-btc-rng-bruteforce: link
[4] Bitcoin Core Tags (0.1.5, 0.2.0, 0.3.0, 0.3.24, 0.4.0, 0.5.0, 0.6.0): link
[5] OpenSSL 0.9.8c + Patch make-OpenSSL-0-9-8c-vulnerable-again.diff
[6] Analiza_entropy_win.txt — Technischer Bericht, 2026-09-10