642 total views
The root cause is that the old version of Geth did not consider the handling of outliers when processing calls to pre-compiled contracts, which led to attackers using this vulnerability to implement overlapping copies, affecting the return value, and ultimately leading to the appearance of forks.
At around 20:50 on August 27, 2021, Beijing time (block height 13107518), Ethereum suddenly forks. We analyzed Geth’s code version modification and the transaction that caused the fork (0x1cb6fb36633d270edefc04d048145b4298e67b8aa82a9e5ec4aa1435dd770ce4) to clarify the root cause of the Ethereum fork: The old version of Geth did not consider special circumstances (corner cases) when processing precompiled contract calls. The processing of the parameter value causes an overlapping copy (overlapping copy), resulting in an abnormal return value. The vulnerability (CVE-2021-39137) has been submitted to Geth official, and the details have not been disclosed yet, but the attacker has used the vulnerability to carry out attacks. We believe that timely analysis and disclosure are necessary, and we hope that our analysis can provide the necessary understanding and help to the community.
Using our online analysis tools , you can see:
This transaction executed a carefully constructed STATICCALL. The attacker set addr to 0x04 (precompiled contract dataCopy), inOffset to 0, inSize to 32, retOffset to 7, and retSize to 32.
Since the target address of STATICCALL is a precompiled contract, the RunPrecompiledContract in Figure 2 will be executed.
According to the code in Figure 3 and Figure 4, we can see that the logic that the precompiled contract 0x04 actually executes is simply to return in (pointer).
Figure 5 is the execution process of STATICCALL. Line 753 is the entry point for executing the precompiled contract. The args of line 751 points to the pointer of the inOffset ~ inOffset + inSize area in the EVM Memory, which means that args points to Mem[0:32].
According to Figure 6 and the previous analysis of the precompiled contract 0x04 (dataCopy), we can know that the return value ret of line 753 is exactly the same pointer as args, and it also points to Mem[0:32].
- In the 1.10.7 version of Geth (with bug): line 762 assigns the value pointed to by ret to the area of retOffset ~ retOffset + retOffset in the Memory of the EVM, that is, assigns the value of Mem[0:32] to Mem[7 :7+32], and because ret is a pointer to Mem[0:32], Memory.Set modifies the value of Mem[7:32] this time, which also modifies the value pointed to by ret. So the ret returned on line 771 is no longer the ret at the end of the execution of the precompiled contract.
- In version 1.10.8 of Geth (no bug): Added 766 lines: ret = common.CopyBytes (ret), a deep copy of the value in Mem[0:32] is assigned to ret, then line 767 The executed Memory.Set will only modify Memory but not ret. The ret returned in line 771 is the correct ret.
Through the analysis of the entire attack process and the analysis of the Geth source code, we believe that the root cause is that the old version of Geth did not consider the handling of outliers when processing the call of the precompiled contract, which caused the attacker to use the vulnerability to implement overlapping copies, affecting The return value will eventually lead to the occurrence of a fork. Since Geth is the basis of public chains such as BSC, HECO, Polygon, etc., the scope of the vulnerability is wide. At present, all public chains have also launched upgrades and patches, and we also call on all relevant nodes to upgrade and patch them as soon as possible to ensure the security of the infrastructure.
Disclaimer: As a blockchain information platform, the articles published on this site only represent the author’s personal views, and have nothing to do with the position of ChainNews. The information, opinions, etc. in the article are for reference only, and are not intended as or regarded as actual investment advice.