8800万ドル以上の損失:Coldcardハードウェアウォレットの脆弱性分析と盗難資金の追跡 7月31日、約500台のColdcardハードウェアウォレットから合計594枚のビットコインが盗まれ、価値は約3800万ドルに上った。その後、Coldcardウォレットの製造を手がけるCoinkite社は、この製品の鍵生成プロセスにセキュリティ脆弱性が存在することを確認し、Coldcard Mk2、Mk3、Mk4、Q、Mk5など複数世代の製品が影響を受けていると発表した。
現在、この脆弱性を悪用した攻撃による損失額は8800万ドルを超え、攻撃は継続中です。Coldcardウォレットのユーザーは、速やかに資金を他のアドレスに移動してください。Beosinによる本脆弱性の分析および盗難資金の追跡状況は以下の通りです。
一、脆弱性分析
Coldcardファームウェアのコードコミット履歴を分析すると、以前のコミット37e4af5451c260c1e7d429fe8972c4cb5e68ee59で、開発チームがMK4設定に関する複数のコードを更新しており、mpconfigboard.hには以下が含まれています:
// 私たちはこのコードの独自バージョンを持っています。#define MICROPY_HW_ENABLE_RNG (0)
MicroPython STM32側では、このマクロはデフォルトのハードウェア乱数生成器(RNG)のバインドと汎用乱数実装のコンパイルパスを制御します。これを0に設定すると、デフォルトのハードウェアRNGパスは汎用rng_get()のバックエンドとして使用されません。
その注釈では、開発者がRNGを自前で実装するとあり、カスタムのrng.hを確認すると、MicroPythonオブジェクトが2つだけ宣言されていることが分かる。
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()///// 30ビットのハードウェア生成ランダム数を返す:または失敗!//STATIC mp_obj_t pyb_rng_get(void){ // 新しいランダム数を取得して返す return mp_obj_new_int(rng_get_or_fault() >> 2);}
/// \function rng_get_bytes()/// ランダムビットでバッファを埋める;呼び出し側がサイズ指定済みのバッファを提供する必要がある。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); }
// 32ビット単語を読み取り、指定されたバッファに展開する 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() は STM32 RNG パーリフェルを読み取ります:
static uint32_t rng_get_or_fault(void){ // RNGペリフェラルが有効でない場合、有効化する rng_init();
// 新しいランダム数が準備できるのを待つ(約10usかかる) uint32_t start = HAL_GetTick();
while (!(RNG->SR & RNG_SR_DRDY)) { if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) { // ハードウェア障害... 何も返さない! mp_raise_OSError(MP_EFAULT); } }
// 新しいランダム数を取得して返す last_value = RNG->DR;
return last_value;}
これは、ColdcardのカスタムコードがハードウェアRNGを使用することを意図していることを示していますが、pyb_rng_get*またはその内部のrandom_buffer()を呼び出した場合にのみ、そのハードウェア関数を使用することを保証しています。
一方、ウォレット作成時に実際に呼び出されるコードは以下の通りであり、shared/seed.py内のウォレット作成関数は:
async def make_new_wallet(nwords): # 新しいランダムなシードを選択。 await ux_dramatic_pause('Generating...', 3) seed = generate_seed() words = await approve_word_list(seed, nwords) if words: await commit_new_words(words)
この呼び出しはまずColdcardのshared/random.pyモジュールに進入します。過去のバージョンでは、random.pyは明示的にngu.randomに依存し、以下を保持していました:
# random.py - 互換性なしで、暗号品質のRNGを使用したrandomモジュールのサブセット
# バイトの場合は、ngu.random.byte(len)を使用してください
# bytes = ngu.random.bytes
ウォレットの初期化に使用されているのは pyb.rng() ではなく random.bytes であり、カスタムの pyb_rng_get_obj は random.bytes を自動的に上書きしていません。
MICROPY_HW_ENABLE_RNG が 0 に設定されているため、ウォレット生成時にハードウェア RNG は使用されず、micropython/ports/stm32/rng.c の pyb_rng_yasmarang が呼び出されました。
#if MICROPY_HW_ENABLE_RNG
uint32_t rng_get(void) { // STM32ハードウェアRNGを使用 ...}
#else
// RNGを備えていないMCU向けに、rng_get()関数を提供する必要がある// 疑似RNGは理想的ではないが、現時点ではこれを使用する。
// Yasmarang疑似乱数生成器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はmakefileファイル内で明確にstm32/rng.cを除外しています:
MicroPythonのフォールバックPRNGをコンパイルしない。ボード固有のrng.cがrng_get()を提供しており、この空のオブジェクトがアップストリームのオブジェクトリストを満たす。
$(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 $@
二、盗難資金の追跡
現在、複数の被害者ウォレットの資金が移転され、複数のアドレスに集約されていますが、さらなる洗浄は行われていません。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チームはさらに多くの集約アドレスを監視し、関連する資金の流れを分析しています。
三、まとめ
今回のColdcardハードウェアウォレットの重大なセキュリティ事故は、開発チームが乱数生成の実装に誤りを犯し、重要なウォレットシード生成プロセスで疑似乱数生成を使用したことが原因です。開発チームはコードに対して継続的かつ包括的なテストと監査を実施するべきであり、Coldcardウォレットのユーザーは速やかに資産を移転し、Coinkiteの今後のセキュリティ公告に注目する必要があります。
Beosinは、プロジェクト上場前のスマートコントラクトセキュリティ監査、運用中のセキュリティリスクの監視とブロック、盗難資金の回収、仮想資産の反マネーロンダリング(AML)、および調査・追跡に特化した、世界的にリーディングなブロックチェーンセキュリティおよび規制コンプライアンステクノロジー企業です。Beosinは、世界20か国以上における規制・法執行機関、200社以上の仮想資産サービスプロバイダー、および4,500社以上のWeb3プロジェクトに、「ワンストップ」ブロックチェーンコンプライアンス製品およびセキュリティサービスを提供しています。

