Kerugian melebihi US$88 juta: Analisis lubang keamanan pada dompet keras Coldcard dan pelacakan dana yang dicuri Pada 31 Julai, sebanyak 500 dompet keras Coldcard telah dicuri, dengan jumlah 594 bitcoin bernilai kira-kira US$38 juta. Selepas itu, Coinkite, syarikat yang bertanggungjawab atas penghasilan dompet Coldcard, mengesahkan bahawa terdapat lubang keamanan dalam proses penghasilan kunci pada produk tersebut, yang mempengaruhi pelbagai generasi Coldcard seperti Mk2, Mk3, Mk4, Q, dan Mk5.
Sekarang, jumlah kerugian akibat serangan terhadap lubang keamanan ini telah melebihi US$88 juta, dan serangan masih berterusan. Pengguna dompet Coldcard seharusnya segera memindahkan dana mereka ke alamat lain. Analisis Beosin terhadap lubang keamanan ini dan pengesanan dana yang dicuri adalah seperti berikut.
Satu, analisis lubang keamanan
Menganalisis rekod penghantaran kod firmware Coldcard, dapat ditemui bahawa dalam Commit sebelumnya 37e4af5451c260c1e7d429fe8972c4cb5e68ee59, pasukan pembangun telah mengemas kini beberapa kod berkaitan konfigurasi MK4, termasuk dalam mpconfigboard.h:
// Kami mempunyai versi kami sendiri untuk kod ini.#define MICROPY_HW_ENABLE_RNG (0)
Pada sisi MicroPython STM32, makro ini mengawal laluan kompilasi untuk pengikatan penghasil nombor rawak peranti (RNG) lalai dan pelaksanaan rawak am. Menetapkannya kepada 0 menyebabkan laluan RNG peranti lalai tidak digunakan sebagai backend untuk rng_get() am.
Catatannya menyatakan bahawa pembangun akan melaksanakan RNG sendiri; semak rng.h yang disesuaikan dan mendapati hanya menyatakan dua objek MicroPython:
MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj); MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);
Implementasi yang sepadan ialah:
/// \function pyb_rng_get()///// Kembalikan nombor rawak yang dihasilkan peranti 30-bit: atau gagal!//STATIC mp_obj_t pyb_rng_get(void){ // Dapatkan dan kembalikan nombor rawak baru return mp_obj_new_int(rng_get_or_fault() >> 2);}
/// \function rng_get_bytes()/// Isi buffer dengan bit rawak; pemanggil harus menyediakan buffer bersaiz.STATIC mp_obj_t pyb_rng_get_bytes(mp_obj_t buffer_io) {
mp_buffer_info_t bufinfo; mp_get_buffer_raise(buffer_io, &bufinfo, MP_BUFFER_WRITE);
mp_uint_t count = bufinfo.len; if(count < 1) { mp_raise_ValueError(NULL); }
// Baca perkataan 32-bit dan bongkar ke dalam buffer yang disediakan random_buffer(bufinfo.buf, count);
return mp_const_none;}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);MP_DEFINE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj, pyb_rng_get_bytes);
rng_get_or_fault() membaca peranti RNG STM32:
static uint32_t rng_get_or_fault(void){ // Aktifkan periferal RNG jika belum diaktifkan rng_init();
// Tunggu sehingga nombor rawak baru sedia, mengambil masa kira-kira 10us uint32_t start = HAL_GetTick();
while (!(RNG->SR & RNG_SR_DRDY)) { if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) { // kegagalan peranti keras... jangan kembalikan apa-apa! mp_raise_OSError(MP_EFAULT); } }
// Dapatkan dan kembalikan nombor rawak baru last_value = RNG->DR;
return last_value;}
Ini menunjukkan bahawa kod tersuai Coldcard memang ingin menggunakan RNG peranti keras, tetapi ia hanya menjamin penggunaan fungsi peranti keras tersebut apabila memanggil pyb_rng_get* atau random_buffer() dalaman.
Sementara itu, semasa penciptaan dompet, kod berikut sebenarnya dipanggil, di mana fungsi penciptaan dompet di shared/seed.py ialah:
async def make_new_wallet(nwords): # Pilih benih rawak baru. await ux_dramatic_pause('Menghasilkan...', 3) seed = generate_seed() words = await approve_word_list(seed, nwords) if words: await commit_new_words(words)
Panggilan ini masuk terlebih dahulu ke modul shared/random.py Coldcard. Dalam versi sebelumnya, random.py secara eksplisit bergantung pada ngu.random, dan menyimpan:
# random.py - subset modul random, tanpa kompatibilitas, dan menggunakan rng berkualiti kriptografi
# untuk bytes, gunakan ngu.random.byte(len)
# bytes = ngu.random.bytes
Iaitu, yang digunakan untuk inisialisasi dompet ialah random.bytes, bukan pyb.rng(), dan pyb_rng_get_obj yang disesuaikan tidak menimpa random.bytes secara automatik.
Kerana MICROPY_HW_ENABLE_RNG ditetapkan sebagai 0, RNG peranti keras tidak digunakan semasa penghasilan dompet, tetapi pyb_rng_yasmarang dari micropython/ports/stm32/rng.c dipanggil:
#if MICROPY_HW_ENABLE_RNG
uint32_t rng_get(void) { // gunakan RNG peranti keras STM32 ...}
#else
// Untuk MCU yang tidak mempunyai RNG, kami masih perlu menyediakan fungsi rng_get()// Pseudo-RNG bukanlah pilihan ideal, tetapi kami menggunakannya sementara ini.
// Penghasil nombor rawak Yasmarangstatic uint32_t pyb_rng_yasmarang(void) { static bool seeded = false; static uint32_t pad = 0, n = 0; ...}
uint32_t rng_get(void) { return pyb_rng_yasmarang();}
#endif
Sementara itu, pyb_rng_yasmarang adalah pseudorandom number generator yang sangat tidak selamat digunakan untuk penghasilan benih dompet keras, kerana penyerang boleh mendapatkan kunci melalui serangan brute force. Semasa ini, Coinkite telah secara jelas mengecualikan stm32/rng.c dalam fail makefile:
# Jangan kompilasi PRNG fallback MicroPython. Fail rng.c yang spesifik papan
# menyediakan rng_get(), dan objek kosong ini memenuhi senarai objek hulu.
$(BUILD)/rng.o: CFLAGS += -Dpyb_rng_yasmarang=error-do-not-want-this
$(BUILD)/rng.o:
$(ECHO) "SKIP stm32/rng.c"
$(Q)$(CC) $(CFLAGS) -x c -c /dev/null -o $@
Dua: Penjejakan dana yang dicuri
Sekarang, dana dari beberapa dompet mangsa telah dipindahkan dan dikumpulkan ke dalam beberapa alamat, tetapi belum dilakukan pembersihan lanjutan. Beosin Trace melalui intelijen ancaman dan analisis perilaku di rantai, memantau alamat pengumpulan berikut:
bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r (562 BTC)
bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3 (398.47 BTC)
Selain itu, terdapat alamat pengumpulan berikut yang pola aliran dananya serupa dengan gambar di atas, dan saat ini tidak ada pemindahan lanjutan:
- bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q (89.62 BTC)
- bc1q0rvn88w08j75k4h48lf9fvhan7unjp7vjf5q6m (64.9 BTC)
- bc1qtfrwa4j6rmj9rsgspv6a0yjumkg39js2numu75 (45.9 BTC)
- bc1qmd5m5ktv7m5ffujxv4248fxv36myvdx79n8jp6 (30.18 BTC)
Serangan terhadap dompet Coldcard masih berterusan, pasukan Beosin terus memantau lebih banyak alamat pengumpulan dan menganalisis aliran dana yang berkaitan.
Tiga, Penutup
Keselamatan besar dalam dompet keras Coldcard ini berpunca daripada kesilapan pelaksanaan pasukan pembangun dalam penghasilan nombor rawak, di mana nombor rawak palsu digunakan dalam proses penghasilan benih dompet yang kritikal. Pasukan pembangun perlu melakukan ujian dan audit yang berterusan dan menyeluruh terhadap kod, manakala pengguna Coldcard wallet perlu segera memindahkan aset mereka dan memantau pengumuman keselamatan seterusnya daripada Coinkite.
Beosin ialah syarikat teknologi keselamatan blockchain dan kepatuhan regulasi terkemuka, yang berfokus pada audit keselamatan kontrak pintar sebelum pelancaran projek, pemantauan dan penghalangan risiko keselamatan semasa operasi projek, pemulihan aset yang dicuri, anti pencucian wang (AML) aset maya, serta penyiasatan dan pelacakan. Beosin telah menyediakan produk kepatuhan blockchain "sekali jalan" dan perkhidmatan keselamatan kepada 200 lebih penyedia aset maya, serta 4,500 lebih projek Web3 di lebih 20 negara dan wilayah di seluruh dunia.

