Zurück zum Blog

Wie ein kritischer Bug im Solana-Netzwerk erkannt und rechtzeitig behoben wurde

Code Auditing
7. Juni 2022
5 Min. Lesezeit

Im April entdeckte unser System zur Schwachstellenerkennung ein Problem in rBPF von Solana (d.h. der virtuellen Maschine, auf der alle Solana dApps laufen: https://github.com/solana-labs/rbpf). Nach sorgfältiger Untersuchung stellten wir fest, dass es sich um eine Sicherheitslücke handelt, die zu einem falschen Ausführungspfad eines Vertrags führen kann. Wir meldeten den Fehler dem Solana-Sicherheitsteam, das die Schwachstelle umgehend bestätigte und behob. Außerdem gewährte uns das Team SoL-Token im Wert von 800.000 US-Dollar.

Die Schwachstelle besteht in neueren Versionen von rBPF (0.2.26 bis 0.2.27). Als wir das Problem meldeten, waren die auf dem Mainnet verwendeten Validatoren noch nicht auf die betroffenen Versionen aktualisiert worden. Unser System erkannte das Problem, bevor die betroffene Version eingespielt wurde, wodurch die Validatoren des Mainnets immun gegen diese Schwachstelle waren.

Im Folgenden erläutern wir die Details dieser Schwachstelle.

1. eBPF und rBPF

eBPF (Extended Berkeley Packet Filter) wurde ursprünglich für das Filtern von Paketen im Kernel entwickelt. Aufgrund der Sicherheit, Effizienz und Skalierbarkeit von eBPF wird es heute in verschiedenen Bereichen wie Netzwerk, Tracing, Profiling usw. eingesetzt. Angesichts der reichen Fähigkeiten von eBPF nutzt Solana es als Ausführungs-Engine für Smart Contracts. Um dApps auf Solana zu entwickeln, entwickeln Entwickler ihre Smart Contracts in Rust und kompilieren den Contract in eBPF-Bytecode.

Solana verwendet rBPF, eine in Rust geschriebene virtuelle Maschine, um den kompilierten BPF-Bytecode auszuführen. Ob die vorgeschlagene virtuelle Maschine (d.h. rBPF) robust, sicher und präzise ist, ist jedoch unbekannt. Wenn Sicherheitsprobleme innerhalb von rBPF bestehen, können alle rBPF enthaltenden Validatoren betroffen sein, was zu riesigen Verlusten (z.B. Verlust von Geldern) für das gesamte Solana-Netzwerk führt.

2. Grundursache

Wir entwickelten ein Tool, das Implementierungsfehler von rBPF automatisch lokalisieren und den Code von rBPF periodisch scannen kann. Während des Scanvorgangs wurde ein ernstes Problem in rBPF (Version 0.2.26) identifiziert, das zu einem falschen Ausführungspfad eines Vertrags führen kann.

Insbesondere wird die sdiv-Instruktion als vorzeichenbehaftete Division-Instruktion verwendet, die als Standard-Feature in rbpf 0.2.26 eingeführt wurde. sdiv unterstützt die Division für Operanden sowohl in 32-Bit (d.h. sdiv32) als auch in 64-Bit (sdiv64). Für die Instruktion sdiv32 wird das Berechnungsergebnis in einem 64-Bit-BPF-Register gespeichert. Wenn jedoch die Instruktionen nach der sdiv32-Instruktion das Berechnungsergebnis als 64-Bit lesen, kann das Ergebnis abweichen. Das liegt daran, dass rBPF das Berechnungsergebnis von sdiv32 während der JIT-Kompilierung nicht in den korrekten Wert in 64-Bit erweitert.

Zum Beispiel, wenn eine positive Zahl (d.h. 12) durch eine negative Zahl (d.h. -4) mit sdiv32 geteilt wird, sollte das korrekte Ergebnis sowohl in 32-Bit als auch in 64-Bit -3 sein. Der folgende Code ist ein Beispiel.

Nachdem wir ihn im Interpreted- und im JIT-Modus ausgeführt und nachverfolgt hatten, konnten wir die Unterschiede zwischen ihnen beobachten:

2.1 Interpreted Modus

0 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000]    29: lddw r5, 0x10000000c
 1 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 000000010000000C, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000]    31: sdiv32 r5, -4
 2 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, FFFFFFFFFFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000]    32: jslt r5, 0, lbb_7
 3 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, FFFFFFFFFFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000]    36: exit

2.2 JIT Modus

0 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000]    29: lddw r5, 0x10000000c
 1 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 000000010000000C, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000]    31: sdiv32 r5, -4
 2 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 00000000FFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000]    32: jslt r5, 0, lbb_7
 3 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 00000000FFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000]    33: lddw r0, 0x1
 4 [0000000000000001, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 00000000FFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000]    35: exit

Im Interpreted Modus wird das Register r5 auf 0xFFFFFFFFFFFFFFFD (-3 im 32-Bit- und 64-Bit-Modus) gesetzt, während im JIT-Modus r5 auf 0x00000000FFFFFFFD gesetzt wird. In diesem Fall wird r5 für die Instruktion jslt, die einen 64-Bit-Wert empfängt, als positive Zahl (d.h. 0x00000000FFFFFFFD) erkannt. Danach wird der Ausführungspfad völlig falsch sein.

3. Auswirkungen

Diese falsche Implementierung kann zu einem fehlerhaften Ausführungspfad eines Vertrags führen und ernsthafte Probleme verursachen.

Wenn beispielsweise eine wesentliche Operation in einem Smart Contract auf dem Ergebnis der sdiv32-Instruktion basiert, kann dies zu fehlerhaften Ausführungsergebnissen führen und von Angreifern ausgenutzt werden.

Dieses Problem wurde in https://github.com/solana-labs/rbpf/pull/283 eingeführt, was bedeutet, dass rBPF ab Version 0.2.26 anfällig ist. Wir identifizierten das Problem und meldeten es dem Solana-Sicherheitsteam am 28. April 2022. Das Team reagierte schnell auf unsere Meldung und behob das Problem innerhalb weniger Stunden, indem es die Vorzeichenerweiterungsoperation für die sdiv32-Instruktion hinzufügte. Die Korrektur ist in https://github.com/solana-labs/rbpf/pull/310 zu finden. Dank der rechtzeitigen Erkennung und Meldung durch unser Team waren die Validatoren des Mainnets von dieser Schwachstelle nicht betroffen.

Dieses Problem wird als Protokoll-Liveness-Bug eingestuft und führte zu einer Bug-Bounty von 800.000 US-Dollar, die von Solana gewährt wurde.

Zeitplan

  • 28.04.2022: Wir meldeten das Problem dem Solana-Sicherheitsteam
  • 29.04.2022: Die Schwachstelle wurde behoben
  • 09.05.2022: CVE-2022-23066 wurde zugewiesen
  • 01.06.2022: Die Bug-Bounty wurde gewährt

Ü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 wird von erstklassigen Sicherheitsexperten und erfahrenen Experten aus Wissenschaft und Industrie gegründet. Sie haben mehrere Blockchain-Sicherheitsarbeiten auf renommierten Konferenzen veröffentlicht, mehrere Zero-Day-Angriffe auf DeFi-Anwendungen gemeldet und detaillierte Analyseberichte zu sicherheitsrelevanten Vorfällen mit hoher Auswirkung veröffentlicht.

Twitter: [BlockSecTeam]

Medium: https://blocksecteam.medium.com

Website: https://www.blocksec.com

Für die neuesten Informationen anmelden
Über die sichere Speicherung hinaus, Teil 2: Wallet-Kryptografie sicher implementieren
Security Insights

Über die sichere Speicherung hinaus, Teil 2: Wallet-Kryptografie sicher implementieren

Kann ein Angreifer einen privaten Schlüssel rekonstruieren, ohne dessen geschützte Kopie auszulesen? Teil 2 von Beyond Secure Storage untersucht sechs Vorfälle, bei denen schwache Zufallszahlen, Entropieverlust oder Fehler bei Signatur-Nonces Schlüssel vorhersagbar oder rekonstruierbar machten. Daraus leitet er Anforderungen an die Implementierung der Schlüsselerzeugung und des Signierens ab und erläutert anschließend, wie Zahlungsinstitute deren Einhaltung durch Code-Reviews und Tests des produktiv eingesetzten Systems überprüfen können.

Über sichere Speicherung hinaus, Teil 1: Sichere Zahlungs- und Signaturabläufe gestalten
Security Insights

Über sichere Speicherung hinaus, Teil 1: Sichere Zahlungs- und Signaturabläufe gestalten

Wie kann ein nicht autorisierter Vorgang eine gültige Signatur erhalten, ohne dass der Angreifer den privaten Schlüssel stiehlt? Teil 1 von Beyond Secure Storage untersucht anhand von Vorfällen bei Bitget, Bybit und Binance Autorisierungsfehler bei Zahlungsanforderungen, der Erstellung, Signierung und Ausführung von Transaktionen sowie bei deren Abwicklung. Daraus leitet er Gestaltungsprinzipien ab, um nicht autorisierte Vorgänge zu verhindern und Verluste zu begrenzen. Anschließend erläutert er, wie Überprüfungen, Audits, Penetrationstests und Übungen diese Schutzmaßnahmen verifizieren können.

NEAR-Intents-Exploit: Fehler bei der Rückerstattung und Lehren für die Sicherheit
Security Insights

NEAR-Intents-Exploit: Fehler bei der Rückerstattung und Lehren für die Sicherheit

Beim Exploit von NEAR Intents wurden überdimensionierte Rückerstattungsereignisse genutzt, um interne Guthaben zu erhalten, nachdem die eingezahlten Vermögenswerte zurückgegeben worden waren. Diese Analyse rekonstruiert den Ablauf der Receipts und sieben Auszahlungen auf der BNB Chain in Höhe von insgesamt 3.865.021 USDT. Sie unterscheidet diese Mittelabflüsse von der vom Projekt gemeldeten vollständigen Rückgewinnung der Mittel und erläutert Sicherheitsaspekte bei der Entwicklung und Prüfung von NEAR-Smart-Contracts.

Der beste Sicherheitsauditor für Web3

Lassen Sie Design, Code und Geschäftslogik vor dem Launch prüfen. Nach den höchsten Sicherheitsstandards der Branche.

BlockSec-Audit