Widespread re-use of SSH Host Keys in Ethereum Mining Rig Operating Systems

Written 2020-04-10

Tags:Cryptocurrency Ethereum Crypto SSH 

How this started

A friend came to me last fall wondering how their newly set up mining rig kept getting rooted. This happened over a few different mining OSs. Eventually we found an old firewall rule allowing inbound SSH access, and the mining rig had lost the DHCP lottery and SSH was exposed. Rather than close the hole immediately we decided to do some logging. We set up a new, fresh install and waited. Mostly, we got the usual SSH scanners hitting the box, but rarely our attacker would log in with the right default password on the first try. That's strange - default passwords change per mining OS, so how would they know what OS was running?

I myself have a GPU rig, for machine learning and other purposes. But while it's idle to me, it mines. Strangely, I noticed that the SSH host-keys on my box predated the software installation, which made me curious who generated them.

With these two bits of knowledge, I discovered a widespread key-reusage bug, worked with the mining OS groups, and filed several CVEs.

What exactly are SSH host keys?

SSH host keys provide a mechanism so that a server can be fingerprinted and identified to a client as a trusted entity, worthy of being fed a password through a login attempt. In other words:


The SSH key should be unique per host, both to prevent a bad actor compromising one machine being able to impersonate another, and to prevent a bad actor from enumerating identifiable hosts by looking for known public keys.

The Problem

Several Linux-based Ethereum mining platforms constructed host-keys prior to disk image generation. This means that a large number of systems share the SSH host keys. In addition to being able to impersonate servers, we can search shodan.io or use an SSH host-public-key scanner to identify hosts accessible on the public IPv4 space. It also means that it is fairly easy to construct a dictionary mapping public key to default credentials for some mining OSs.

The Extraction Process

For each mining image, the disk image was downloaded, and testdisk was run to extract the SSH keys. Testdisk had trouble with a few images, so the remaining ones were booting in a VM. SSH keys were then searched on shodan.io to confirm the presence of IPv4 exposes hosts.


It seems attackers have weaponized SSH host keys, both as a means of identifying hosts, and identifying default exploits like unchanged default usernames and passwords. Additionally, most appliances or IoT devices should not be exposed on IPv4/6 for ingress from the general internet. This sentiment was echoed by some mining OS vendors who did not recognize shared host keys as an issue until presented with results showing their miners were easily identifiable online. Finally, a secure automatic update path is a must - without this miners will remain exposed until manually patched, likely with many miners unaware they are exposed.

Affected Platforms and Keys and Host Counts

PlatformSSH Host Key(Search Shodan For This)Shodan.io Host Count(when found)

Responsible Disclosure

An effort was made to contact the authors of each identified OS, and publication was delayed four months in an effort to allow vendors to patch their distributions:
Platform CVE Initial Report Outcome
MinerStat CVE-2019-19750 Sept 8, 2019 Fixed issue promptly.
nvOC CVE-2019-19752 Dec 1, 2019 Devs on bitcoin talk said it would be fixed in next release.
EasyMine CVE-2019-19751 Sept 23, 2019 Fixed Dec 5, 2019
SimpleMiningOSCVE-2019-19753 Sept 8, 2019 Declined to fix, pinged again, said they would consider.
HiveOS CVE-2019-19754 Sept 9, 2019 Said thank you for submitting, they would consider it. Never heard back.
EthOS CVE-2019-19755 Dec 1, 2019 Stated in IRC they would ask developers to fix it
MinerBabe CVE-2020-5200 Dec 3, 2019 Said they would fix it, but did not say anything about fixing the SSH login key shipped in the image.

JSON and KML now available for OpMap

Written 2020-03-20

ULS Search now has options for JSON and KML output.

Setting up ESP8266 for sample-based profiling and debugging

Written 2020-02-22

Tags:Espressif Xtensa ESP8266 

This weekend I finally got my ESP8266 working with OpenOCD's JTAG sample-based profiling. There were four problems, one with the Arduino Core, two with OpenOCD, and a similar bottleneck to ESP32.

First, the Arduino Core defaults all GPIO-capable pins into GPIO inputs. This very quickly disables the JTAG pins. The solution is simply:


Next, OpenOCD's reg command was returning no registers, because they were marked as exist=false. Also OpenOCD's profiler looks for a register, PC, but the ESP8266 only implemented pc, and OpenOCD's profiler is case-sensitive.

This is fixed in my OpenOCD port.

Why ESP32 sample-based profiling will likely never be fast

Written 2020-02-17

Tags:Espressif ESP32 Xtensa 

This weekend I investigated why sample-based profiling was so slow with OpenOCD on ESP32 over JTAG; this is a report of my findings.

When I started, I was getting about 8 samples per second using a J-Link debugger at 10MHz. When I was done, I was up to around 10. This is not a story of great success.

On Cortex-M, reading the program counter over JTAG is rather straightforward. The program-counter is usually memory-mapped to DWT_PCSR, so you let the core run, and spam reads from the DWT_PCSR, then halt the core when you are done.

On Xtensa, the situation is a little more complicated. The CPU core is accessed via the DebugDataRegister(special function register 104, DDR). To access a general (also known as address registers for Xtensa) register over JTAG, the instruction WriteSpecialRegister(WSR) is used to copy a general register into DDR, like WSR A3, DDR. However, the program-counter is not accessible as a general register like A3, it's accessible when the core is halted in the ExceptionProgramCounter(EPC) special function registers. This means we must use ReadSpecialRegister(RSR) to first fetch the EPC into a general purpose register, then use WSR to copy it to the DDR register, where we can read it over JTAG. However, this corrupts the general purpose register we used, so the minimum sequence appears to be:

As an optimization, on halt, OpenOCD reads all the registers out of the core so that they are available for debugging. This is useful for debugging; however, it adds some extra overhead for profiling, where we really just care about the program counter.

It may be possible to add a dedicated path for profiling where we fetch just a handful of registers. This could be around 2-3x faster than the current approach, but always bottlenecked by the stop-and-go-approach of program-counter sampling.

Reverse Engineering PhoenixMiner JSON API

Written 2019-12-25

Tags:Ethereum PhoenixMiner 

In this video, I take a look at how PhoenixMiner implements JSON APIs by reverse engineering the function that identifies and calls each API.