A Novice Mistake: Meet Milk Sad … And The 32-bit Key!!!!!!

A team of developers at Distrust and others has discovered a weakness in the cryptographic methods of creating a random seed for the…

A Novice Mistake: Meet Milk Sad … And The 32-bit Key!!!!!!

Apple [Here] Spotify [here]

A team of developers at Distrust and others has discovered a weakness in the cryptographic methods of creating a random seed for the Libbitcoin Explorer wallet. This is allegedly behind a number of cryptocurrency thefts on 12 July 2023, and on November 2022. The vulnerability has been given the CVE identifier of CVE-2023–39910 and dubbed Milk Sad [here]:

Basically, the wallet uses the bx seed program and which uses a Mersenne Twister [here] for its random generator. Overall it is a secure method when used with a strong seed value. Normally these nonce values are at least 92 bits long, but more typically, at least 128 bits. Unfortunately, in this case, it is initialised with 32 bits of system time. A sample run as [here]:

% bx seed 
6183d30558f3f56b0f7248aea1ed9b1098037ff5ad5eea69
% bx seed
090a30f539d443b9ca61cc40c0e8142fc3e95c2e2d288a85
% bx seed | bx ec-new > private_key
% cat private_key
43c8175d0dc33bfca0bd6bb5f758fd3489da33b08e9b65cd377436952cbc6eb3

We can see that bx seed is generating a random number which has 48 hex characters, and thus 24 bytes. This gives us 192 bits of output, but the nonce is along 32 bits long. We then use ec-new to create a 256-bit private key for secp256k1.

And so the problem is trivial … we only use 32 bits of system time to generate the random seed:

For anyone who has studied cryptography, you should know that we need at least 72 bits of a random seed to be safe from brute force recovery — this is known as the key entropy. Basically, cracking a 32-bit value is fairly easy … if not trivial. For this, the number of possible keys will thus be:

4,294,967,296

whereas normally, we need 256 bits of entropy, which is:

115792089237316195423570985008687907853269984665640564039457584007913129639936

Overall, it will take less than a day to brute force a private key, as we only have, on average, to search though half of the 2³² space. There are a few ways to setup bx, but once the base configuration is known, it is then easy to brute force the key. Once the private key is discovered, the intruder can then drain the wallet of cryptocurrency — by signing transfers.

The name “Milk Sad” comes from a system time of 0.0 gives a secret of:

milk sad wage cup reward umbrella raven visa give list decorate bulb gold raise twenty fly manual stand float super gentle climb fold park

Conclusions

This is sheep-following-sheep. Someone on the Internet would have shown the bx key generation method and then just followed it. More details of the vulnerability here:

Here is more technical details:

Postscript

With Bitcoins, we create a 256-bit random for the private key and then convert it to Wallet Interchange Format key (WiF) format, which is a Base-58 form for the random key. This is the format that is stored in the Bitcoin Wallet. For example, a sample private key is [here]:

Private key: 5c04990cf2fb95ca8749d4021100ee98b0744e81a5ec00a2177aeaf4b29c00d3

We then convert this into WiF format (Base-58) to give:

5JWp4FM7sfAAE88DW3yvGF5mQyrsEXeWzXZn79bg61Vg8YMfJjA

This can be stored in a Bitcoin wallet. Next we can take the private key and a hash value, and covert it into a useable Bitcoin address, such as:

1A3CohNBuB6kFAMtp3KFEYwv3Eu58F2HyN

The format of the keys is defined below, where we create a 256-bit private key and convert this to a WiF private key. Next, we generate a 512-bit public key, and then take a 160-bit RIPEM-160 hash and convert to a Bitcoin address:

The following defines the coding [here]:

echo Seed
bx seed
echo EC private key
bx seed | bx ec-new
echo Mnemonic
bx seed | bx mnemonic-new
echo Wif
bx seed | bx ec-new | bx ec-to-wif
echo Public key
bx seed | bx ec-new | bx ec-to-public
echo Bitcoin address
bx seed | bx ec-new | bx ec-to-public | bx ec-to-address

A sample run is [here]:

Seed
d221fb46899e5289854dfb5bd2061ccc9e81e250ee23412e

EC private key
b274570e2afe1cc740d85361355ffdf9b6553d77a165f9de0c1fe8ba8147748e

Mnemonic
uniform faint aim genuine nuclear desk analyst pencil level talk sheriff vibrant fruit harvest estate outdoor salon prize

Wif
KzamaTJW3SC1Dd4CzPyeLMUQDShpf78pwqrgH9wycNwF6noE7y7G

Public key
037c71386365e4edef307f43ee511e953efa0b917158cbd7b1c24e7add8d6c65db

Bitcoin address
1N4hqRzvaTNzGVdytC6KkEaNT9j6XgBsbf

The bx command is:

(base) billbuchanan@ASecuritySite Downloads % ./bx

Usage: bx COMMAND [--help]

Version: 3.2.0

Info: The bx commands are:

address-decode
address-embed
address-encode
base16-decode
base16-encode
base58-decode
base58-encode
base58check-decode
base58check-encode
base64-decode
base64-encode
bitcoin160
bitcoin256
btc-to-satoshi
cert-new
cert-public
ec-add
ec-add-secrets
ec-multiply
ec-multiply-secrets
ec-new
ec-to-address
ec-to-ek
ec-to-public
ec-to-wif
ek-address
ek-new
ek-public
ek-public-to-address
ek-public-to-ec
ek-to-address
ek-to-ec
fetch-balance
fetch-header
fetch-height
fetch-history
fetch-public-key
fetch-stealth
fetch-tx
fetch-tx-index
fetch-utxo
hd-new
hd-private
hd-public
hd-to-ec
hd-to-public
help
input-set
input-sign
input-validate
message-sign
message-validate
mnemonic-new
mnemonic-to-seed
qrcode
ripemd160
satoshi-to-btc
script-decode
script-encode
script-to-address
seed
send-tx
send-tx-node
send-tx-p2p
settings
sha160
sha256
sha512
stealth-decode
stealth-encode
stealth-public
stealth-secret
stealth-shared
token-new
tx-decode
tx-encode
tx-sign
uri-decode
uri-encode
validate-tx
watch-address
watch-stealth
watch-tx
wif-to-ec
wif-to-public
wrap-decode
wrap-encode