The untold story of the PIVX hack

History

Since the launch of Bitcoin in 2011, many new competing cryptocurrency projects have been created. Bitcoin and its clones like Lite coin use the first consensus protocol – Proof-of-Work (PoW), which has advantages and disadvantages. The main advantage is that anybody who wants to control the whole network needs to generate more than 50% of the total hash power to create the majority of generated blocks in the blockchain. At this time, the Bitcoin blockchain network consists of approximately 10,000 nodes, and anybody who would like to conduct a “51%” attack would need to be able to generate 5,000 * 160 TH/s = 800,000 TH/s = 800 Petahashes per second! This is practically impossible for anyone at this time. But enormous hash power is directly translated to consumed electrical energy, which is now the main disadvantage of the Bitcoin blockchain. It was recognized quickly, and another consensus algorithm was introduced – Proof-of-Stake (PoS). The “Peercoin” was the first project launched using the Bitcoin codebase but implementing the PoS consensus to replace the PoW. Unlike the PoW consensus protocol, the PoS consensus does not require enumerating possible nonces to complete a new block, which eliminates the consumption of much of the electrical energy. In other words, we may expect that using the PoS consensus instead of the PoW will eliminate the main disadvantage of the Bitcoin PoW – increased electrical energy consumption. Does it sound too good to be true?

PoS vulnerabilities

To no surprise the PoS consensus algorithm introduced new vulnerabilities. Here is a list of known vulnerabilities:

  • Nothing-at-stake (mining multiple alternatives forks)
  • DoS attack (disrupting network communication between nodes)
  • Sybil attack
  • Fake-stake (another type of DoS attack)
  • PIVX zero-coin attack, double-spending

Nothing-at-stake

This type of attack is well-known, but it appears that it is still more theoretical rather than an actual attack against PoS projects. In short, it may be described as a malicious attempt to build alternative blockchain forks in secret. As soon as one of them has a calculated weight of more than the actual fork, it is published, and other peers agree to roll back the real fork to the point of separation and then accept the new fork with another set of recorded transactions. It effectively allows to double-spend any amount of coins. However, there is no confirmation that this vulnerability ever impacted any real projects.

DoS attack

A generic Denial of Service (DoS) attack targets participating blockchain nodes. The primary goal is to overload nodes and remove them from participating in the consensus process. Usually, it may be achieved by finding vulnerable code and sending malformed data packets to nodes to cause either high CPU/RAM consumption or even crash them. The possibility of such attacks mostly depends on the quality of the code (infinite loops, etc.), but sometimes it may be caused by flaws in the original algorithm. The “Fake-stake” attack is a good example of an attack that is similarly based on a logical flaw.

Fake-stake attack

This interesting type of attack belongs to the domain of DoS attacks and has impacted multiple PoS projects. The original article was published in Jan 2019 after providing information about the attack to targeted projects in 2018: https://medium.com/@dsl_uiuc/fake-stake-attacks-on-chain-based-proof-of-stake-cryptocurrencies-b8b05723f806

In a few words the attacks was conducted by creating an “amplification” of an invalid stake transaction:

  1. Create a single transaction that contains non-existing staking UTXO
  2. Spend this transaction multiple times in the same block (“amplification”)
  3. Publish a set of transactions to peer nodes to include them into the next block

As soon as a peer node receives a set of malcrafted transactions, it performs initial validation. Transactions pass this check since it looks “valid,” and the only invalid part of transactions is the non-existing staking UTXO transaction hashes. The only way to validate the UTXO hash is to check all existing hashes in the blockchain. Since the hash does not exist and the blockchain database is already huge, the targeted node must process the entire blockchain from the database stored on its hard drive. Also, keep in mind that many nodes have a tight constraint for available RAM. As a result, the impacted node spends a lot of time validating each non-existing hash to decide that the transaction must be rejected. To make things more complicated, an attacker creates a pack of such invalid transactions, about 50-100. Eventually, impacted nodes lag behind the rest of their peers, and due to lagged response, they may be banned by other peers. This starts a chain reaction that causes significant disruption of the blockchain network.

Sybil attack

A Sybil attack creates multiple “identities” that are not connected. In theory, it allows multiplying an attacker’s “voting” power. The PeerCoin project is not impacted since an “identity” of its PoS consensus implementation has “weight” of the coins amount is associated with a participating staking transaction. Thus splitting staking transactions to two or more staking transactions does not multiply its “voting power”.

Ideally, a node should keep all blockchain transactions in RAM to quickly validate its hash. Possible remediations are:

  • Keep a hash map of all transactions hashes in RAM
  • Reject a packet of transactions from a node as soon node threshold of invalid transactions from one node is reached
  • Limit number of transactions in one block (“spam control”)

PIVX Zero-coin attack, double-spending

The PIVX is one of the most famous PoS projects implementing the Zero-coin protocol. Many other PoS projects clone the code of the PIVX project to create their own customizations. A Zero-coin protocol allows for creating “anonymous” coins that make tracking of spending much more complicated or practically impossible. A process called “Zerocash protocol” explains in detail how anonymous “zero” coins are minted. There are two types of zero-coin transactions:

  1. Minting new zero coins with fixed nominal values (1, 5, 10, etc.) and burning an equivalent amount of “regular” coins
  2. Spending several zero-coins and converting them to “regular” coins as output

Each zero-coin with a fixed value has a pair of “serial” public numbers. Owners of zero-coins have an associated private key used to spend zero-coins, and any participating node could check spending transactions.

On March 15, 2019, the PIVX developers published an article that a successful attack against the PIVX Zerocash protocol was discovered, and the codebase was updated to fix it. The attacks became possible due to an exploitation of the vulnerable BigNum class that truncated the calculated result and used the lowest 256 bits of the computed number ignoring the rest. The threat actor discovered this flaw and exploited it by creating many fake “serials” with the same low 256 bits. The vulnerable code accepted those “serials” as valid. The threat actor made 568,897 PIV coins (approximately $438,000 at the time) from thin air. See the vulnerable code:

The first invalid zero-coin “serial” was spent on March 2, 2019:

https://explorer.pivx.link/tx/2537e84a54e4bf8dae16f8ca6baf7137a85e4257c97e6987eb56db14ef4ea3b8

But this “serial” was already spent on March 1, 2019:

https://explorer.pivx.link/tx/caf7ee443214b4fb3162cd753b1faa35fce7c42c7520b825246d6968d0ddff34

To address the discovered vulnerability, the PIVX team fixed the code, created additional RPC functionality to introspect zero-coin transactions, and added functional tests to the codebase to test that the new code is not vulnerable to “serials” double-spending.

PoS “crystall ball” vulnerability

This is the most interesting part of the exploit, in my opinion, and in contrast to published vulnerabilities “Fake stake” and “Wrapped serials”, none of the other research articles have covered this fundamental vulnerability in the PIVX PoS consensus algorithm.

Let’s take a look at the PIVX code repository and committed code changes in 2019. There is one commit called “Stake modifier V2”:

The code was committed on Aug 24, 2019, introducing a relatively small change that does nothing important at first glance:

This code in the wallet.cpp is part of the method CreateCoinStake that enumerates all UTXO candidates for staking coins in the wallet. For each UTXO, it calculates its staking hash and compares it to the current hash target according to the expected difficulty of the blockchain. The only difference in the new code that we can see is that now it takes into account the index of the current (the latest) block. But why? Let’s dig into the code:

We can see that starting from the selected block height, the code uses a new “Stake modifier.” But first of all, what is the “Stake modifier”? It was introduced in the PeerCoin project to make the calculated staking hash not predictable. To calculate the staking hash, we need to consider attributes of a stake UTXO: the time of creation, the block where it was introduced, and its hash. These attributes won’t change; they are fixed. Another attribute used for calculating the hash is the time of the new block. This chosen time is variable so the pseudo-random attribute was added to solve the stake modifier problem. It is calculated based on 64 blocks using a pretty complex algorithm implemented by the ComputeNextStakeModifier method. But the original implementation of the process has a severe flaw: those blocks are selected before creating the candidate UTXO. It means that whenever we would like to evaluate the candidate UTXO, we can do it in advance regardless of how far it is in the future.

The new code fixes the vulnerability by replacing the “stake modifier” by a hash of the previous block:

Since it is impossible to predict the future block hashes, it adds required randomness to the calculation of the staking hash.

Possible exploitation of the vulnerability

There is a potential scenario on how to exploit this vulnerability: as soon as a wallet has several staking UTXO, a threat actor embeds a “miner” code that evaluates each staking candidate’s chances to stake sometime soon (in a few hours or days). If some staking candidates don’t stake soon, the threat actor may spend those coins themselves and create a new set of staking candidates and repeat the process. This is analogous to putting random bets in a casino, receiving information of which bets will win, and then removing the bets that don’t. Eventually, such a wallet will contain only UTXO that will stake very soon, and after the actual staking, the process will be repeated. Let’s try to find suspicious transactions in the PIVX blockchain explorer. Here is one of the possible candidates:

PIVX Explorer (zkbitcoin.com)

This does not look like a typical transaction since it takes funds from many addresses (about 30) and then splits funds amongst another set of addresses with equal value. The involved addresses exhibit similar activity by scattering funds across other addresses and staking after a short period of time.

Summary

Proof-of-Stake cryptocurrency projects have had several vulnerabilities that impacted them, and we can see that at least one was caused by a fundamental flaw in its lack of randomness. The PIVX vulnerability looks like it has been exploited in the past, but it is hard to estimate its financial impact. Eventually, the vulnerability was fixed. Unfortunately, developers decided not to publish any information about the exposure but rather fix it silently.

Resources

PeerCoin Project: https://www.peercoin.net/
History of Proof-of-Stake: https://www.gemini.com/cryptopedia/proof-of-stake-delegated-pos-dpos#section-history-of-po-s
Nothing-at-stake problem: https://golden.com/wiki/Nothing-at-stake_problem
PIVX “wrapped serials attack”: https://medium.com/@dev.pivx/report-wrapped-serials-attack-5f4bf7b51701
Sybil attack explained: https://academy.binance.com/en/articles/sybil-attacks-explained
Zerocoin project: http://zerocoin.org/
Zerocash protocol: http://zerocash-project.org/how_zerocash_works.html

Leave a comment