Kerugian melebihi $88 juta: Analisis kerentanan Coldcard hardware wallet dan pelacakan dana yang dicuri Pada 31 Juli, sekitar 500 unit hardware wallet Coldcard kehilangan total 594 bitcoin, senilai sekitar $38 juta. Selanjutnya, perusahaan yang bertanggung jawab memproduksi wallet Coldcard, Coinkite, mengonfirmasi adanya kerentanan keamanan pada proses generasi kunci, yang memengaruhi berbagai generasi produk Coldcard seperti Mk2, Mk3, Mk4, Q, dan Mk5.
Saat ini, kerugian akibat serangan terhadap kerentanan ini telah melebihi $88 juta, dan serangan masih berlangsung. Pengguna Coldcard wallet sebaiknya segera memindahkan dana mereka ke alamat lain. Berikut adalah analisis Beosin terhadap kerentanan ini dan pelacakan dana yang dicuri.
Satu, analisis kerentanan
Menganalisis riwayat commit kode firmware Coldcard, dapat ditemukan bahwa pada commit sebelumnya 37e4af5451c260c1e7d429fe8972c4cb5e68ee59, tim pengembang memperbarui beberapa kode terkait konfigurasi MK4, termasuk di mpconfigboard.h:
// Kami memiliki versi kami sendiri dari kode ini.#define MICROPY_HW_ENABLE_RNG (0)
Di sisi MicroPython STM32, makro ini mengontrol jalur kompilasi untuk binding generator angka acak perangkat keras default (RNG) dan implementasi angka acak umum. Menetapkannya ke 0 menyebabkan jalur RNG perangkat keras default tidak digunakan sebagai backend untuk rng_get() umum.
Catatannya menyatakan bahwa pengembang akan mengimplementasikan RNG sendiri; setelah memeriksa rng.h khusus, ditemukan hanya mendeklarasikan 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 sesuai adalah:
/// \function pyb_rng_get()///// Kembalikan angka acak yang dihasilkan perangkat keras 30-bit: atau gagal!//STATIC mp_obj_t pyb_rng_get(void){ // Dapatkan dan kembalikan angka acak baru return mp_obj_new_int(rng_get_or_fault() >> 2);}
/// \function rng_get_bytes()/// Isi buffer dengan bit acak; pemanggil harus menyediakan buffer berukuran tertentu.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 kata 32-bit dan uraikan 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() secara langsung membaca perangkat STM32 RNG:
static uint32_t rng_get_or_fault(void){ // Aktifkan perangkat RNG jika belum diaktifkan rng_init();
// Tunggu hingga angka acak baru siap, memakan waktu sekitar 10us uint32_t start = HAL_GetTick();
while (!(RNG->SR & RNG_SR_DRDY)) { if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) { // kegagalan perangkat keras... jangan kembalikan apa pun! mp_raise_OSError(MP_EFAULT); } }
// Dapatkan dan kembalikan angka acak baru last_value = RNG->DR;
return last_value;}
Ini menunjukkan bahwa kode khusus Coldcard memang ingin menggunakan hardware RNG, tetapi hanya menjamin penggunaan fungsi hardware tersebut saat memanggil pyb_rng_get* atau random_buffer() internalnya.
Sedangkan saat pembuatan dompet, kode berikut yang sebenarnya dipanggil, di mana fungsi pembuatan dompet di shared/seed.py adalah:
async def make_new_wallet(nwords): # Pilih seed acak 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 pertama-tama masuk ke modul shared/random.py Coldcard. Dalam versi sebelumnya, random.py secara eksplisit bergantung pada ngu.random, dan mempertahankan:
# random.py - subset dari modul random, tanpa kompatibilitas, dan menggunakan rng berkualitas kriptografi
# untuk bytes, gunakan ngu.random.byte(len)
# bytes = ngu.random.bytes
Artinya, wallet initialization menggunakan random.bytes, bukan pyb.rng(), dan pyb_rng_get_obj yang disesuaikan tidak secara otomatis menimpa random.bytes.
Karena MICROPY_HW_ENABLE_RNG diatur ke 0, RNG perangkat keras tidak digunakan saat pembuatan dompet, melainkan memanggil pyb_rng_yasmarang dari micropython/ports/stm32/rng.c:
#if MICROPY_HW_ENABLE_RNG
uint32_t rng_get(void) { // gunakan RNG perangkat keras STM32 ...}
#else
// Untuk MCU yang tidak memiliki RNG, kami tetap perlu menyediakan fungsi rng_get()// Pseudo-RNG tidak benar-benar ideal, tetapi kami menggunakannya sementara ini.
// Generator angka acak 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
Sedangkan pyb_rng_yasmarang adalah pseudorandom number generator yang sangat tidak aman untuk digunakan dalam pembuatan seed dompet perangkat keras, karena penyerang dapat memperoleh kunci melalui serangan brute force. Saat ini, Coinkite telah secara eksplisit mengecualikan stm32/rng.c dalam file makefile:
# Jangan mengompilasi PRNG cadangan MicroPython. File rng.c spesifik papan
# menyediakan rng_get(), dan objek kosong ini memenuhi daftar objek upstream.
$(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 $@
II. Pelacakan Dana yang Dicuri
Saat ini, dana dari beberapa dompet korban telah dipindahkan dan dikumpulkan ke dalam beberapa alamat, belum dilakukan pencucian lebih lanjut. Beosin Trace melalui intelijen ancaman dan analisis perilaku di blockchain, memantau alamat pengumpulan berikut:
bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r (562 BTC)
bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3 (398,47 BTC)
Selain itu, ada alamat pengumpulan berikut yang pola aliran dananya serupa dengan gambar di atas, dan saat ini belum ada transfer lebih lanjut:
- bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q (89,62 BTC)
- bc1q0rvn88w08j75k4h48lf9fvhan7unjp7vjf5q6m (64,9 BTC)
- bc1qtfrwa4j6rmj9rsgspv6a0yjumkg39js2numu75 (45,9 BTC)
- bc1qmd5m5ktv7m5ffujxv4248fxv36myvdx79n8jp6 (30,18 BTC)
Serangan terhadap dompet Coldcard masih berlangsung, tim Beosin terus memantau lebih banyak alamat pengumpulan dan menganalisis arus dana terkait.
Tiga, Penutup
Insiden keamanan besar pada dompet perangkat keras Coldcard ini berasal dari kesalahan implementasi tim pengembang dalam pembangkitan angka acak, yang menggunakan pembangkit angka pseudo-acak pada tahap kritis pembuatan seed dompet. Tim pengembang harus melakukan pengujian dan audit kode secara berkelanjutan dan menyeluruh, sementara pengguna Coldcard Wallet sebaiknya segera memindahkan aset mereka dan memantau pengumuman keamanan selanjutnya dari Coinkite.
Beosin adalah perusahaan teknologi keamanan blockchain dan kepatuhan regulasi terkemuka yang berfokus pada audit keamanan kontrak cerdas sebelum peluncuran proyek, pemantauan dan pencegahan risiko keamanan selama operasi proyek, pemulihan aset yang dicuri, anti pencucian uang (AML) untuk aset virtual, serta investigasi dan pelacakan. Beosin telah menyediakan produk kepatuhan blockchain "all-in-one" dan layanan keamanan kepada 200+ penyedia aset virtual, serta 4.500+ proyek Web3 di lebih dari 20 negara dan wilayah di seluruh dunia.

