In 2008, Satoshi Nakamoto proposed an electronic cash system (Bitcoin) fully realized through peer-to-peer technology. The core value of this scheme is that it proposes a proof-of-work-based solution that enables the cash system to operate in a peer-to-peer environment and can prevent double-spending attacks. Now that Bitcoin has been born for ten years, and countless digital currencies have been born accordingly, the discussion of double-spending attacks still seems to be stuck on Bitcoin’s 51% attack. In fact, our research found that there are many other forms of practical digital currency double-spending attacks. In this article, by introducing the multiple double-spend attack vulnerabilities that we discovered against EOS, NEO and other large public chain platforms, we summarize a variety of reasons for the double-spend attack of digital currency, and propose an efficient mitigation measure.
1. Proof of Work and Double Spend Attacks
In 2008, Satoshi Nakamoto proposed an electronic cash system fully realized through peer-to-peer technology, which enables online payment to be initiated directly by one party and paid to another party without going through any financial institution in the middle. Although digital signatures partially solve this problem, if the support of a third party is still required to prevent double-spending, then the system loses its value. The essence of Bitcoin's proof-of-work (PoW) mechanism is to make the cash system operate in a peer-to-peer environment and prevent double-spending attacks.
The principle of the proof-of-work mechanism is as follows: each block in the network contains the transaction in the current network and the block header hash of the previous block. When a new block is generated, its block header hash must satisfy the proof-of-work condition (a large number of hash calculations are required). The entire network connects hash chains that satisfy proof-of-work to form a blockchain. The resulting transaction record will not be altered until the attacker redoes the full proof-of-work. The longest blockchain will not only serve as proof of the observed sequence of transactions, but also as the consensus from the group with the most computing power. As long as most of the computing power in the entire network does not intend to cooperate to attack the entire network, honest nodes will generate the longest chain that exceeds the attacker, thus achieving resistance to double-spending attacks.
A double spend attack is actually a result. If an attacker A pays the same bitcoin to both users B and C at the same time, and both users B and C approve the transaction. Then we say that A spends the bitcoin twice, and A achieves a double-spend attack. Among the double-spend attacks against the proof-of-work mechanism, the 51% attack is the most discussed form of attack. However, there are actually many forms of double-spend attacks against the proof-of-work mechanism, including Fanny attacks, competition attacks, and Vector76 attacks. These attacks have actually received sufficient attention and discussion, and will not be repeated in this article. In fact, there are many other forms of practical digital currency double-spending attacks. In the following, we will discuss the various reasons for the double-spending attack of various digital currencies through the multiple security vulnerabilities we have discovered, and propose an efficient mitigation measure.
2. New classification of double-spend attack
The smart contract platform is essentially to share a ledger across the entire network. This can be seen as a distributed state machine replication problem. The current ledger state, we can think of as State_n. When a new transaction Tx_ is generated, Tx_ will have an effect on State_n. Thereby, the State_n state transitions to the State_ state. We can express this process with the formula: State_n × Tx_{n+1} → State_{n+1}
The consensus mechanism of the smart contract platform is essentially to convert all transactions [Tx_1 Tx_2  …. Tx_n] acts on the initial State_0 in sequence, so that the entire network always maintains the same state. Each block in the blockchain will actually be a sequence of transactions [Tx_1 Tx_2  …. Tx_n] is divided into different blocks Block1, Block2 in sequence and linked in sequence. In the process of replicating the state machine of the whole network, if the state of the whole network is inconsistent for some reason, we can think that a fork has occurred in the whole network. Forks are exploited by attackers to further achieve double-spending attacks.
In this article, we divide the double-spend exploits we found into 3 categories:
· Double-spend attack caused by lax validation.
· Double-spend attack caused by inconsistent execution of state machine State_n × Tx_{n+1}→State_{n+1}.
· Double-spend attack caused by consensus mechanism.
The main reason for the double-spending attack caused by lax verification is the specific implementation of logic verification. Bitcoin's vulnerability CVE-2018-17144 is actually one such vulnerability.
The double-spend attack caused by the inconsistent execution of the state machine is mainly due to the inconsistent direct results of the smart contract virtual machine due to various reasons, thereby creating a fork in the entire network, resulting in a double-spend attack.
Vulnerabilities in the consensus mechanism may result in forks of the entire network, further causing double-spending attacks. The 51% attack that people often say is actually a fork vulnerability of the PoW consensus mechanism.
3. Double-spend attack caused by lax verification
The main reason for the double-spending attack caused by lax verification is the specific implementation of logic verification. Here we introduce two loopholes in which the verification is not strict when the block is bound to the transaction, resulting in a double-spend attack.
In the blockchain project, a transaction Tx_1 is packaged in a block Block_1 as follows: first calculate the hash value Hash_1 of the transaction Tx_1, and then combine Hash_1 with the hash values ​​of other transactions Hash_2...Hash_n to form Merkle Hash Tree. Calculate the root node root of the hash tree, and then pack the root into Block_1. This forms a binding between a transaction and a block. Generally speaking, unless an attacker can break the collision resistance of the hash function, it is impossible to break the binding of a transaction to a block. If the attacker can package the binding of the transaction and the block, the attacker can achieve a double-spend attack by causing a fork of the entire network. Below we introduce two double-spend exploits we discovered on NEO:
3.1 NEO virtual machine GeTInvocaTIonScript double-spend attack vulnerability:
In a blockchain project, a transaction is generally composed of an unsigned part (UnsignedTx, the content of the transaction to be executed) and a signed part (the witness of the transaction). In a blockchain project such as Bitcoin, the hash calculation of a transaction actually includes the signature part of the transaction. In various blockchain platforms such as NEO and ONT, the transaction calculation formula is hash=SHA256 (UnsignedTx). That is, the hash of the transaction is calculated from the unsigned part, regardless of the witness of the transaction. When the NEO smart contract is executed, it can obtain the witnesses of the transaction from a transaction through the TransacTIon_GetWitnesses method. Its specific implementation is as follows:
After a contract transaction obtains its own witness, the verification script in the witness can also be obtained through the Witness_GetVerificaTIonScript method. If an attacker targets the same unsigned transaction UnsignedTx1, two different verification scripts can be constructed. It can cause inconsistency in the execution of the contract. Under normal circumstances, the VerificationScript of the contract is determined by the input and other information of the contract, and attackers cannot construct different verification scripts and pass the verification. But we found that in the VerifyWitness method, when VerificationScript.length=0, the system will call EmitAppCall to execute the target script hash.
Therefore, when VerificationScript=0, or when VerificationScript is equal to the target script, the witness verification condition can be satisfied. That is, an attacker can construct two different VerificationScripts for the same unsigned transaction UnsignedTx_1. Attackers can use this property to double-spend all token assets on NEO smart contracts. The specific attack scenarios are as follows:
Step 1: The attacker constructs a smart contract transaction Tx_1 (unsigned content UnsignedTx_1, verification script is VerficationScript_1). In the contract execution of UnsignedTx_1, the contract judges whether its VerficationScript is VerficationScript_1. If VerficationScript_1, choose to send tokens to user A. If VerficationScript is empty, send tokens to user B.
Step 2: Tx_1 is packaged into block Block_1.
Step 3: After receiving Block_1, the attacker replaces Tx_1 with Tx_2 (Tx_1 has the same unsigned content UnsignedTx_1 as Tx_1, but the verification script is empty) to form Block_2. The attacker sends Block_1 to User A and Block_2 to User B.
Step 4: When user A receives Block_1, he finds himself receiving the tokens sent by the attacker. When user B receives Block_2, he also finds himself receiving the tokens sent by the attacker. Double spend attack complete.
It can be seen that the threshold for exploiting this vulnerability is very low, and it can double-spend all token assets on the NEO smart contract. The hazard is very serious.
3.2 NEO MerlkeTree binding bypass causes transaction double-spending attack vulnerability:
The binding of smart contract transactions to blocks is usually done through MerkleTree. If an attacker can bypass this binding, it is possible to double-spend any transaction. Here we look at the implementation of NEO's MerkleTree as follows:
In the MerkleTreeNode function, NEO performs the calculation from the MerkleTree leaf node to the parent node. But there is a problem here, when leaves.length is odd n. NEO's MerkleTree will copy the last leaf node once and add it to the calculation of MerkleTree. That is to say, when n is odd, the MerkleRoot values ​​of the following two sets of transactions will be equal:
ã€Tx_1 Tx_2 …… Tx_n】
[Tx_1 Tx_2 …… Tx_n Tx_] where Tx_= Tx_n
Using this feature, an attacker can achieve a double-spend attack on any NEO asset. The specific attack scenarios are as follows:
Step 1: Assuming a normal legal Block_1, the transaction list contained is [Tx_1 Tx_2 ... Tx_n]. After receiving Block_1, the attacker replaces the transaction list with [Tx_1 Tx_2 ... Tx_n Tx_] to form Block_2. Then publish Block_2 to the network.
Step 2: After an ordinary node receives Block_2, it will verify the validity of Block_2. However because [Tx_1 Tx_2 ... Tx_n Tx_] has the same MerkleRoot as [Tx_1 Tx_2 ... Tx_n]. Therefore, Block_2 can pass the block validity check, thus entering the block persistence process. NEO natively removes normal nodes from validating transactions in legitimate blocks (trusting several consensus nodes). Then the Tx_n transaction can be executed twice by ordinary nodes, and the double-spending attack is executed successfully.
It can be seen that the threshold for exploiting this vulnerability is very low, and double-spending attacks can be performed on all assets on NEO. The hazard is very serious.
4. Inconsistent execution of virtual machines
The consensus mechanism of the smart contract platform is essentially to convert all transactions [Tx_1 Tx_2  …. Tx_n] acts on the initial State_0 in sequence, so that the entire network always maintains the same state. During state machine replication, we require State_n × Tx_èState_ to be deterministic. State_n × Tx_èState_ is essentially the execution process of the smart contract virtual machine on Tx_. If there are design or implementation loopholes in the smart contract virtual machine, the virtual machine will be inconsistently executed (for the same input State_n and Tx_, the output State_ is inconsistent) . Then attackers can use this problem to generate forks and double-spend attacks in the network. Below we introduce the inconsistent execution vulnerabilities of virtual machines that we found on EOS and NEO and their causes.
4.1 EOS virtual machine memory corruption RCE vulnerability:
Previously, we published the article "EOS Node Remote Code Execution Vulnerability --- EOS WASM Contract Function Table Array Out of Bound" (http://blogs.360.cn/post/eos-node-remote-code-execution-vulnerability .html). In this paper, we discovered a memory out-of-bounds write vulnerability in the EOS WASM virtual machine. The exploit program we wrote for this vulnerability can successfully exploit this vulnerability to make the EOS virtual machine execute arbitrary instructions, thereby fully controlling all EOS block-producing and validating nodes .
In essence, it is in the process of State_n × Tx_{n+1} → State_{n+1}. The attacker can make the EOS virtual machine completely deviate from the original execution path, execute arbitrary instructions, and naturally complete the double-spending attack. The attack process is as follows:
Step 1: The attacker constructs a malicious smart contract capable of implementing RCE and publishes the contract to the EOS network.
Step 2: After the EOS super node parses the contract, it triggers the vulnerability and executes arbitrary commands customized by the attacker.
Step 3: The attacker implements a double-spend attack.
The vulnerability of this vulnerability is very serious, and it is the first time that a smart contract platform has been attacked by remote code execution. Readers can read this article for relevant details, which will not be repeated here.
4.2 Double-spending attack caused by uninitialized EOS virtual machine memory:
In the process of writing the exploit program of "EOS Node Remote Code Execution Vulnerability --- EOS WASM Contract Function Table Array Out of Bound", we also exploited an undisclosed memory uninitialization vulnerability in EOS at that time. In memory corruption attacks, memory uninitialized vulnerabilities can often cause further problems such as information leakage, type confusion, etc., which can help us bypass the mitigation measures of modern binary programs such as ASLR and further achieve the attack. However, in the smart contract virtual machine, there is a more direct way of exploiting the memory uninitialized vulnerability, which can directly cause a double-spend attack. The following are details of a memory uninitialization vulnerability we exploited in EOS RCE, which can be used to directly implement a double-spend attack on EOS smart contract tokens.
When the WASM virtual machine requests new memory through the grow_memory pseudocode. In the initial implementation of EOS WASM grow_memory, the requested memory was not cleared. The space of this block of memory is actually random (depending on the memory state of the contract execution machine). Then an attacker can construct a malicious contract to achieve a double-spend attack on any contract asset on EOS. The attack process is as follows:
Step 1: The attacker constructs a malicious smart contract. The contract obtains a new memory address through grow_memory.
Step 2: The contract reads the content of a bit in the address (the bit may be 0 or 1 at this time, depending on the state of the contract execution machine).
Step 3: The contract judges the content of the bit. If it is 1, it will send tokens to user A, and if it is 0, it will send tokens to user B, thereby realizing a double-spending attack.
4.3 Double-spend attack caused by out-of-bounds reading of EOS virtual machine memory:
In traditional memory corruption, memory out-of-bounds read vulnerabilities will mainly lead to information leakage, which will assist us to bypass the mitigation measures of modern binary programs such as ASLR, and further implement the attack together with other vulnerabilities. However, in the smart contract virtual machine, the memory out-of-bounds read vulnerability has a more direct exploit, which can directly cause a double-spend attack. The following is an EOS memory out-of-bounds read vulnerability we discovered, which we can exploit to achieve a double-spend attack.
When EOS WASM translates an offset into the WASM memory address, its bounds checking process is as follows:
Here the type of |ptr| is actually an I32 type, which can be a negative number. Then when: -sizeof(T) < ptr < 0
When ptr+sizeof(T) is a small number that can pass the bounds check. In the addressing later, we see the code: T &base = (T)(getMemoryBaseAddress(mem)+ptr);
The address of |base| will exceed the memory base address of WASM, so that the smart contract can read the memory out of bounds (the content of the read memory address depends on the current execution state of the virtual machine, which can be considered random). An attacker can exploit this vulnerability to achieve a double-spend attack. The attack process is as follows:
Step 1: The attacker constructs a malicious smart contract. The contract uses the memory out-of-bounds read vulnerability to read a bit beyond the WASM memory base address. At this time, the bit may be 0 or 1, depending on the state of the contract execution machine).
Step 2: The contract judges the content of the bit. If it is 1, it will send tokens to user A, and if it is 0, it will send tokens to user B, thereby realizing a double-spending attack.
4.4 Double-spend attack caused by inconsistent implementation of standard functions:
To summarize the essence of the above two examples of double-spend attack, in fact, the EOS contract reads random variables due to some memory leaks during the execution process, which breaks the consistency of the original virtual machine execution and causes double-spend attack. In fact, the inconsistency of contract execution does not necessarily depend entirely on randomness. Here we introduce a double-spend attack caused by inconsistent implementation of standard C functions on various platforms (versions).
In the C language standard definition, the return of the memcmp function is required to be: less than 0, equal to 0, or greater than 0. However, in various C version implementations, the specific return may be different (but still in line with the C standard). Attackers can use the inconsistency implemented by this standard to cause inconsistent execution results of EOS virtual machines running on different systems, thereby achieving double-spending attacks. The attack process is as follows:
Step 1: The attacker constructs a malicious smart contract, calls the memcmp function in the contract, and obtains the return value.
Step 2: At this point, different platforms and versions implement Memcmp with inconsistent return values ​​(even though the binary code of the EOS virtual machine is the same). The malicious contract judges the return value of Memcmp and decides to transfer it to A or B, thus completing the double spend.
The specific fixes for this vulnerability are as follows:
EOS enforces conversion of the return value of memcmp to 0, -1 or 1, thus resisting this inconsistent execution.
The problem of Memcmp is caused by the inconsistency of the implementation of the same standard in the same language. In fact, the same blockchain project often has multiple implementations in different languages. Different languages ​​usually have deviations in the implementation of the same standard. For example, one of the inconsistent implementations we found due to inconsistent implementation of standard definitions is the ECDSA function. The ECDSA signature standard requires that the private key x is not 0. For example, the standard is strictly enforced in multiple cryptography libraries in python and JS, but we found that some golang ECDSA libraries allow private key x=0 to perform signature and verification calculations. Different version implementations of the blockchain platform (such as golang implementation and python implementation) construct inconsistent execution of malicious contracts, thereby further completing double-spending attacks.
Inconsistent implementation of version 4.5 causes double-spend attack:
The same blockchain project often has multiple implementations of different programming languages. Implementations in different programming languages ​​also have various possibilities for such inconsistent execution. ECDSA above is an example. Big integer arithmetic is also a common example. For example, in the previous implementation of the C# version of NEO and the implementation of the python version, the division operation of big integer (BigInteger) can lead to inconsistent execution phenomenon seen in different programming language implementation versions, resulting in a double-spend attack. Similar phenomena have occurred in multiple blockchain projects.
4.6 Other Issues Inconsistency Issues
Factors such as system time, random numbers, and floating-point calculations can also cause inconsistent execution of virtual machines. However, in our audit, we did not find that such loopholes appeared in the public chain projects. Most blockchain projects are designed with these obvious problems in mind.
But the factors that can cause inconsistent execution can go far beyond the issues we identified above. In fact, some subjective factors (factors that depend on the current operating state of the machine, we call them subjective factors) may cause inconsistent execution of virtual machines. For example, in 4G memory, machines with 8G memory have different subjective boundaries of out-of-memory (OOM) during execution. Attackers may use OOM to cause inconsistent execution of virtual machines.
5. Double-spend attack caused by consensus mechanism
The double-spend attack caused by the consensus mechanism is actually an issue that has been fully discussed in the industry. However, various public chain schemes may still have fork problems in the implementation of the consensus mechanism, resulting in a double-spend attack.
5.1 ONT vBFT VRF Random Number Bypass Vulnerability
Long range attack is a fork attack method that all PoS consensus mechanisms currently face. The attacker can choose not to fork the existing chain, but actually return to a chain state a long time ago (the attacker once held a large amount of currency in this state), and create a new chain with a longer jump to make the network mistaken for it. The main chain, thus completing the double spend. At present, there is no fundamental solution to the Long range attack in the industry, and it can only be ensured that the fork can be prevented from occurring when the "Weak Subjectivity" does not occur.
ONT's vBFT consensus algorithm proposes a method that relies on Verifiable Random Functions (VRFs) to prevent malicious forks from scaling. The network first selects a round of consensus candidate block proposal node set, block verification node set and block confirmation node set in the consensus network based on VRF, and then the selected node set completes the consensus. Since the priority order of nodes is determined by VRF for each block, for maliciously generated forks, it is difficult for the attacker to maintain his high priority continuously (if the attacker does not control the vast majority of equity), so malicious The resulting fork will die quickly, allowing vBFT to have fast state finality.
However, we found that there is a loophole in the VRF implementation in vBFT, which allows users with a private key of 0 to generate the same vrfValue for any block data. Specifically, the vrf in vBFT is an implementation of the draft VRF standard proposed by Boston University (https://hdl.handle.net/2144/29225). Specifically in sections 5.1 and 5.2 of the draft, we can see the algorithms for proof generation and random number calculation. As shown in the figure:
The vulnerability is that when x=0, y is still a valid public key from the calculation, and can pass the verification of ValidatePublicKey in the vBFT implementation. gamma is a fixed point (point at infinity) on the elliptic curve. That is, for any input alpha, the value generated by the vrf is a fixed value. There is absolutely no randomness. This problem can lead to attackers using fixed vrf to destroy the randomness of consensus algorithm, thus controlling node election for a long time.
5.2 NEO dBFT Consensus Fork
NEO's dBFT consensus mechanism can be regarded as a POS+pBFT scheme in essence. In the original NEO code, we found that NEO and ONT had fork problems when implementing their dBFT consensus mechanism. Malicious consensus nodes can generate a forked block, resulting in double spending. For details, please refer to our previous article: "Analysis and Improvement of NEO's dBFT Consensus Mechanism" (http://blogs.360.cn/post/NEO_dBFT_en.html), we will not repeat it here.
6. An efficient mitigation measure for the inconsistent double-spending problem of virtual machine execution
For logic loopholes such as verification bypass and double-spending loopholes caused by consensus mechanism problems, it is still necessary to analyze specific problems in business logic. Here we propose a mitigation against virtual machine execution inconsistency.
A simple way to solve the double-spending problem caused by inconsistent execution of virtual machines is for the block producer to hash the global state State_ after running the transaction, and then pack the hash into the block. After receiving the block, the ordinary node compares the hash of the state State'_ after running the transaction locally with the hash of State_. If they are equal, there is no fork. However, since the local data grows first, hashing the global state each time is extremely expensive. In response to this problem, Ethereum uses the structure of MekleTree to improve performance and deal with the fork rollback problem. But Ethereum's solution is not suitable for blockchain projects that use other data structures to store state information. Here we propose a new solution whose workflow is as follows:
1. In the block packaging stage, the block producer performs the sequence of write operations to the database during the running of all transactions in the block [write_db_1 write_db_2 …. write_db_n] record and calculate the hash value write_db_hash of the sequence.
2. After the ordinary node receives the new block, it will verify the block. Then execute the transaction in the virtual machine. At the same time, the write operation sequence of these transactions to the database is recorded locally [write_db_1' write_db_2' .... write_db_n'], and then calculate write_db_hash'. Determine whether it is equal to write_db_hash. If equal, no inconsistent execution is considered to have occurred. If not, reject the commit for the sequence of write operations.
The core idea of ​​this method is that the reason for the inconsistency in the execution of the virtual machine of the smart contract platform is that various functional functions in the contract and the support of Turing completeness may introduce various uncertain factors, resulting in inconsistent execution. A variety of complex and small reasons may lead to such inconsistent execution. But let's take a step back and see that the essence of the double-spend attack is to modify the global state State_, which is essentially a series of simple write operations (simple write operations often do not produce ambiguity). To prevent double spending, it is only necessary to perform a match check on all write operation sequences. The overhead of matching and recording these write operations locally is very small, and at the same time recording the sequence of these write operations locally, it is also convenient to deal with other factors such as fork rollback.
7. Postscript
In this article, by introducing the case findings of multiple double-spend attack vulnerabilities we found against EOS, NEO and other large public chain platforms, we have summarized a variety of reasons for the double-spend attack of digital currency, and proposed a general security mitigation measures. From the above analysis, we can see that the current form of blockchain security is still very serious. Various public chain projects have actually had serious security problems such as double-spending attacks. Our work ethic has stood the test of time. make a billion or work hard? Of course, work is hard. But luckily, in a few months of blockchain security research, we have received more than $300,000 worth of digital currency vulnerability report rewards from various project parties, thank you.
All vulnerabilities mentioned in this article have been fixed. In the process of vulnerability reporting and resolution, we found that the EOS and NEO project parties deal with security issues professionally, efficiently and in a timely manner. Project security has also been improved step by step. We will continue to pay attention to and study the security issues of blockchain-related technologies and promote the development of blockchain technology.
A manual pulse generator (MPG) is a device normally associated with computer numerically controlled machinery or other devices involved in positioning. It usually consists of a rotating knob that generates electrical pulses that are sent to an equipment controller. The controller will then move the piece of equipment a predetermined distance for each pulse.
The CNC handheld controller MPG Pendant with x1, x10, x100 selectable. It is equipped with our popular machined MPG unit, 4,5,6 axis and scale selector, emergency stop and reset button.
Manual Pulse Generator,Handwheel MPG CNC,Electric Pulse Generator,Signal Pulse Generator
Jilin Lander Intelligent Technology Co., Ltd , https://www.landerintelligent.com