HDDCash reference wallet considered unsafe, specific RPC user/pass pair allows access to the API


Intro/Historical note

HDD.Cash, a (C)PoC coin currently supports only a single version of a wallet software, the one provided by the project mantainers (site: https://www.hdd.cash/#wallet-section).

This wallet is obviously based on BitCoin Core and supports most of its features, including RPC server. However, it contains a well-known "bug" which prevents anything from connecting to that RPC server. Even if you configure your wallet properly, any attempts to connect to RPC server via standard protocol will result in authentication failure, similar to the one you'd get using invalid login/password. This makes creating fully-featured pools and exchanges impossible, as certain operations like inspecting recent blocks or issuing transfers cannot be automated.

While I have not tracked its history, it's worth noting that this blockchain already passed block height of 45500. At average ~280 blocks per day, this means it's online for several months, and no solution to this problem wasn't provided so far.

Recently HDD.Cash developers revealed on Twitter, that this is not a bug, but a "security feature", and was added intentionally to prevent "malicious pools and exchanges" from being created. They also announced that they are going to launch such services in a few weeks. This somewhat explains why this "bug" was not resolved yet. I'll leave drawing conclusions to you.

Problem analysis

I've inspected most-recent version of the wallet, package for Windows x64 and for Linux. Source code is not available, so I ended up inspecting binaries:

  • hddcash-v0.16.14.0-f8ebe58-win64-setup.exe
    file: daemon/hddcashd.exe
  • hddcash-v0.16.14.0-f8ebe58-x86_64-linux-gnu.tar.gz
    file: bin/hddcashd

Since I usually work on Windows, I started with the former. I focused on the 'daemon' binaries since these should contain most of the networking and API code while lacking UI, reducing their size and making analysis easier.

Software used for analysis: x64dbg

It took me a while to find code responsible for setting up json-rpc server, but once found, it was pretty easy to notice that it exposes 3 groups of operations:

  • /wallet
  • /hddcash
  • /burst

Last two are configured to be handled by the same code, and simply speaking that part is responsible for providing classic BURST mining API with operations like getMiningInfo or submitNonce.

The first one is responsible for providing API for the wallet operations, that's the one which requires some form of authentication before accepting incoming requests, and that's the one that rejected any communication attempts from 3rd party software.

Authentication is based on HTTP Basic Auth mechanism. It's possible to find pieces of code that checks if the incoming request contains basic-auth headers. Shortly after that, I expected to find code responsible for parsing basic-auth data, and maybe for verifying them.

And that's how it looks like:
disassembly view: verifying incoming authentication data

The wallet loads two hardcoded blocks of text (rainbowed-out on the screenshot), does something with them, and then the result is stored in r14b register.

Shortly after:
disassembly view: using comparison result to accept or reject incoming request

Here we see that [r14b] is used to decide whever to produce a meaningful error message: "incorrect password attempt".

So, yeah. It seems that those two hardcoded blocks of text are used in verification of the incoming "login-password" data. However, the best, or worst, part of it is, what are those blocks?

I intentionally obscured them on the first screenshot, but you can see the last two characters of the second block. It's ==. If you know a bit about basic-auth scheme, you probably know that for some reasons the user+pass information is not send directly, but is first encoded with base64. Base64 pads the result with = character depending on the length of the input data.

It turns out that these two hardcoded blocks of text data contain the expected user and password information. This means that HDD.Cash wallet may ignore configuration of -rpcuser and -rpcpass options, and provides access to the RPC server basing on those hardcoded values.

This has been tested on an unmodified running wallet, and it in fact accepted those credentials and I was able to use its json-rpc API without authentication errors.

After finding this our, I also inspected the Linux version of the wallet, and it contains the same hardcoded blocks of authentication data. I'm pretty sure that it behaves in the same way as Windows version, but I have not tested that on a live linux wallet.

Summary/Opinion

This means that it RPC API works and it is possible to connect to it, you just need to know the login-pass pair. And that pair is unconfigurable and exactly the same for each instance HDD.Cash wallet on any computer.

This also means, that it is not a security feature. It's a security HOLE. The original BitCoin Core wallet provided user with a way to secure the RPC API a bit with a configurable user-pass pair, while this feature in HDD.Cash wallet has been degenerated down to a hardcoded password known "only" to the developers of that wallet. And me. And who knows how many other people.

This also means, that the developers of HDD.Cash wallet were not lying: this is not a "bug". This was done absolutely intentionally. To "prevent malicious pools and exchanges". And potentially allowing people other than the owner of the wallet to connect to RPC API of the wallet, provided that they know the magic words, while the owner of the wallet is expected to not know the magic words and to be unable to connect.

By the way, did I tell you that I obscured the user-pass pair on the screenshot? The binaries are not even packed or obfuscated, now you know to look for ==. I counted several hundred instances of == in the Windows x64 .exe daemon file, so you can find the magic phrase pretty easily, shouldn't take more than 15 minutes of hitting 'find next' in your favourite text editor.

Impact analysis

This is a potential vulnerability for any HDD.Cash wallet that has RPC server enabled.

Typically, this means users who try to automate some operations, or who try integrating the wallet with other software. Pool owners need it to keep balances and transfer mining rewards. Exchanges need a wallet obviously as well. And so on. Users who don't need RPC server probably have it disabled and are safe on that matter.

If you have not explicitely configured the RPC server to be available, then by the rules inherited from BitCoin Core, the RPC server should be disabled by default. I hope it stayed like that. However, there is a slight chance that HDD.Cash developers decided to also ignore this option and that they set it to keep RPC server always alive. I have not verified this at this time.

This vulnerability is limited to some extent by the fact that by default the RPC server accepts incoming connections only from the localhost, so only from the machine the wallet is running on.

If you have not explicitely configured the RPC server to accept connections from other machines as well, you can feel somewhat protected. The wallet should reject connections from remote machines, so only some malware that infected your computer could be able to connect to your wallet. But that's true only if the HDD.Cash developers didn't decide to also ignore this option and to let RPC server accept connections from remote machines. I have not verified this at this time.

I think that they did not do any more damage then hardcoding the user-pass pair. But I may be wrong. I wouldn't except a hardcoded credentials IN A WALLET for fuck's sake in the first place, so who knows what they did out there.

Advice

Ensure that your wallet's RPC ports are not open to the internet. Check what ports your wallet opens (Process Hacker, etc) for listening for incoming connections, and block them on your firewall. Or hack your wallet and find the magic words and hex-edit them to any other text. It's plain there in the exe file. Easily readable and easily editable. Just keep it the same byte-length or else you'll damage the binary file.


Comments 2