Welcome back. Regular readers of our blog know that we usually try to analyse the vulnerabilities very thoroughly which allows us to code functional exploits. Then we execute the exploits in our isolated environment where we run an instance of a mainnet-like network of the project we analyse. We do that because we know that unless we have a working exploit that has been tested in an environment that is functionally equivalent to a project's mainnet, the analysed vulnerability might be just imagined. This is because the code bases of nearly all blockchain projects are so huge that it is practically impossible to analyse them completely. Therefore when one sees a potential vulnerability in one part of code, it often happens that the problem is not there because there is another part of the code, that one is not aware of, that prevents exploitation.
Today, however, we make an exception to our usual process. Today, we present two vulnerabilities that we have not tested in our local environment. In case of Verge, this means that the vulnerability might not exist, but we strongly believe it does. And in case of Lisk, the whole thing is just absurd as you can read below. In both cases, there is just no incentive for us to spend any more time analysing the project in question. You will see why that is the case if you continue reading.
51% Attack On Verge Using One Algorithm Dominance
Bug type: 51% attack
Bug severity: 8/10
First, let us explain why we don't see any incentive in actually verifying this bug properly or analysing Verge further. Shortly after we started our examination of its code base, we got the idea of this attack. We also learned that Verge was already hacked multiple times not so long ago. And actually the hacks were based on exactly the same idea as our attack – to get the majority hash rate of just one algorithm out of the available five algorithms that are used to produce blocks in Verge, and using a clever construction of blocks, to achieve the dominance over the whole chain. Our finding of previous similar incidents made us suspicious that maybe the development team behind Verge is not very interested in the security of their product. And if that was the case, it would mean there is no business for us. So we went directly to contact the developers and ask them if they have any bug bounties implemented in their project. The response, unfortunately, confirmed that the only way how to make money here would be to exploit the mainnet, which we do not do. Verge's approach to the security of their product very much goes along the dysfunctional model of NavCoin (see our earlier blog posts) – i.e. it is a community effort to make the product secure, but the developers are not competent to do so.
If we are not mistaken with the analysis below (which is possible as this is untested attack as explained above), Verge is just waiting to be hacked once again.
Attacker cost: medium
The attacker obtains majority of the hash power on one of the five PoW algorithms in Verge. With proper selection of the algorithm and careful construction of blocks the attacker is able to produce the heaviest chain and thus control the network entirely, which allows the attacker to perform additional attacks such as double spending.
Because this is not a full and proper report, we will not go into all details. We will just describe the pillars of the attack as we envisioned it. Verge is a fork of Bitcoin, in which the SHA256d PoW algorithm is replaced with a set of 5 PoW algorithms, namely Scrypt, Myriad-Groestl, Lyra2REv2, Blake2S, and X17. The related claim (in their Blackpaper) is that this "results in increased security due to a wider range of people and devices that can mine Verge."
The history of this project disproved this claim.
Couple of things are important here. The algorithms were initially independent and so it was possible to mine any number of consecutive blocks using just one algorithm. Also, the difficulty of each algorithm is calculated separately. The first property was modified in this commit after the coin was hacked. After this change, it is no longer considered valid if a chain contains more than five blocks mined with the same PoW algorithm in any series of 10 consecutive blocks (see hasUsedValidMiningAlgorithm() in the commit above). Therefore AACADEAAEA is no longer a valid subchain, because algorithm A is used more than 5 times in 10 blocks. However, ABABABABABABABABABA is perfectly valid.
Such an alternating series is what we use in our attack. It implies that the attacker needs to be able to mine blocks using two algorithms, not just one. How is it then that we claim that the attack is possible when the attacker has a majority of the hash rate on just one algorithm? This is because the difficulties are independent. Therefore let us assume that the attacker has the majority of the hash rate on algorithm A. Then the attacker only needs arbitrary nontrivial amount of hash rate on algorithm B. At first, the attacker will only be able to produce blocks with algorithm B rarely, but that will cause the difficulty on B to go down quickly. Once the B's difficulty is lowered enough, the attacker will be able to produce B blocks at a normal rate. Even just 1% of the total hash rate on B is enough for the attacker to eventually be able to produce the alternating chain ABAB... with a normal rate. Of course that the more hash rate the attacker obtains for B, the faster the attack is going to be.
What remains to be shown is how such an alternating chain can be better than the naturally created chain of the honest part of the network. This is because of unequal contribution of each algorithm towards the total chain work. Verge does contain a balancing method that is supposed to mitigate this issue, but it has been implemented long time ago and today's distribution of the hashing power does not correspond to the initial implementation.
At the time of writing, the individual contributions to total chain work of each algorithm for a single block were roughly as follows:
- Scrypt – 0x0000 5000 0000 0000 0000;
- Myriad-Groestl – 0x0000 a000 0000 0000 0000;
- Lyra2REv2 – 0x000f 8000 0000 0000 0000;
- Blake2S – 0x0000 4000 0000 0000 0000;
- X17 – 0x0021 0000 0000 0000 0000.
Note that these are values after the balancing. The most powerful algorithm is thus X17 and the second most powerful is Lyra2REv2. The values above means that a single X17 block is weighted as more than 16 Lyra2REv2 blocks. And every Lyra2REv2 block is weighted as about 24 Myriad-Groestl blocks, which are third most powerful.
Of course, these values are valid for one moment in time and the difficulties of all five algorithm fluctuate heavily, but the attacker does not need them to be valid in long term. If the values are somewhat stable for a reasonable period of time (Binance requires 120 confirmations), the attack should be viable. Moreover, even if the values change dramatically and different algorithm will become heaviest, the attacker just selects the best algorithm at the time of her attack. In case there is no algorithm significantly better than others at some point, the attacker just waits until one is weighted significantly higher.
Stealing Money From Uninitialized Lisk Accounts With 64 Bits Of Work
Bug type: money theft
Bug severity: 9/10
In case of Lisk, we also started our analysis at one point and very quickly we decided to stop. What happened? We found out something that is probably immediately obvious to everyone working with Lisk – their account addresses are very short compared to other projects. So we focused on that and we found out something very disturbing. There is a critical vulnerability in the very design of the Lisk account system, and it has been known for years, and as far as we know, it still has not been fixed yet. Therefore we can't see an incentive to analyse this project because it's developers seem to be OK with critical vulnerabilities in the system.
Attacker cost: very high
The attacker identifies an uninitialised account and then performs 64-bit of work to calculate a private key that can be used to move funds from the target account.
Since this vulnerability is known for very long time, we do not need to describe it ourselves. You can just read the full analysis by Kudelski Security from January 2018.
Notably, the mentioned account 1082640123928843793L is still uninitialised today and still contains over 1.6 million LSK. Of course, with today's prize of LSK, this is just about 2 million USD. But in the past, the incentive was much greater, LSK often traded for 10x today's price in USD and sometimes even at more than 20x. So today, creating a special hardware to exploit this vulnerability might be very risky, but in the past it was not so risky. The only reason why it has not been exploited yet is probably the fear of chain rollback/hardfork by centralized authority of the development team, just like it happened with the famous Ethereum DAO hack.