Lỗ hổng ví phần cứng Coldcard dẫn đến việc đánh cắp hơn 88 triệu bitcoin

iconMetaEra
Chia sẻ
AI summary iconTóm tắt
Một lỗ hổng trong ví phần cứng Coldcard do RNG được cấu hình sai đã dẫn đến việc đánh cắp hơn 594 BTC, tương đương hơn 88 triệu USD. Vấn đề này ảnh hưởng đến các mẫu Coldcard Mk2, Mk3, Mk4, Q và Mk5, làm lộ khóa riêng tư cho các cuộc tấn công bạo lực. Beosin đã theo dõi các quỹ tổng hợp đến một số địa chỉ Bitcoin. Sự cố này làm dấy lên lo ngại dưới CFT và nhấn mạnh sự cấp thiết của việc tuân thủ MiCA khi EU siết chặt quy định về tiền mã hóa.

Thiệt hại vượt quá 88 triệu USD: Phân tích lỗ hổng phần cứng Coldcard và theo dõi số tiền bị đánh cắp Vào ngày 31 tháng 7, khoảng 500 ví phần cứng Coldcard đã bị đánh cắp tổng cộng 594 bitcoin, trị giá khoảng 38 triệu USD. Sau đó, công ty Coinkite chịu trách nhiệm sản xuất ví Coldcard xác nhận rằng sản phẩm này có lỗ hổng bảo mật trong quá trình tạo khóa, ảnh hưởng đến nhiều thế hệ sản phẩm như Coldcard Mk2, Mk3, Mk4, Q và Mk5.

Hiện tại, số tiền thiệt hại do cuộc tấn công khai thác lỗ hổng này đã vượt quá 88 triệu USD, và cuộc tấn công vẫn đang tiếp diễn. Người dùng ví Coldcard nên chuyển tiền của mình sang địa chỉ khác càng sớm càng tốt. Phân tích của Beosin về lỗ hổng này và tình hình theo dõi số tiền bị đánh cắp như sau.

I. Phân tích lỗ hổng

Phân tích lịch sử commit của mã firmware Coldcard, có thể thấy rằng trong commit trước đó 37e4af5451c260c1e7d429fe8972c4cb5e68ee59, nhóm phát triển đã cập nhật nhiều đoạn mã liên quan đến cấu hình MK4, bao gồm trong mpconfigboard.h:

// Chúng tôi có phiên bản riêng của mã này. #define MICROPY_HW_ENABLE_RNG (0)

Trên nền tảng MicroPython STM32, macro này điều khiển đường dẫn biên dịch cho bộ tạo số ngẫu nhiên phần cứng mặc định (RNG) và triển khai số ngẫu nhiên chung. Đặt nó thành 0 sẽ khiến đường dẫn RNG phần cứng mặc định không được sử dụng làm backend cho rng_get() chung.

Ghi chú của nó cho biết nhà phát triển sẽ tự triển khai RNG, khi kiểm tra tệp rng.h tùy chỉnh, chỉ thấy khai báo hai đối tượng MicroPython:

MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj); MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);

Việc triển khai tương ứng là:

/// \function pyb_rng_get()///// Trả về một số ngẫu nhiên do phần cứng tạo ra gồm 30 bit: hoặc báo lỗi!//STATIC mp_obj_t pyb_rng_get(void){    // Lấy và trả về số ngẫu nhiên mới    return mp_obj_new_int(rng_get_or_fault() >> 2);}
/// \function rng_get_bytes()/// Điền bộ đệm bằng các bit ngẫu nhiên; người gọi phải cung cấp bộ đệm có kích thước xác định.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);    }
    // Đọc các từ 32-bit và giải nén vào bộ đệm đã cung cấp    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() đọc trực tiếp thiết bị RNG của STM32:

static uint32_t rng_get_or_fault(void){    // Bật peripheral RNG nếu chưa được bật    rng_init();
    // Chờ cho đến khi có số ngẫu nhiên mới sẵn sàng, mất khoảng 10us    uint32_t start = HAL_GetTick();
    while (!(RNG->SR & RNG_SR_DRDY)) {        if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) {            // lỗi phần cứng... không trả về bất kỳ giá trị nào!            mp_raise_OSError(MP_EFAULT);        }    }
    // Lấy và trả về số ngẫu nhiên mới    last_value = RNG->DR;
    return last_value;}

Điều này cho thấy mã tùy chỉnh của Coldcard thực sự muốn sử dụng RNG phần cứng, nhưng nó chỉ đảm bảo sử dụng hàm phần cứng này khi gọi pyb_rng_get* hoặc random_buffer() bên trong của nó.

Và khi tạo ví, mã sau đây thực sự được gọi, trong đó hàm tạo ví trong shared/seed.py là:

async def make_new_wallet(nwords):    # Chọn một seed ngẫu nhiên mới.    await ux_dramatic_pause('Đang tạo...', 3)    seed = generate_seed()    words = await approve_word_list(seed, nwords)    if words:        await commit_new_words(words)

Lời gọi này đầu tiên đi vào mô-đun shared/random.py của Coldcard. Trong các phiên bản trước, random.py phụ thuộc rõ ràng vào ngu.random và giữ lại:

# random.py - một phần của module random, không có tính tương thích và sử dụng rng chất lượng mật mã  
# để xử lý bytes, hãy dùng ngu.random.byte(len)  
# bytes = ngu.random.bytes

Tức là, khi khởi tạo ví, sử dụng random.bytes, không phải pyb.rng(), và pyb_rng_get_obj được tùy chỉnh không tự động ghi đè lên random.bytes.

Do MICROPY_HW_ENABLE_RNG được đặt thành 0, nên khi tạo ví, không sử dụng RNG phần cứng mà gọi đến pyb_rng_yasmarang trong micropython/ports/stm32/rng.c:

#if MICROPY_HW_ENABLE_RNG
uint32_t rng_get(void) {    // sử dụng RNG phần cứng STM32    ...}
#else
// Đối với các MCU không có RNG, chúng ta vẫn cần cung cấp hàm rng_get()// Một bộ tạo số ngẫu nhiên giả không thực sự lý tưởng, nhưng chúng ta sẽ sử dụng nó trong lúc này.
// Bộ tạo số ngẫu nhiên 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

Trong khi đó, pyb_rng_yasmarang là bộ tạo số ngẫu nhiên giả, việc sử dụng nó để tạo seed cho ví phần cứng là cực kỳ không an toàn, vì kẻ tấn công có thể lấy được khóa thông qua tấn công bạo lực. Hiện tại, Coinkite đã loại bỏ rõ ràng stm32/rng.c trong tệp makefile:

# Không biên dịch PRNG dự phòng của MicroPython. Tệp rng.c cụ thể cho bo mạch
# cung cấp hàm rng_get(), và đối tượng trống này đáp ứng danh sách đối tượng từ nguồn.
$(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 $@

Hai: Theo dõi số tiền bị đánh cắp

Hiện tại, vốn từ nhiều ví nạn nhân đã được chuyển và tập trung vào nhiều địa chỉ khác nhau, nhưng chưa được làm sạch thêm. Beosin Trace thông qua phân tích tình báo đe dọa và hành vi trên chuỗi, đã phát hiện các địa chỉ tập trung sau:

bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r (562 BTC)

https://wdcdn.qpic.cn/MTMxMDI3MDE1MTgxMDU0NzA_369595_usmImxZpHsKmu9X__1785899827?w=1080&h=656

bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3 (398,47 BTC)

https://wdcdn.qpic.cn/MTMxMDI3MDE1MTgxMDU0NzA_304781_-IeWjFtIQ4RhvCbz_1785899827?w=1080&h=674

Ngoài ra, còn có các địa chỉ tập trung sau đây, sơ đồ luồng tiền của chúng tương tự như biểu đồ trên, hiện chưa có chuyển tiếp nào thêm:

  • bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q (89,62 BTC)
  • bc1q0rvn88w08j75k4h48lf9fvhan7unjp7vjf5q6m (64,9 BTC)
  • bc1qtfrwa4j6rmj9rsgspv6a0yjumkg39js2numu75 (45,9 BTC)
  • bc1qmd5m5ktv7m5ffujxv4248fxv36myvdx79n8jp6 (30,18 BTC)

Các cuộc tấn công vào ví Coldcard vẫn đang tiếp diễn, đội ngũ Beosin đang tiếp tục theo dõi các địa chỉ thu gom thêm và phân tích luồng tiền liên quan.

Ba, Kết luận

Sự cố bảo mật nghiêm trọng này đối với ví phần cứng Coldcard xuất phát từ lỗi triển khai của đội ngũ phát triển trong việc tạo số ngẫu nhiên, khi sử dụng bộ tạo số giả ngẫu nhiên trong giai đoạn quan trọng tạo seed ví. Đội ngũ phát triển cần thực hiện kiểm tra và kiểm toán mã nguồn liên tục và toàn diện, còn người dùng ví Coldcard nên nhanh chóng chuyển tài sản và theo dõi sát các thông báo bảo mật tiếp theo từ Coinkite.

Beosin là một công ty công nghệ hàng đầu về bảo mật blockchain và tuân thủ quy định, chuyên về kiểm toán bảo mật hợp đồng thông minh trước khi dự án ra mắt, giám sát và ngăn chặn rủi ro bảo mật trong quá trình vận hành dự án, truy tìm tài sản bị đánh cắp, chống rửa tiền (AML) cho tài sản ảo và điều tra truy vết. Beosin đã cung cấp các sản phẩm tuân thủ blockchain và dịch vụ bảo mật “một cửa” cho hơn 200 nhà cung cấp tài sản ảo, hơn 4.500 dự án Web3, cùng các cơ quan quản lý và thực thi pháp luật tại hơn 20 quốc gia và vùng lãnh thổ trên toàn cầu.

Tuyên bố miễn trừ trách nhiệm: Thông tin trên trang này có thể được lấy từ bên thứ ba và không nhất thiết phản ánh quan điểm hoặc ý kiến của KuCoin. Nội dung này chỉ được cung cấp cho mục đích thông tin chung, không có bất kỳ đại diện hay bảo đảm nào dưới bất kỳ hình thức nào và cũng không được hiểu là lời khuyên tài chính hay đầu tư. KuCoin sẽ không chịu trách nhiệm về bất kỳ sai sót hoặc thiếu sót nào hoặc về bất kỳ kết quả nào phát sinh từ việc sử dụng thông tin này. Việc đầu tư vào tài sản kỹ thuật số có thể tiềm ẩn nhiều rủi ro. Vui lòng đánh giá cẩn thận rủi ro của sản phẩm và khả năng chấp nhận rủi ro của bạn dựa trên hoàn cảnh tài chính của chính bạn. Để biết thêm thông tin, vui lòng tham khảo Điều khoản sử dụngTiết lộ rủi ro của chúng tôi.