Уязвимость аппаратных кошельков Coldcard привела к краже биткоинов более чем на $88 млн
Сводка рынка от ИИ
Сообщается, что выявленный дефект генерации ключей в аппаратном кошельке Coldcard позволил злоумышленникам похитить более $88M в BTC; эксплуатация уязвимости описывается как продолжающаяся, а средства агрегируются в блокчейне. Хотя это не является проблемой Bitcoin на уровне протокола, инцидент может оказывать давление на краткосрочные настроения, повышая риски хранения и операционные риски, потенциально провоцируя ускоренную миграцию к самостоятельному хранению, усиление внимания к цепочкам поставок аппаратных кошельков и более активный мониторинг связанных адресов биржами и командами по комплаенсу.
Степень влияния
● Высокая
Затронутые активы
BTC/USDT+0.88%
Инсайт ИИ · BTC/USDTИнсайт ИИ
▼ Медвежий
Торговать
⚠️ Инсайты, сгенерированные ИИ, основаны на новостном контенте и предоставляются исключительно в информационных целях. Они не являются инвестиционной рекомендацией и не отражают позицию BingX. Торговля сопряжена с риском. Пожалуйста, торгуйте ответственно.
Общий ущерб превысил $88 млн: разбор уязвимости Coldcard и мониторинг похищенных средств.
31 июля были скомпрометированы около 500 аппаратных кошельков Coldcard. По оценке, злоумышленники похитили 594 BTC на сумму порядка $38 млн. Позже Coinkite, производитель Coldcard, подтвердила наличие уязвимости в процессе генерации ключей, затрагивающей несколько поколений устройств: Coldcard Mk2, Mk3, Mk4, Q и Mk5. Совокупные потери от эксплуатации уязвимости уже превысили $88 млн, атака продолжается. Пользователям Coldcard рекомендуется как можно быстрее перевести средства на новый адрес.
Ниже приведены выводы Beosin по анализу уязвимости и отслеживанию украденных средств.
I. Анализ уязвимости
Изучение истории коммитов прошивки Coldcard показывает, что в коммите 37e4af5451c260c1e7d429fe8972c4cb5e68ee59 команда разработки внесла изменения в участки кода, связанные с конфигурацией MK4. В частности, в mpconfigboard.h было установлено:
// We have our own version of this code.
#define MICROPY_HW_ENABLE_RNG (0)
В MicroPython для STM32 этот макрос определяет путь компиляции для стандартной привязки аппаратного генератора случайных чисел (RNG) и общей реализации random. Значение 0 отключает использование стандартного аппаратного RNG как бэкенда для generic rng_get(). По смыслу комментариев разработчик должен реализовать RNG самостоятельно. В пользовательском файле rng.h объявлены лишь два объекта MicroPython:
MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj);
MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);
Реализация выглядит так:
/// \function pyb_rng_get()
///// Returns a 30bit hardwaregenerated random number, or fails!
//STATIC mp_obj_t pyb_rng_get(void){
// Retrieve and return the new random number
return mp_obj_new_int(rng_get_or_fault() >> 2);
}
/// \function rng_get_bytes()
/// Fills a buffer with random bits; the caller must provide a buffer of appropriate size.
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 SR & RNG_SR_DRDY)) {
if (HAL_GetTick() start >= RNG_TIMEOUT_MS) {
// Hardware failure... do not return anything!
mp_raise_OSError(MP_EFAULT);
}
}
// Retrieve and return the new random number
last_value = RNG>DR;
return last_value;
}
Это указывает на то, что пользовательский код Coldcard действительно нацелен на использование аппаратного RNG, но гарантирует его применение только при вызовах pyb_rng_get* или внутренней random_buffer().
При создании кошелька фактически вызывается другой путь. Функция инициализации в shared/seed.py:
async def make_new_wallet(nwords):
# Select a new random seed.
await ux_dramatic_pause('Generating...', 3)
seed = generate_seed()
words = await approve_word_list(seed, nwords)
if words:
await commit_new_words(words)
Далее управление переходит в shared/random.py. В прежних версиях random.py явно зависел от ngu.random и содержал:
# random.py subset of the random module, with no compatibility, using cryptographically secure RNG
# for bytes, use ngu.random.bytes(len)
# bytes = ngu.random.bytes
Инициализация кошелька использует random.bytes, а не pyb.rng(); при этом пользовательский pyb_rng_get_obj не переопределяет random.bytes автоматически. На фоне MICROPY_HW_ENABLE_RNG = 0 генерация сид-фразы не использовала аппаратный RNG и вместо этого обращалась к pyb_rng_yasmarang из micropython/ports/stm32/rng.c:
#if MICROPY_HW_ENABLE_RNG
uint32_t rng_get(void) {
// Use STM32 hardware RNG ...
}
#else
// For MCUs without an RNG, we still need to provide an rng_get() function.
// A pseudoRNG is not ideal, but we use it for now.
// Yasmarang random number generator
static 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
pyb_rng_yasmarang — псевдослучайный генератор, крайне непригодный для создания сидов аппаратного кошелька: злоумышленник может перебором восстановить ключ.
Coinkite также указала, что теперь явно исключает stm32/rng.c из сборки через Makefile:
Do not compile MicroPython's fallback PRNG.
The boardspecific rng.c provides rng_get(), and this empty object satisfies the upstream object list.
$(BUILD)/rng.o: CFLAGS += Dpyb_rng_yasmarang=errordonotwantthis
$(BUILD)/rng.o: $(ECHO) "SKIP stm32/rng.c"
$(Q)$(CC) $(CFLAGS) x c c /dev/null o $@
II. Отслеживание похищенных средств
Средства с кошельков нескольких пострадавших уже были переведены и агрегированы в нескольких адресах, при этом признаков дальнейшего "отмывания" на момент анализа не наблюдается. На основе threat intelligence и анализа ончейн-поведения Beosin Trace выявил следующие адреса-агрегаторы:
bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r (562 BTC)
bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3 (398.47 BTC)
Кроме того, у следующих адресов отмечен сходный сценарий поступления средств; дальнейших переводов пока не зафиксировано:
bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q (89.62 BTC)
bc1q0rvn88w08j75k4h48lf9fvhan7unjp7vjf5q6m (64.9 BTC)
bc1qtfrwa4j6rmj9rsgspv6a0yjumkg39js2numu75 (45.9 BTC)
bc1qmd5m5ktv7m5ffujxv4248fxv36myvdx79n8jp6 (30.18 BTC)
Атаки на пользователей Coldcard продолжаются. Команда Beosin ведет постоянный мониторинг новых адресов-агрегаторов и анализирует связанные потоки средств.
III. Итоги
Крупный инцидент безопасности вокруг аппаратных кошельков Coldcard связан с ошибкой реализации: при критически важной процедуре генерации сид-фразы использовался псевдослучайный генератор. Разработчикам необходимы регулярные комплексные тесты и аудит кода. Пользователям Coldcard следует оперативно перевести активы и внимательно отслеживать дальнейшие сообщения Coinkite по безопасности.
Beosin — компания в сфере безопасности блокчейна и технологий регуляторного комплаенса, специализирующаяся на предрелизных аудитах смарт-контрактов, мониторинге и блокировке рисков в реальном времени, возврате активов, AML для виртуальных активов и расследовательском трейсинге. Beosin предоставляет "one-stop" продукты и услуги по комплаенсу и безопасности регуляторам и правоохранительным органам более чем в 20 странах и регионах, свыше 200 провайдерам услуг с виртуальными активами, а также 4"500+ Web3-проектам.