Is VERGE fixed? Or how to hack VERGE again and get more than $2M USD only with CPU.

LINC
19 min readJun 5, 2018

--

Disclaimer: A rough draft of this article was written right after the second attack on Verge network has been carried out, and during all this time I have doubts about publishing it. But since the problem described in this article increasingly started to be raised publicly, I finally decided to publish it, only adding some updated information and bringing it to the readable form.

Upd. 06/06/18: Verge team swiftly got in touch with me to inform that they’re working on moving to the new codebase, and the issues detailed in the article have been considered and certainly will be fixed. Hoping it gets released ASAP.

Introduction

Last two months, Verge had become a subject of close attention of many members of cryptocurrency community. However and unfortunately, that’s caused by some troublesome events — the Verge network has been attacked, more than once, at interval of less than two months. So, what happened and how come that a cryptocurrency, which is in Top 50 by 24h trade volume (around 10m$), has been attacked twice and almost identically? And the main question, whether the Verge developers protected their network and fixed the issue, or a third attack is still possible?

Timeline

Let’s go over the key timestamps and recover the chronology of the attacks on Verge.

The first attack has been registered on Apr 4th. The circumstances of this attack are well-known and sufficiently detailed in many sources (first and foremost, on Bitcointalk forum by ocminer, the owner of Suprnova pool). Attacker was able to mine a huge amount of blocks within a short period of time by exploiting a range of vulnerabilities in Verge code. Blocks were mined at intervals of just one second per block, along with it, the difficulty of each block was as minimal as possible.

Actually, there were two attacks. First attack started at block 2.007.364 and it looked more like a trial run, since it was interrupted at block 2.009.911, and then attacker was still continued to mine blocks, but with no exploit. Of course, other miners joined at once, and the difficulty was swiftly increased. But the attack has been continued, starting again from the block 2.011.409, and this time it lasted much longer, until block 2.026.085.

A total amount of more than 26 millions XVG coins were mined by the attacker, and at their current price as of writing this, that was over $1m USD.

Verge developers reacted to this attack with chaotic attempts to quickly fix the issue, however that caused an unintentional fork of the chain.

https://github.com/Vergecurrency/Verge/commit/7294e062a61f78ffb05689b562f90985463d1179
https://github.com/Vergecurrency/Verge/commit/b6c380727ebe285538b9e5ac330176d9e8983f87

Here we need to take an aside and point out, that Verge uses a multi-algo PoW. Its mining cycles go through Scrypt, Lyra2Rev2, Blake2s, Groestl and X17 algorithms. By design, a multi-algorithm PoW should guarantee the decentralization of the blockchain and avoid a monopolization of a coin by mining pools, and thereby significantly reduce a possibility of carrying out the 51% attack.

However, there’s no any check in the Verge code, that forces the use all the 5 algorithms. Besides, one and the same algo may be used, hence the attacker took advantage of this flaw to make an attack much easier.

In their next fix, Verge developers closed this critical vulnerability, by setting the limit for a maximum amount of blocks mined with the same algorithm to 6 blocks.

https://github.com/Vergecurrency/Verge/commit/80c81aef63272231fc39c2af4b8db9f3f2e9d328

By the way, the limit value is actually not 5 as it’s defined in SAME_ALGO_MAX_COUNT constant, but 6, since the check is starting from a previous block and ignoring the current one. Hard to say, if that is an intentional behavior, but anyway that’s not so critical.

More important is that this fix, although it’s quite important, doesn’t fix at all the root cause of the attack issue.

With the next step, the ClockDrift constant has been returned to its initial value, probably with intention to resolve the issue of a chain fork.

https://github.com/Vergecurrency/Verge/commit/2b6faff66ecfd8b9361aa5db14ffa5019b784f4f

Despite all the ambiguity of this parameter as well as chaotic attempts to adjust it, the decision to return it to the initial value was fatal, along with the fact that the root case of the attack issue wasn’t determined. Within less than two months, the attack was repeated again.

On May 22th, at block 2.155.843, the second attack began and continued until block 2.205.870 during a 5 hour span. This attack was much more prepared and extensive, during which an amount of 50.000 blocks and 36.5 millions of XVG coins were mined. That was over $1.5m USD at the current price, and almost $2m USD at the moment of the attack.

It is noteworthy that this attack was almost identical to the previous one, with the only difference — instead of one algorithm (Scrypt) the attacker used two (Scrypt and Lyra2Rev2) algorithms, rotating them one by one. Thus, the last fix just made the attack a bit more complicated but still, it didn’t fix the root cause.

This time, as a fix, developers initiated a planned hard fork of the chain at block 2.158.500, to limit a ClockDrift value to 10 minutes.

https://github.com/Vergecurrency/Verge/commit/f8ca082646f9d98f5856e341097807ba06268464

As the developers declared, the flaw is fixed and the network is not vulnerable anymore. But is that true? Let’s see…

Difficulty adjustment in Verge

A little bit of theory now.

Verge is a PoW coin, that uses DGW difficulty retargeting algorithm. What is DGW?

DGW (Dark Gravity Wave) was for the first time announced in 2014 by the main Dash developer Evan Duffield, and it was declared as an improved version of KGW (Kimoto Gravity Well) algorithm. In concept, DGW is similar to KGW, adjusting the difficulty levels every block by using statistical data of the last blocks found. In this way block issuing times can remain consistent, despite high fluctuations in hashpower. According to the developer, “DGW uses multiple exponential moving averages and a simple moving average to smoothly adjust the difficulty. This implementation is far more simplistic and better suited to adjust difficulty than KGW and also fixes all known exploits.”

Basically, DGW formula can be represented as:

where:
Dnext — required next target
Dk — difficulty of previous k block
Tk — timestamp of last k block
N — blocktime
n — past blocks count (12 in Verge, 24 in Dash)

In the first step, the average difficulty of last 12 blocks is calculated, then on the second step, it’s multiplied to the proportion of an actual timespan (which is limited by minimal value of target timespan/3 and maximal value of target timespan*3) and target timespan.

The implementation of this algorithm in Verge is almost the same as the original. There’s a difference in the amount of past blocks, and the mining algorithm of the current block is considering as well.

DGW algorithm is declared as resistant to time-warp attack. Unfortunately, regarding to this attack such a claim has now been disproven.

The starting

Let’s take a look at the very beginning of the attack.
It was started from two blocks, 2.155.843 and 2.155.844.
We should take a special look at the timestamps of these blocks.

As we can see, one block goes «to the future» for 90 minutes.

The interval of 90 minutes isn’t random.

In Verge, blocktime for each algorithm is 150 seconds. When difficulty is retargeting, 12 last blocks are considered, thus the value of target timespan is equal to:

90 minutes are the same as 5400 seconds, which in turn equals to target timespan * 3. If we take a look above, at the description of DGW, we can see that this exact value is the upper limit of actual timespan value, and that exact interval causes a highest difficulty drop. In addition, this value doesn’t exceed the ClockDrift value, which is set to 2 hours.

Let’s take a look at the next timestamps.

It’s easy to notice a some sequence, which is repeating each 11 blocks, and can be conditionally described as:

where B = A + 5400, and where each next value of A and B is incremented by one.

This sequence is required to pass the check for MTP (Median Time Past). This check compares a median of last 11 blocks with a current timestamp. It’s important that timestamp of group B should never be selected as median when comparing with the current timestamp of group A (obviously, A is less then B and check will fail). But it is with such sequence, that a stack of timestamps of last 11 blocks always contains more than 6 timestamps of group A, thus the median is always a timestamp of group A.

Let’s take a look at the graph of timestamps and medians of first 400 blocks since the beginning of the attack:

As we can see, despite the fluctuation of up to 5400 seconds, block timestamp is never exceeding the value of median timepast.

(Some small gaps and interruptions are probably the cause of testing and adjusting of some parameters by the attacker. The follow-up change of the timestamp sequence is also pointing to that. It seems that the attacker matched the best parameters directly in the process of mining.)

Notably, the different sequences are used on different time. Thus, such a sequence has been used during the first attack:

And it’s changed to simplest (and fastest) during the second attack starting from the block 2.156.223:

But the same result is always achieved.

Graph of timestamps and medians for the “B A A” sequence.

Let’s return to the interval between timestamps of A and B groups. As it has been mentioned above, an interval of 5400 seconds causes a highest drop of the difficulty.

Logarithmic difficulty decrease chart

Thus, even though this interval wasn’t seen at each step, and the difficulty periodically sought to the highest value (which is caused by the negative value of Timespan), the lowest difficulty has been reached at block 1467 so far just in 75 conditional minutes for Lyra2Rev2 algorithm and at block 1785 in 77 minutes for Scrypt algorithm.

The follow-up blocks were mined with the same timestamp sequence, but already on the lowest difficulty with some small fluctuations.

As for the forced rotation of algorithms, the attacker used a quite simple solution. The alignment was made starting from the first block, that is, the sequence of the algorithms was like that until block 2.155.560:

The next sequence is quite obvious — a maximum amount of blocks for the same algorithm is just following each other:

The key problem

It’s obvious that the forced change of mining algorithms doesn’t fix at all the issue for the attack. So, the cause is in the difficulty retargeting algorithm? And any coin that use this algorithm, can become a victim of the same attack? Not so easy!

Certainly, DGW is inconsistent with declared specifications since it doesn’t protect from a time-warp attack. It’s a quite serious problem, but still this is not the only key to the successful attack.

To understand the root cause, let us return again to some theory.

Let’s imagine a situation. There are two conditional parts of world, that are jointly mining the Bitcoin. But suddenly, for whatever reason, the first part disconnects from the public network, loses the connection with the second part, and both of them become isolated from each other. As the result, each part of world now has its own fork of the chain. After some time, the first part connects to the public network and becomes accessible. The nodes are starting to synchronize and the conflict of the chains occurs. Of course, both of these chains are valid and meet the consensus rules. So how to resolve this conflict?

In the very early versions of Bitcoin such conflict was resolved through a comparison of height of chains. The network switches to the chain that has the highest height, and the other chain is marked as a fork and all its blocks become orphaned. It’s quite obvious that this method is very insecure, vulnerable and easy to be unfairly exploited.

Suddenly after determining the problem, the new procedure of choosing the best chain was developed. It’s using a so-called Chainwork — a value that equals to the sum of hash works of all blocks in the chain. Thus, now the best chain is a chain that has the highest total hash work, regardless of its height. This method, as the most correct and secure, is accepted as the standard and is used in all PoW networks.

In 2012, a coin with a distinctive feature of new type of achieving consensus was developed. Its name is Peercoin and the new type is called Proof-of-Stake.

In Proof-of-Stake-based networks, the creator of the next block is chosen via various combinations of random selection and wealth or age (i.e., the stake), and unlike PoW coins, are more energy efficient.

As a solution to the problem of selecting the best chain, the ChainTrust parameter was implemented, which also contains the sum of difficulties of all blocks in the chain, but here the difficulty doesn’t mean the amount of hash work, though it sets on the basis of a term, during which a block forger is storing the coins in active phase to receive stake reward.

Verge was started to be developed in 2014, and one of codebases that was used as a basis, is Peercoin. Despite Verge is declared as PoW coin, it has an integrated PoS system, although it’s disabled for now.

But there is a really important thing that developers haven’t considered while porting a Peercoin codebase. Even if PoS is disabled at this moment, the PoS procedure of selecting the best chain is used, so chains are compared by their ChainTrust values.

https://github.com/Vergecurrency/Verge/blob/f8ca082646f9d98f5856e341097807ba06268464/src/main.cpp#L1973
https://github.com/Vergecurrency/Verge/blob/f8ca082646f9d98f5856e341097807ba06268464/src/main.cpp#L2145
https://github.com/Vergecurrency/Verge/blob/f8ca082646f9d98f5856e341097807ba06268464/src/main.h#L1389

The big problem is that Verge is a full PoW coin, and the ChainTrust parameter is meaningless. Besides, in the Verge implementation, ChainTrust equals just to the Height-1, since the BlockTrust value for each block always sets to 1! Therefore, the best chain is always the chain with the highest height!

And this is a main problem of Verge network!

No other PoW coin with ChainWork check can be affected by this kind of attack.

If we suppose that the current network difficulty is just 250 (BTW Verge network difficulty for each algorithm is ten times higher now), then to disconnect only 1 block mined with this difficulty, we need to mine more than 1.000.000 blocks with the lowest possible difficulty!

Yes, time-warp issue is still the important problem, since it allows to make more than 100x profit even if chainwork is calculated. But then an attacker still has to compete with total network hash rate, so this would be a pure 51% attack.

But the absence of Chainwork check is exactly what made the attack on Verge such a magnitude and easy to be carried out.

Is that a 51% attack?

No, this is not 51% attack.
At least, it doesn’t require to have such power.

It should be understood, that all the timestamps in the blocks mined by the attacker are bogus and false, and are totally unrelated to the real time of block discovering. Thus, since there are no limits by time, when a fork could be met, an attacker can mine his private fork as long as needed. In other words, there is no need to have a power comparable to the total hashrate of the network, to find the first blocks in blocktime period, when the difficulty is still high. If an attacker has only 10% of the network that means that a block will be mined not in 150 seconds in average, but in 1500 seconds. And having an advantage by exploiting time-warp vulnerability, therefore having more than two weeks to spare (for 50.000 blocks), allows having even 1% of total network hashrate to find a small amount of blocks with high difficulty in a short period of time.

Then, an attacker just needs to connect his node to the public network and start to see how all the nodes are switching to the new malicious chain.

But what is interesting is that the attacker even did not attempted to hide the chain and had enough power to start the attack in real-time.

And it’s quite possible that initially the first blocks were mined with a some delay, therefore they were marked as orphaned by other miners. But the attacker continued to mine his chain, and when the difficulty was drop, the speed of mining was significantly increased, the chain became longer, therefore, was selected as the best.

And in this, the attacker even didn’t care about another miners that could compete in block mining with such low difficulty, and it’s quite easy to explain why. There are both vulnerabilities that made it possible to ignore other miners — the possibility of time-warp attack and the absence of chainwork check as well.

Of course, honest miners tried to connect to the chain and continue to mine, but with each new fairly mined block the difficulty was increasing, therefore the block time was increasing as well, and after some period of time the chain became less longer than the attacker’s chain, that continued to have a lowest difficulty. After receiving a new portion of blocks mined by the attacker, a mining pool disconnected his shorter chain, and started to mine from the new point, and this process was repeated over and over again producing many orphaned blocks mined by the pools.

Of course, this would not be possible if the chainwork check is integrated. Just a small amount of fairly mined blocks would have a chainwork larger than a hundreds and thousands of blocks mined by the attacker, so all these blocks would become orphaned, and the attack would be interrupted.

So after all, is Verge still vulnerable or not?

Yes! And it’s extremely easy to hack it again!

Let’s look at few ways how it could be made.

CPU mining (sorry mate, you’re late)

Actually the easiest way to hack Verge again becomes unavailable almost a week ago. But still it should be described.

So, we have an opportunity to start the mining of our private chain from any block in the Verge blockchain (until the last checkpoint).

So let’s take an advantage of what was done before by the previous attacker, and take for example a block 2.158.500. It’s just a random block in the range of mined blocks during the second attack. Its difficulty is lowest, as well as its predecessors have. All we need now is just to launch a CPU mining starting from this block, repeating the same sequence that was used during the last attack. Therefore, we reach the hard-fork block pretty fast, where the ClockDrift value that is set to 10 minutes and doesn’t allow us to continue current sequence of timestamps (since 600 sec are less than a minimal value of actual timespan required to lower the difficulty).

If we can’t continue to mine low-difficulty blocks on the high speed, we still may try to just save the current lowest difficulty. We are already ahead of the public chain, so we have a lead time for a leeway.

Based on the description of DGW, it’s obvious that the proportion of actual timespan and target timespan should equal or be more than 1 to save the lowest difficulty.

An envelope calculation shows that we need the interval of 164 seconds.

Moreover, since the blocks mined with different algorithms don’t overlap, they can be forged at the same time.

But to make it we need a sequence like that:

So we need to align it by using the next sequence:

And that’s all! Despite our chain is much slower than public chain (2 blocks in 164 seconds instead of 5 block in 150 seconds), we still have a time gained in the result of possibility of carrying out the time-warp attack until the hard-fork block.

The possible side-effect of this attack is a quite long synchronization and slow process of switching to the new chain, since all orphaned blocks need to be disconnected and transactions need to be returned to the memory pool.

The consequences of this attack are indeed much fatal, since the whole weekly history of blockchain would be rewritten, unlike previous attacks, where the most of mined blocks were completely new.

But anyway, at the moment of publication of this article, time is over and last chance to carry out this attack was around midnight of May 31.

But let’s add one more algorithm.

It’s impossible to carry out the attack described above, but we still may add a third algorithm in the sequence, and lower its difficulty. As was mentioned above, to reach the lowest difficulty as soon as possible, the next condition should be met:

It’s easy to achieve that by setting the block time interval to 491 seconds:

So now we just need to insert the extra blocks with third algorithm to our sequence, complying with the interval of 491 seconds.

Logarithmic difficulty decrease chart

As we can see, the difficulty is lowering very fast, and only 70–100 blocks are sufficient to reach the lowest value.

Now we have more lead time until the chains aren’t equal by heights, but still the critical point occurs tomorrow (on June 6th) at around 6:00 UTC.

Actually, this attack is still doesn’t require to have own rigs, a rented powers could be used when the time of difficult block is came, and CPU mining is still can be used for the rest of time.

We have more algorithms, let’s add another one.

It’s the same as previous, the difference is that the critical point occurs on June 25th, so there is a high risk of this attack.

And finally, all the algorithms are used.

Since the average real block time is in range of 33–35 seconds, and the block time in private chain is 33 seconds, it’s a very small chance that the public chain can become longer than private chain. So there’s no limits when the attack can be carried out.

Double spend attack

All attacking vectors described above could be supplemented by double spend attack, since all blocks affected by the attack will be “rewritten”. So we still can intentionally include/exclude some transactions.

Besides, since it’s enough just to go ahead of the public chain, the double spend attack can be performed at any point of the blockchain (until checkpoint), and it’s still enough to use only two of the mining algorithms.

Conclusion

Verge is extremely vulnerable and immediate fixes are required!

What should be fixed at first:

1) As just a quick “fix”, adding a checkpoint on the hard-fork block, then the first 4 attacking methods will become irrelevant.
2) A hard-fork with the implementation of Chainwork check.
3) Switching to more secure difficulty adjustment algorithm, which is not vulnerable to time-warp attack. Actually it’s just enough to use MTP instead of pure block timestamps when calculating actual timespan.
4) Finally, leave alone the clock drift value.

Just a few things that are the basic principles of any blockchain network are needed to ensure the security of the network. Until that, the risk of a new attack is extremely high, and the impact will be much serious than it was during two previous attacks.

LINC Aequilibrium

We, LINC team, take our responsibility to protect our network and to ensure the integrity of the blockchain very seriously. That’s why our goal and current main task is an implementation of the Aequilibrium concept, which is committed to significantly reduce the possibility of carrying out the 51% attack and all the relevant attacks.

We are still working on its improvement and adjustment, but now we’re ready to present its guiding principles:

— Verification of miners. A forger can make a request to the validator and/or governance system to become a verified forger. Therefore, subject to certain technical conditions, and to the successful vote through the decentralized governance system, a forger could be added to the whitelist and avoid some restrictions and penalties in mining.

— Same forger penalty, along with the previous point, almost excludes the possibility to mine the private chain with intention to replace the public one. In addition it forces the mining resources to be evenly distributed among different pools, thereby avoiding a concentration of a huge amount of hash power in one pool.

— Since LINC is using the same algo as Dash and Verge as well (DGW), switching to another difficulty retarget algorithm is planned. We’re still considering and testing some of open-source algorithms, as well as working on our own solutions.

If you haven’t already, join our community in Discord where you’ll get updates on the project’s developments.

Bob,
LINC Executive

--

--