EVM-kompatible (Ethereum Virtual Machine) Blockchains sind darauf ausgelegt, mit der Smart-Contract-Funktionalität, der Programmiersprache (Solidity) und dem Tooling-Ökosystem der Ethereum-Blockchain kompatibel zu sein. Bei diesem Prozess ist die Implementierung einer EVM-konformen virtuellen Maschine einer der wichtigsten Schritte. Im Rahmen unserer Recherchen haben wir jedoch festgestellt, dass die Aufrechterhaltung der EVM-Kompatibilität in verschiedenen Implementierungen keine leichte Aufgabe ist.
Um dieses Problem zu lösen, hat BlockSec ein internes System entwickelt, das systematisch Bugs und Sicherheitslücken in der EVM-Implementierung aufspüren kann. Dieses System erwies sich als effektiv. Es meldete vier Bugs in der Aurora Engine und vier Bugs in Moonbeam. Alle wurden gemeldet und behoben. Zu beachten ist, dass diese Testmethodik auch verwendet wurde, um letztes Jahr zwei kritische Schwachstellen (CVE-2021–46102, CVE-2022–23066) in der Solana-rbpf-Implementierung zu lokalisieren.
1. Hintergrund
Heutzutage werden viele verschiedene Blockchains mit Optimierungen hinsichtlich niedriger Gasgebühren, hohem Durchsatz und hoher Leistung vorgeschlagen. In diesem Zusammenhang werden neue virtuelle Maschinen oder Entwicklungssprachen vorgeschlagen, was die Hürde für den Umstieg für ursprüngliche Solidity-Entwickler erhöht. Daher werden viele EVM-kompatible Lösungen vorgeschlagen, die es Benutzern ermöglichen, ihre in Solidity entwickelten DApps auf diesen neuen Chains zu deployen. Aurora und Moonbeam sind die Vertreter dieser EVM-kompatiblen Lösungen. Die Robustheit, Zuverlässigkeit und Präzision dieser EVM-Implementierungen sind jedoch unbekannt und verdienen unsere Aufmerksamkeit. Zu diesem Zweck nutzen wir die Technik des Differential Fuzzing und prüfen, ob es Mängel in den Implementierungen gibt.
2. Differential Fuzzing
Der grundlegende Gedanke besteht darin, identische Eingaben an diese EVM-Implementierungen (z. B. Aurora, Moonbeam) und den modernsten Ethereum-Client (d. h. geth) zu senden, um zu prüfen, ob sie dieselbe Ausgabe liefern. Konkret sammeln wir historische Transaktionen auf Ethereum und mutieren den Contract-Code und die Transaktionszustände mit verschiedenen Strategien, um Testfälle zu generieren. Unsere Ergebnisse zeigen, dass Aurora Engine und Moonbeam in einigen Fällen nicht der Spezifikation entsprechen. Glücklicherweise wurden alle gemeldeten Probleme behoben, und wir werden nun die Details mitteilen.
3. Gefundene Bugs
Die meisten dieser Bugs befinden sich in den vorkompilierten Contracts, und die Ursachen und Auswirkungen sind unterschiedlich. Einige der Bugs können beispielsweise die Berechnung des Nonce-Werts beeinflussen, während andere die Gasberechnung beeinflussen und zu einem DoS-Angriff führen können. Alle gefundenen Bugs verstoßen gegen die vorgesehene Ausführungslogik der EVM-Spezifikation und können in bestimmten Fällen zu unerwartetem Verhalten führen. Eine detaillierte Beschreibung der gefundenen Bugs finden Sie nachfolgend.
3.1 Unzureichende Validierung
Kryptografische Logik ist komplex. In diesem Fall kann die Implementierung der entsprechenden Logik in EVM-Bytecode zu einem sehr hohen Gasverbrauch führen. Stattdessen können vorkompilierte Contracts, die in nativem Code entwickelt werden, die Leistung steigern. Wir haben jedoch aufgrund unzureichender Validierung mehrere Bugs in den vorkompilierten Contracts gefunden.
Aurora Engine: ecPairing
Dieser Bug wird im vorkompilierten Contract ecPairing gefunden.
Die Eingabe von ecPairing besteht aus mehreren Punkten auf zwei elliptischen Kurven. Gemäß der Spezifikation liegt der Punkt (0, 0) auf beiden Kurven und sollte eine gültige Eingabe sein:


Aurora Engine (Version 2.7.0) wird jedoch einen Revert durchführen, wenn der Punkt (0,0) in der Eingabe enthalten ist.

Der zugehörige PR ist hier.
Moonbeam: ecMul
Dieser Bug befindet sich im vorkompilierten Contract ecMul. Anders als bei Aurora Engine führt Moonbeam einen Revert der Transaktion durch, wenn die Eingabe gültig ist. Gemäß der Spezifikation sollte der vorkompilierte Contract ecMul die Eingabe mit Nullen auffüllen, wenn die Länge der Eingabe kleiner als 64 ist. Moonbeam wird jedoch einen Revert durchführen, anstatt den Auffüllvorgang durchzuführen.

Wir haben auch festgestellt, dass die vorkompilierten Contracts ecAdd und modexp dasselbe Problem aufweisen.
Moonbeam: ecRecover
Dieser Bug befindet sich im vorkompilierten Contract ecRecover, der zur Wiederherstellung der Ethereum-Adresse verwendet wird.
Gemäß der Spezifikation repräsentiert input[32..63] v einen U256-Bezeichner, der entweder 27 oder 28 sein soll, andernfalls sollte ecRecover nichts zurückgeben (die gesamte Transaktion sollte jedoch nicht rückgängig gemacht werden).
Moonbeam macht hier jedoch zwei Fehler:
- Es überprüft nur input[63], anstatt input[32..63] in einen U256-Typ zu konvertieren und dann den Wert zu überprüfen.
- Die Eingabe wird als gültig betrachtet, wenn der Bezeichner 0 oder 1 ist (er sollte nur 27 oder 28 sein).

Moonbeam: ecPairing
Dieser Bug befindet sich im vorkompilierten Contract ecPairing. Moonbeam führt keinen Revert der Transaktion durch, wenn die Eingabe ungültig ist. Gemäß der Spezifikation sollte die Eingabe des vorkompilierten Contracts ecPairing ein Vielfaches von 192 sein. Andernfalls sollte die Transaktion rückgängig gemacht werden.

Moonbeam führt jedoch keinen Revert der Transaktion durch, wenn die oben genannten Anforderungen nicht erfüllt sind.
3.2 Fehlerhafte Gasberechnung
Jeder Precompile-Contract hat einen Algorithmus zur Bestimmung des Gasverbrauchs. Eine fehlerhafte Gasberechnung kann zu einem DoS-Angriff führen.
Wir haben jedoch zwei Bugs sowohl in Aurora Engine als auch in Moonbeam gefunden, bei denen die Gasberechnung fehlerhaft ist.
Aurora Engine: modexp
Der Bug befindet sich im vorkompilierten Contract modexp. Der Algorithmus zur Berechnung des Gasverbrauchs ist durch EIP-2565 definiert. Der Gasverbrauch hängt von der Anzahl der Iterationen ab.
Der Algorithmus zur Berechnung der Anzahl der Iterationen ist der folgende.
def calculate_iteration_count(exponent_length, exponent):
iteration_count = 0
if exponent_length <= 32 and exponent == 0: iteration_count = 0
elif exponent_length <= 32: iteration_count = exponent.bit_length() - 1
elif exponent_length > 32: iteration_count = (8 * (exponent_length - 32)) + ((exponent & (2**256 - 1)).bit_length() - 1)
return max(iteration_count, 1)
Gemäß dem obigen Algorithmus beträgt die Iterationsanzahl mindestens eins. Aurora Engine gibt jedoch iteration_count direkt zurück, anstatt max(iteration_count, 1). In diesem Fall kann der zurückgegebene Wert (d. h. iteration_count) 0 sein, was bedeutet, dass Aurora in bestimmten Fällen eine deutlich geringere Gasgebühr als erwartet berechnen wird.
Der zugehörige Issue-Link ist hier.
Moonbeam: modexp
Der Bug befindet sich ebenfalls in der Funktion calculate_iteration_count des vorkompilierten Contracts modexp. Er wird jedoch in Moonbeam gefunden.
Wenn die exponent_length größer als 32 ist, wird der iteration_count mit dem folgenden Algorithmus berechnet.
(8 * (exponent_length - 32)) + ((exponent & (2**256 - 1)).bit_length() - 1)
Zu beachten ist, dass exponent & (2**256 - 1) verwendet wird, was die niedrigsten 32 Bytes des exponent nimmt, und Moonbeams Implementierung diesem Algorithmus folgt.
Gemäß der Spezifikation sollte die Gasberechnungsformel jedoch die höchsten 32 Bytes des exponent verwenden:

3.3 Nonce-Inkrementierungsfehler
Der Nonce eines extern verwalteten Kontos (EOA) gibt die Anzahl der erfolgreichen Transaktionen an, die von dieser Adresse signiert wurden. Wir haben jedoch festgestellt, dass der Nonce durch das Senden ungültiger Transaktionen auf der Aurora Engine erhöht werden kann.
Gemäß EIP-1559 sollte die EVM vor der Ausführung einer Transaktion sicherstellen, dass der Unterzeichner über ausreichend Guthaben verfügt, um den übertragenen nativen Token (z. B. ETH) und das erforderliche Gas zu decken. Andernfalls sollte die Transaktion verworfen und der Nonce des Unterzeichners nicht erhöht werden.

Obwohl Aurora Engine die Transaktion in dieser Situation verwirft, erhöht sie dennoch den Nonce des Unterzeichners.
Der zugehörige PR ist hier.
3.4 Fehlerhafte Opcode-Implementierung
Dieser Bug betrifft die Implementierung eines bestimmten Opcodes (d. h. PUSH). Wenn die auf den PUSH-Opcode folgenden Bytes unvollständig sind, sollten sie rechtsbündig ausgerichtet werden. Beispielsweise kann der Bytecode 0x64ffff wie folgt dekodiert werden:
PUSH5 0xffff
Da der Operand rechtsbündig ausgerichtet sein sollte, sollte der Wert 0xffff000000 auf den Stack gepusht werden. Die EVM-Implementierungen sowohl in Aurora Engine als auch in Moonbeam pushen jedoch stattdessen 0xffff, was fehlerhaft ist.
Der zugehörige PR ist hier.
4. Unser Service
Bei BlockSec verstehen wir, wie wichtig es ist, die EVM-Kompatibilität und -Sicherheit in verschiedenen Blockchain-Implementierungen aufrechtzuerhalten. Deshalb haben wir einen systematischen Ansatz zur Fehlererkennung entwickelt, der Schwachstellen in EVM-Implementierungen problemlos lokalisieren kann.
Unser internes System hat sich als äußerst effektiv bei der Lokalisierung von Bugs und Sicherheitslücken in EVM-Implementierungen erwiesen. Es hat erfolgreich vier Bugs in Aurora Engine und vier Bugs in Moonbeam gemeldet und behoben. Darüber hinaus wurde unsere Testmethodik verwendet, um letztes Jahr zwei kritische Schwachstellen (CVE-2021–46102, CVE-2022–23066) in der Solana-rbpf-Implementierung zu lokalisieren, was die Effektivität unseres Ansatzes unterstreicht.
Durch die Implementierung unseres systematischen Fehlererkennungsansatzes können unsere Kunden sicher sein, dass ihre EVM-Implementierungen sicher und zuverlässig sind. Wir sind bestrebt, erstklassige Lösungen für EVM-Kompatibilität und -Sicherheit bereitzustellen und unseren Kunden dabei zu helfen, Vertrauen bei ihren Benutzern und Stakeholdern aufzubauen.
Über BlockSec
Das BlockSec-Team konzentriert sich auf die Sicherheit des Blockchain-Ökosystems und arbeitet mit führenden DeFi-Projekten zusammen, um deren Produkte zu sichern. Das Team wurde von erstklassigen Sicherheitsforschern und erfahrenen Experten aus Wissenschaft und Industrie gegründet. Sie haben mehrere Blockchain-Sicherheitspapiere auf renommierten Konferenzen veröffentlicht, mehrere Zero-Day-Angriffe auf DeFi-Anwendungen gemeldet und detaillierte Analyseberichte zu sicherheitsrelevanten Vorfällen mit großer Auswirkung veröffentlicht.



