Add blogpost format, RSS, first blogpost entry

This commit is contained in:
Christian Reitter 2023-11-10 13:34:48 +01:00
parent 7c59abb139
commit 34b0f7e6b7
8 changed files with 204 additions and 3 deletions

View File

@ -1,4 +1,5 @@
source "https://rubygems.org" source "https://rubygems.org"
# gem "jekyll-theme-console", path: "./_vendor/jekyll-theme-console" # gem "jekyll-theme-console", path: "./_vendor/jekyll-theme-console"
gem "jekyll" gem "jekyll"
gem "jekyll-feed"

View File

@ -31,6 +31,8 @@ GEM
safe_yaml (~> 1.0) safe_yaml (~> 1.0)
terminal-table (>= 1.8, < 4.0) terminal-table (>= 1.8, < 4.0)
webrick (~> 1.7) webrick (~> 1.7)
jekyll-feed (0.17.0)
jekyll (>= 3.7, < 5.0)
jekyll-sass-converter (3.0.0) jekyll-sass-converter (3.0.0)
sass-embedded (~> 1.54) sass-embedded (~> 1.54)
jekyll-watch (2.2.1) jekyll-watch (2.2.1)
@ -57,6 +59,8 @@ GEM
sass-embedded (1.63.6) sass-embedded (1.63.6)
google-protobuf (~> 3.23) google-protobuf (~> 3.23)
rake (>= 13.0.0) rake (>= 13.0.0)
sass-embedded (1.63.6-x86_64-linux-musl)
google-protobuf (~> 3.23)
terminal-table (3.0.2) terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3) unicode-display_width (>= 1.1.1, < 3)
unicode-display_width (2.4.2) unicode-display_width (2.4.2)
@ -68,6 +72,7 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
jekyll jekyll
jekyll-feed
BUNDLED WITH BUNDLED WITH
2.4.17 2.4.17

View File

@ -27,15 +27,19 @@ url: "https://milksad.info" # the base hostname & protocol for your site, e.g. h
header_pages: header_pages:
- index.md - index.md
- updates.md
- disclosure.md - disclosure.md
- lookup.md
- faq.md - faq.md
- lookup.md
style: dark # dark (default), light or hacker style: dark # dark (default), light or hacker
listen_for_clients_preferred_style: false # false (default) or true listen_for_clients_preferred_style: false # false (default) or true
footer: '2023' footer: '2023'
plugins:
- jekyll-feed
# Build settings # Build settings
# included locally instead # included locally instead
@ -45,6 +49,12 @@ footer: '2023'
kramdown: kramdown:
toc_levels: 2..3 toc_levels: 2..3
# show post excerpts in post overview
show_excerpts: true
# change URL path to posts
permalink: /posts/:title/
sass: sass:
sass_dir: _sass sass_dir: _sass

View File

@ -1,3 +1,3 @@
<footer> <footer>
<span><img src="/assets/base/milksad_bottle_transparent.svg" height="16px" alt="Milk Sad logo as icon"/></span> {{ site.footer }} <span><a href="{{ site.url | relative_url }}/feed.xml">RSS</a><img src="/assets/base/milksad_bottle_transparent.svg" height="18px" alt="Milk Sad logo as icon"/></span>{{ site.footer }}
</footer> </footer>

33
_layouts/post.html Normal file
View File

@ -0,0 +1,33 @@
---
layout: default
---
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">{{ page.title | escape }}</h1>
<p class="post-meta">
{%- assign date_format = site.minima.date_format | default: "%b %-d, %Y" -%}
<time class="dt-published" datetime="{{ page.date | date_to_xmlschema }}" itemprop="datePublished">
{{ page.date | date: date_format }}
</time>
{%- if page.modified_date -%}
~
{%- assign mdate = page.modified_date | date_to_xmlschema -%}
<time class="dt-modified" datetime="{{ mdate }}" itemprop="dateModified">
{{ mdate | date: date_format }}
</time>
{%- endif -%}
{%- if page.author -%}
Author(s): {% for author in page.author -%}
<span itemprop="author" itemscope itemtype="http://schema.org/Person"><span class="p-author h-card" itemprop="name">{{ author }}</span></span>
{%- if forloop.last == false %}, {% endif -%}
{% endfor %}
{%- endif -%}</p>
</header>
<div class="post-content e-content" itemprop="articleBody">
{{ content }}
</div>
<a class="u-url" href="{{ page.url | relative_url }}" hidden></a>
</article>

View File

@ -0,0 +1,34 @@
---
layout: default
---
<div class="home">
{{ content }}
{% assign posts = site.posts %}
{%- if posts.size > 0 -%}
{%- if page.list_title -%}
<h2 class="post-list-heading">{{ page.list_title }}</h2>
{%- endif -%}
<div class="post-list">
{%- assign date_format = site.minima.date_format | default: "%b %-d, %Y" -%}
{%- for post in posts -%}
<div>
<h3>
<a class="post-link" href="{{ post.url | relative_url }}">
{{ post.title | escape }}
</a>
</h3>
{%- if site.show_excerpts -%}
{{ post.excerpt }}
{%- endif -%}
<span class="post-meta">{{ post.date | date: date_format }}</span>
</div>
{%- endfor -%}
</div>
{%- endif -%}
</div>

View File

@ -0,0 +1,110 @@
---
layout: post
title: "Research Update No. 1 - New bx Data, ETH, Service Changes"
author: "Christian Reitter"
date: 2023-11-23 00:00:00 +0000
---
Three months have passed since discovering the explanation for the observed thefts and our intense sprint towards the initial publication of the `Milk Sad` vulnerability in the blockchain-explorer `bx` wallet software. By quickly publishing, we fulfilled our primary goal of telling the world about the issue - providing an explanation for affected victims, and hopefully sparing some future users from the same fate. The disclosure also raised the public profile of the weak Pseudorandom Number Generators (PRNGs) vulnerability class and underlined the catastrophic impacts it can have in the cryptocurrency world.
After the dust settled and things got back to normal, most of our team members have now turned their focus back to their day jobs and other projects.
Curiosity is a powerful motivation, though, and so a few members of the group keep digging into more details of the fallout of weak `bx` keys, similar vulnerabilities involving weak private keys, and related security research that interests us.<br/>
Going forward, we will make use of individual blogposts to share new details, discoveries, and other topics we see as notable.
<div id="toc-container" markdown="1">
<h2 class="no_toc">Table of Contents</h2>
* placeholder
{:toc}
</div>
## Summary of Weak BIP39 Private Keys for bx 3.x
In the original publication, [we listed]({% link disclosure.md %}#searching-for-wallets---implementation) some aggregated statistics of the discovered Bitcoin wallet private keys in the BIP39 range associated with `bx` `3.x`, the main CVE-2023-39910 impact, that we had found at the time.
Our updated current statistics on discovered wallets and path usage are as follows:
| BIP39 entropy bit length <br/>_mnemonic length_ | 128 bit<br/>_12 words_ | 160 bit<br/>_15 words_| 192 bit <br/>_18 words_| 224 bit <br/> _21 words_| 256 bit <br/>_24 words_|
| -- | -- | -- | -- | -- | -- | -- |
| `m/44'/0'/0'/0/0` path | 8 | 0 | 2 | 0 | 14 |
| `m/49'/0'/0'/0/0` path | 1 | 0 | 1 | 0 | 2634 |
| `m/84'/0'/0'/0/0` path | 0 | 0 | 1 | 0 | 9 |
| -- | -- | -- | -- | -- | -- |
| sum of unique wallet private keys | 9 | 0 | 4 | 0 | 2654 |
In the 256 bit range, there are two wallets which used multiple paths.
The total number of known weak BIP39 private keys with Bitcoin Mainnet usage (on the analyzed paths and address formats) in this range is therefore **2667**.
Additional notes:
* Our search doesn't detect wallets used exclusively with an additional BIP39 user passphrase, non-standard path use or multisig wallets.
* We scanned the 15 word (160 bit) and 21 word (224 bit) BIP39 seed ranges, but found them empty, at least on the common paths. While `bx mnemonic-new` can create those variants of the BIP39 standard, they are not so common. This result is therefore plausible to us.
* In the [original writeup]({% link disclosure.md %}#searching-for-wallets---implementation), we outlined that many of the `3`-prefix BIP49 wallets in the 256 bit range likely belong to the same entity. One of the earliest transactions for this seems to be [3931b570..4f501910](https://mempool.space/tx/3931b570e562a58608f9b7f7291d12a40dbe617112c721077e441d264f501910) on 2018-10-03, and many similar transfers to weak wallets in this range happen within the next few days, some with identical transaction amounts.
## Breaking Weak bx 3.x ec-new Private Keys
During the initial research sprint towards understanding and reproducing the `bx` PRNG weakness, we focused on code paths and usage variants that run weak `bx seed` entropy through `bx mnemonic-new` to generate BIP39 mnemonics. BIP39 is the de facto standard for interoperability with other hardware and software wallets for many years now, and was the mechanism used by the affected wallet owners who kicked off our research, which is why we saw this as the most relevant and important variant.
After the public disclosure, we continued our search into another mechanism that `bx` has for wallet generation: the `bx ec-new` mode ([documentation](https://github.com/libbitcoin/libbitcoin-explorer/wiki/bx-ec-new)).
Unlike `bx mnemonic-new`, this is more of a legacy mode and somewhat limited in flexibility. Under the hood, it is based on [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki), but not [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki). Despite following the well-defined "hierarchical deterministic" wallet scheme of BIP32, the ec-new logic is hardcoded to only use the topmost derivation path (`m/`) in combination with the older P2PKH address format (`1`-prefix addresses, [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)).
It took us a bit of time to figure out the details from the `bx` source code, particularly due to the unexpected path usage. Once we knew what we were looking for, the actual wallet private key searches progressed multiple times faster than for the BIP39 variants 😎.
The core reasons for this are:
1. No need to compute the 2048 rounds of PBKDF2-HMAC with SHA512 that BIP39 requires.
2. Use of a single derivation path for the receive address derivation, which doesn't need separate receive address searches.
3. Cheaper address path derivation calculations, since the path is short and doesn't traverse through multiple sub-keys.
To put this into perspective, brute-forcing and checking all possible Bitcoin private keys of a particular `bx seed | bx ec-new` input length range for 2^32 wallet candidates requires only about 70 minutes of wall-time on a modern Ryzen 7950X3D desktop processor according to our experiments, without the need for GPUs or other accelerators. In other words, this is a very practical attack!
We found the following new Bitcoin wallets:
| entropy bit length | 128 bit | 192 bit | 256 bit | 512 bit |
| -- | -- | -- | -- | -- |
| number of wallets, `m/` path | 2 | 54 | 12 | 1 |
Overall, we discovered **69** such new wallets in total.
Additionally, we did not find any wallets in the following bit length range variations: 64 bit, 160 bit, 224 bit, 384 bit, 768 bit, 1024 bit, 2048 bit, 3072 bit, 8192 bit.
A noteworthy detail here is the apparent trend towards `192 bit` wallets, which is the default bit length of `bx seed`. It appears that users of `bx ec-new` had less reason or motivation to override the default settings, which is different from the BIP39 keys where 24-word (256 bit) and 12-word (128 bit) mnemonics were more popular. One possible explanation is that users were less concerned with compatibility of the generated private key by other software, since it's not widely used elsewhere.
Some relevant facts about the discovered wallets from ec-new:
* Earliest use on 2016-12-15, likely with a pre-release version of `bx` `3.0.0`. All other usages are after the official release date.
* Overall, a total cumulative volume of **111.94BTC** has moved across the weak wallets of this type.
* The last large outgoing transaction from this set of wallets is [3a5b1c78..f54fe376](https://mempool.space/tx/3a5b1c7816217f56a583f7dc910ffef2d022ed69e3c599e82bb4813df54fe376) with **1.13 BTC**, which happened on 2023-03-31 18:58. It is unclear to us if this is theft or a legitimate movement.
* The attacker behind the [2023-07-12 main theft]({% link disclosure.md %}#ongoing-on-chain-thefts---some-facts) was in control of at least one of these private keys, as proven by stealing from [1JUdUgFm7B9GZihtf4jtryCmt4YcRMaJGx](https://mempool.space/address/1JUdUgFm7B9GZihtf4jtryCmt4YcRMaJGx) via one of the three main theft transactions. The stolen amount was small: **0.0015 BTC**, less than $50 at the time.
* In August 2023, several small outgoing transactions moved other remaining funds, which individually were worth a few dollars. We think these were intentionally skipped by the attacker due to the remaining low value considering the transfer fee overhead, and are now slowly swept by other opportunistic thieves. The primary destination address for this is [bc1q0yxd9avwy2wnj7lpj35v5d5n5ejfn79mk37xgd](https://mempool.space/address/bc1q0yxd9avwy2wnj7lpj35v5d5n5ejfn79mk37xgd).
To summarize, the `bx ec-new` type of wallets generated with the weak `bx seed` PRNG were indeed used over multiple years and held sizeable funds. Based on our current understanding, the wallet owners were lucky enough that the PRNG issue was not exploited until some point 2023. Only one minor loss from this range can clearly be attributed to the 2023-07-12 theft actor.
## 2023-07-12 On-Chain Theft - Ethereum Addresses
In our [initial analysis]({% link disclosure.md %}#ongoing-on-chain-thefts---some-facts), we listed several Bitcoin transactions that transferred money away from `bx` wallets with weak private keys.
On Ethereum, we regard [0xaa8b55e2..854e9125](https://etherscan.io/txs?a=0xaa8b55e21ef3df5f15adf4d0f49d3bfa854e9125) as the main address used by the primary thief to steal coins and related assets in the Ethereum ecosystem from weak `bx` wallets. The vast majority of these transactions also happened on 2023-07-12 within hours of the Bitcoin theft transactions, strongly suggesting this Ethereum account was used by the same person or group.
According to a [Reddit post](https://reddit.com/r/trustwalletcommunity/comments/150qpcp/trust_wallet_hacked_trust_vulnerability/), at least one apparent victim used a weak [Trust Wallet]({% link disclosure.md %}#not-even-the-second-hack-mersenne-twister-use-in-trust-wallet) private key, and not a weak `bx` private key. We have not confirmed this ourselves yet, but it sounds very plausible to us given the overall timeline and similarity between the Trust Wallet and `bx` PRNG implementation issues that the attacker stole from a pool of Trust Wallet- and `bx` users, plus potentially other weak wallets they were tracking.
Observations:
* The funds collected and forwarded by this address within a week of the time of the main theft exceeds **1350 ETH**, plus many additional ERC20 assets which are valuable on their own.
* Unlike the Bitcoin theft destination addresses, `0xaa8b55e2..854e9125` account stayed active for several days in July 2023.
* The account has some brief activity again in August 2023.
Counting just the identified amount of Ethereum that went through this account, this adds over $2.5M USD to the overall theft volume (@ $1,868.50 USD / 1 ETH on 2023-07-12), if all of was gained by illegitimate means. We'll go further into this in a future blog post.
## Milk Sad Lookup Server - End of Service
We're shutting down the [lookup]({% link lookup.md %}) service for weak BIP39 mnemonics.
Despite the challenges involved, it was important to us to give potentially affected wallet owners a way to verify if they are using a known weak wallet, and the lookup service filled that gap.
Internally, we intended this to be a time-limited service from the start, and now the moment has come to spin it down.
We hope the service has been useful for some of you.
## New Git Repositories
We've published some of the underlying source code and configuration behind the lookup server [here](https://git.distrust.co/milksad/lookup). This does not allow a direct 1:1 replication of the service since the underlying search data isn't included, but could still be useful as a reference. It also includes the Rust source code for generating a fast bloom filter and searching entries against it, which we've used in a similar role for the main research as well.
The source code and content for this `milksad.info` website you're reading is now also available in a [public repository](https://git.distrust.co/milksad/website-public). If you're interested in how the Jekyll static website generation is configured and which changes we're making to the published content over time, go check it out!
## Outlook
Our research has led us deeper into the Mersenne-Twister rabbit hole, and we have new results to share about weak Trust Wallet private keys, and more. We've now got a new [RSS]({% link feed.xml %}) feed for updates, if you don't want to miss the next post.
Stay tuned!
<br/>

8
updates.md Normal file
View File

@ -0,0 +1,8 @@
---
title: /updates
layout: post_overview
permalink: /updates.html
---
# Research Updates
News on several Lost 'n' Found boxes full of private keys 🔑🔥