Back to Blog

zkLend Exploit Post-Mortem: Details und Missverständnisse des $10M Flash Loan Angriffs beleuchtet

February 20, 2025
8 min read

Am 12. Februar 2025 wurde zkLend [1], ein Kreditprotokoll auf StarkNet, durch eine ausgeklügelte Manipulation seines Akkumulatormechanismus um rund 10 Millionen US-Dollar kompromittiert. Der Angreifer nutzte Flash-Kredite und Rundungsfehler, um die Werte der Sicherheiten künstlich aufzublähen und andere Vermögenswerte vom Protokoll zu leihen, um Gewinne zu erzielen.

Es fehlt jedoch eine detaillierte und genaue technische Analyse aus Sicherheitssicht. Trotz vorhandener Analysen anderer Sicherheitsexperten, die wertvolle Einblicke lieferten, bestehen weiterhin einige Missverständnisse – insbesondere hinsichtlich der Angriffsanalyse. Die spätere Veröffentlichung des offiziellen Post-Mortems von zkLend [2] bietet eine vereinfachte Beschreibung, es fehlt jedoch eine detaillierte technische Analyse. In diesem Blogbeitrag möchten wir eine umfassende Untersuchung liefern, um den Vorfall zu klären.

Wichtigste Erkenntnisse (TL;DR)

  • Die Hauptursache dieses Vorfalls liegt in der Kombination der folgenden drei Probleme:

    • Die leere Markinitialisierung ermöglicht die Einzahlung beliebiger Vermögenswerte.
    • Der spezifische Spendenmechanismus in zkLends Flash-Kredit ermöglicht die Manipulation des Akkumulators, einer globalen Variablen als Skalierungsfaktor zur dynamischen Anpassung der Sicherheitenwerte der Benutzer.
    • Präzisionsverlust tritt durch Abschneiden auf. Im Gegensatz zum klassischen Präzisionsverlust bei der Division beginnt der Nenner bei 1, wird aber auf einen sehr großen Wert aufgebläht, was zu einer Unterschätzung beim Verbrennen des Anteil-Tokens führt.
  • Der Angreifer profitierte nicht von wstETH, das von anderen Benutzern hinterlegt wurde. Stattdessen nutzte der Angreifer die Schwachstellen aus, um den Sicherheitenwert zu manipulieren und eine kleine Menge wstETH als Anfangskapital zu verwenden, um den Sicherheitenwert auf über 7.000 wstETH zu erhöhen, was die Aufnahme anderer Vermögenswerte aus dem Markt ermöglichte.

In den folgenden Abschnitten werden wir zunächst einige wichtige Hintergrundinformationen zu zkLend liefern. Anschließend werden wir eine eingehende Analyse der Probleme und des damit verbundenen Angriffs durchführen.

0x1 Hintergrund: Verständnis des Kernprotokolls von zkLend

zkLend ist ein Kreditprojekt auf StarkNet, das gängige Kreditprotokolle wie besicherte Kredite und Flash-Kredite unterstützt. Lassen Sie uns in die Implementierungsdetails dieser beiden Protokolle eintauchen.

0x1.1 Besicherte Kredite

Ein besicherter Kredit bezieht sich auf den Prozess, bei dem Benutzer bestimmte Vermögenswerte als Sicherheit an das Protokoll hinterlegen und im Gegenzug andere Vermögenswerte leihen. Der Wert der Sicherheit bestimmt die Kreditkapazität. Es ist wichtig zu beachten, dass Kreditprotokolle normalerweise nicht den Wert des Sicherheitenvermögens direkt speichern; stattdessen berechnen sie ihn mit der Formel:

collateral_balance = lending_accumulator * raw_balance

Insbesondere ist der lending_accumulator ein Skalierungsfaktor, der den Sicherheitenwert jedes Benutzers dynamisch anpasst, während raw_balance den tatsächlichen Anteil darstellt, den der Benutzer auf dem Markt hält. raw_balance wird aus dem collateral_balance unter Verwendung des lending_accumulator abgeleitet.

Was ist der Zweck dieses Designs? Es ermöglicht dem Protokoll, den Sicherheitenwert effizient zu verwalten und gleichzeitig die Benutzer zur Einzahlung von Vermögenswerten zu ermutigen. Durch die Zuweisung eines Teils der Einnahmen des Protokolls an die Sicherheitenanbieter steigt der lending_accumulator, wodurch der Wert aller Sicherheiten proportional und gleichzeitig verstärkt wird.

0x1.2 Flash-Kredite auf zkLend

Ein Flash-Kredit ist eine Art unbesicherter Kredit, bei dem Benutzer Vermögenswerte für einen sehr kurzen Zeitraum, normalerweise innerhalb einer einzigen Transaktion, vom Protokoll leihen können. Gelingt es dem Kreditnehmer nicht, den Kredit zurückzuzahlen oder die angegebenen Bedingungen zu erfüllen, wird die gesamte Transaktion rückgängig gemacht und der Kredit wird nicht ausgeführt.

In der Flash-Kredit-Implementierung von zkLend gibt es einen einzigartigen Spenden-Mechanismus. Wenn Benutzer Vermögenswerte zurückzahlen, geben sie nicht nur den erforderlichen Mindestbetrag zurück, sondern können auch zusätzliche Gelder als Spende beitragen. Das Protokoll verfolgt diese gespendeten Gelder und aktualisiert den lending_accumulator entsprechend. Dieser Prozess wird in der Funktion thesettle_extra_reserve_balance() implementiert. Die Formel zur Aktualisierung des lending_accumulator lautet wie folgt:

new_accumulator = (reserve_balance + totaldebt - amount_to_treasury) / ztoken_supply

  • reserve_balance: Der Gesamtbetrag des zugrunde liegenden Tokens (z. B. wstETH), der im Vertrag gehalten wird, einschließlich der von Benutzern gespendeten Token.
  • totaldebt: Die Gesamtschuld aller Kreditnehmer.
  • amount_to_treasury: Der Betrag der Protokolleinnahmen.
  • ztoken_supply: Die Gesamtmenge des Anteil-Tokens (z. B. zwstETH). Wenn Benutzer wstETH einzahlen, prägt der zkLend ztoken-Vertrag einen entsprechenden Betrag an zwstETH.

Nachdem wir das Kernprotokoll von zkLend verstanden haben, werden wir nun formal erläutern, wie der Angreifer seine Sicherheitenwerte manipulierte, indem er die Variablen lending_accumulator und raw_balance manipulierte.

0x2 Angriffsanalyse

Der Angreifer nutzte die folgenden Mechanismen und Schwachstellen im zkLend-Vertrag aus, um den Wert der Sicherheit zu manipulieren:

  • Manipulation von lending_accumulator
    • Leerer Markt: Vor dem Angriff war der zkLend-Markt für wstETH-Token leer, was die perfekte Bedingung für die Manipulation schuf. Darüber hinaus erlaubt der zkLend Market-Vertrag jedem, beliebige Mengen von Vermögenswerten in einen leeren Markt einzuzahlen. Der Angreifer zahlte eine geringe Menge an Vermögenswerten ein, um den Wert des lending_accumulator erheblich aufzublähen.
    • Spendenmechanismus: Die Funktion flash_loan() des zkLend Market-Vertrags verfügt über einen einzigartigen Spenden-Mechanismus. Insbesondere wenn ein Benutzer einen Flash-Kredit zurückzahlt, berechnet der Market-Vertrag die überschüssigen zurückgegebenen Mittel und erhöht die globale Variable lending_accumulator, wodurch die Sicherheitenwerte für alle Benutzer im Vertrag verstärkt werden.
  • Manipulation von raw_balance
    • Rundungsverhalten: Die Division im Prozess der Verbrennung von Anteil-Tokens verwendet Abschneiden (Truncation), was zu einer Unterschätzung der Änderung des raw_balance des Benutzers bei Entnahmen führt.

Durch die Manipulation beider Variablen konnte der Angreifer den Sicherheitenwert auf über 7.000 wstETH erhöhen und andere Vermögenswerte vom Markt leihen, um Gewinne zu erzielen.

0x2.1 Manipulation der Variable lending_accumulator

0x2.1.1 Leere Markinitialisierung

Durch die Untersuchung des Transaktionsprotokolls des Market-Vertrags vor dem Angriff können wir beobachten, dass der Angreifer zunächst 1 wei wstETH in den wstETH Market-Vertrag eingezahlt hat. Bei Durchsicht der internen Aufrufe dieser Transaktion wird deutlich, dass der wstETH Market-Vertrag 0 wstETH hielt und die Gesamtmenge an zwstETH ebenfalls 0 betrug.

Daher können wir bestätigen, dass es im zkLend wstETH-Markt keine vorherigen Einzahlungen oder Kredite gab. Sowohl der reserve_balance als auch die ztoken_supply befanden sich in ihren Anfangswerten von 0, und der Anfangswert des lending_accumulator war 1. Dieses leere Marktszenario schuf die Voraussetzungen für den nachfolgenden Angriff und ermöglichte es dem Angreifer, den lending_accumulator mit einer minimalen Menge an wstETH erheblich zu verstärken.

0x2.1.2 Manipulation von lending_accumulator über Flash-Kredit

Als Nächstes ruft der Angreifer in dieser Transaktion die Funktion flash_loan() auf, leiht 1 wei wstETH und zahlt 1000 wei wstETH zurück. Die überschüssigen 999 wei werden als Spende behandelt und im reserve_balance des Vertrags verbucht.

Gemäß der Formel zur Berechnung des lending_accumulator erhöht diese Transaktion den lending_accumulator von 1 auf 851,0.

0x2.1.3 Wiederholte Ausführung von flash_loan()

Der Angreifer führt insgesamt 10 flash_loan()-Aufrufe durch, leiht jedes Mal nur 1 wei wstETH, zahlt aber einen größeren Betrag zurück. Infolgedessen steigt der lending_accumulator auf einen astronomischen Wert von 4.069.297.906.051.644.020 (4,069 × 10^18), was zufällig der Dezimalpräzision von wstETH entspricht.

0x2.2 Manipulation der Variable raw_balance

Nachdem der lending_accumulator auf etwa 4,069 × 10^18 manipuliert wurde, rief der Angreifer die Funktion deposit() des Market-Vertrags mit 4.069297906051644020 wstETH auf. Basierend auf dem neuesten Wert des lending_accumulator wurde das raw_balance des Angreifervertrags zu 2.

0x2.2.1 Die erste Transaktion zur Manipulation von raw_balance

In dieser Transaktion rief der Angreifer die Funktion callflashloandraaan() des Angreifervertrags auf. Obwohl dieser Vertrag nicht Open Source ist, kann basierend auf der internen Aufrufsprotokollierung spekuliert werden, dass die Logik dieser Funktion eine Schleife enthält, die folgende Aktionen durchführt:

  • Einzahlung: Der Angreifer zahlt eine bestimmte Menge wstETH in den Marktvertrag ein.
  • Entnahme: Der Angreifer entnimmt den spezifischen Betrag an wstETH.

Analyse der Token-Übertragungsaufzeichnungen

Es kann beobachtet werden, dass der vom Angreifer eingezahlte Betrag an wstETH immer ein ganzzahliges Vielfaches des lending_accumulator ist, zum Beispiel das 2-fache des Wertes (z. B. 8.13859) des lending_accumulator.

Der entnommene wstETH-Betrag ist jedoch das 1,5-fache des Wertes (z. B. 6.10394) des lending_accumulator.

Durch Berechnungen können wir feststellen, dass der entnommene wstETH-Betrag den eingezahlten Betrag übersteigt. Warum passiert das?

Rundungsverhalten

Bei Überprüfung der Implementierung der Methoden deposit() und withdraw() sehen wir, dass diese beiden Methoden die Prägung und Verbrennung von zwstETH beinhalten. So funktioniert es:

`mint()` Funktion im Market-Vertrag

`burn()` Funktion im Market-Vertrag

Die Prozesse mint() und burn() beinhalten beide eine Skalierungslogik. Die Skalierungslogik beinhaltet Ganzzahldivision mit Abrundung (Abrundung auf die nächste ganze Zahl), was eine Schlüsselrolle beim Exploit spielt.

Wenn der Angreifer eine bestimmte Menge zwstETH verbrennt, wird die Skalierungslogik angewendet. Aufgrund des manipulierten Wertes des lending_accumulator, der außergewöhnlich hoch ist (etwa 4.069.297.906.051.644.020), führt diese Division dazu, dass das raw_balance des Angreifers nur um 1 Einheit sinkt, obwohl über 6 zwstETH verbrannt werden.

Die Änderungen am raw_balance des Angreifers sind in der folgenden Tabelle zusammengefasst:

Wir können beobachten, dass der Angreifer in dieser Transaktion wiederholt die Einzahlung - Entnahme-Logik ausführt und dabei den Präzisionsverlust während der Funktion withdraw() ausnutzt, was zu einer Unterschätzung der Differenz des raw_balance führt. Letztendlich stieg das raw_balance des Benutzers von 2 auf 3, was eine zusätzliche Einheit einbrachte.

0x2.2.2 Nachfolgender Angriffsprozess

Nachfolgende Angriffstransaktionen folgten dem gleichen Muster wie der erste Angriff: Der Angreifer durchlief wiederholt Einzahlungs - Entnahme-Transaktionen, um wstETH zu erwerben.

Das erworbene wstETH wird wieder in den Markt eingezahlt, wodurch das raw_balance weiter erhöht wird, was dazu führt, dass der Wert der Sicherheiten des Angreifers weiter steigt.

Beispielhafte Erläuterung

Wir verwenden die folgende Transaktion als Veranschaulichung.

  • Es wurden insgesamt 30 Einzahlungen getätigt, wobei jedes Mal 4,069 wstETH eingezahlt wurden.
  • Es wurden insgesamt 30 Entnahmen getätigt, wobei jedes Mal 6,104 wstETH entnommen wurden.
  • Nach diesem Zyklus konnte der Angreifer laut Berechnungen 61,39 wstETH entnehmen.

Darüber hinaus ist anzumerken, dass zwischen diesen Angriffstransaktionen mehrere increase()-Methoden aufgerufen wurden. Diese Methoden wurden verwendet, um eine bestimmte Menge wstETH vom Konto des Angreifers an den Angreifervertrag zu überweisen, der dann die Mittel für nachfolgende Einzahlungen in den Market-Vertrag bereitstellte.

Diese Aktionen steigern den Wert von raw_balance und ermöglichen es dem Angreifer, den Sicherheitenwert weiter zu erhöhen. Schließlich erreichte das raw_balance des Angreifers 1.724 mit einem Wert von 7.015,4 wstETH, was ausreichte, um andere Vermögenswerte vom Markt zu leihen.

0x3 Gewinnanalyse

0x3.1 Leihen anderer Finanzierungsarten

Nach der Manipulation des Sicherheitenwertes lieh der Angreifer andere Arten von Geldern vom Markt und fuhr mit den folgenden Transaktionen fort (Auszug):

0x3.2 Überbrücken der geliehenen Gelder auf Layer1

Bei der Überprüfung der Bridge-Transaktionen des Angreifervertrags kann beobachtet werden, dass der Angreifer einen Teil der geliehenen Gelder auf Layer 1 überbrückte.

0x4 Fazit

Zusammenfassend unterstreicht dieser Angriff auf das zkLend-Protokoll mehrere wichtige Implikationen für das Design und die Sicherheit von dezentralen Kreditprotokollen:

  • Markinitialisierung und Bedingungen für die Einzahlung von Vermögenswerten: Der anfänglich leere Markt ermöglichte es dem Angreifer, eine geringe Menge wstETH einzuzahlen und den lending_accumulator zu manipulieren, wodurch er einen Hebel für den Exploit erhielt. Die Sicherstellung einer ausreichenden Liquiditätsbasis oder die Begrenzung von Vermögensspenden in frühen Marktphasen könnte helfen, ähnliche Angriffe zu verhindern.
  • Wichtigkeit korrekter Akkumulatormechanismen: Der Angreifer nutzte den Spendenmechanismus in der Funktion flash_loan() aus, um den lending_accumulator zu manipulieren und die Sicherheitenwerte aller Benutzer aufzublähen. Protokolle mit akkumulatorbasierten Mechanismen sollten vor einer einfachen Manipulation von Skalierungsfaktoren geschützt sein.
  • Rundungsverhalten und Präzisionsverlust: Ein Rundungsproblem während der Verbrennung von zwstETH-Tokens führte zu Präzisionsverlust und Unterschätzung des raw_balance, was es dem Angreifer ermöglichte, das raw_balance zu manipulieren. Protokolle sollten eine höhere Präzision oder Validierungsprüfungen verwenden, um solche Exploits zu verhindern.

Dieser Vorfall unterstreicht erneut die Bedeutung von rechtzeitigen Benachrichtigungen bezüglich der Initialisierungs- und Betriebsstati sowie der proaktiven Gefahrenabwehr zur Minderung potenzieller Verluste.

Referenz

[1] https://zklend.com/

[2] zkLends Sicherheitsvorfall Post-Mortem: https://drive.google.com/file/d/10i1dh_J89tPPw7KRcmFIVM6iNrJZAyfi/view

Sign up for the latest updates
The Decentralization Dilemma: Cascading Risk and Emergency Power in the KelpDAO Crisis
Security Insights

The Decentralization Dilemma: Cascading Risk and Emergency Power in the KelpDAO Crisis

This BlockSec deep-dive analyzes the KelpDAO $290M rsETH cross-chain bridge exploit (April 18, 2026), attributed to the Lazarus Group, tracing a causal chain across three layers: how a single-point DVN dependency enabled the attack, how DeFi composability cascaded the damage through Aave V3 lending markets to freeze WETH liquidity exceeding $6.7B across Ethereum, Arbitrum, Base, Mantle, and Linea, and how the crisis forced decentralized governance to exercise centralized emergency powers. The article examines three parameters that shaped the cascade's severity (LTV, pool depth, and cross-chain deployment count) and provides an exclusive technical breakdown of Arbitrum Security Council's forced state transition, an atomic contract upgrade that moved 30,766 ETH without the holder's signature.

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026

This BlockSec weekly security report covers four attack incidents detected between April 13 and April 19, 2026, across multiple chains such as Ethereum, Unichain, Arbitrum, and NEAR, with total estimated losses of approximately $310M. The highlighted incident is the $290M KelpDAO rsETH bridge exploit, where an attacker poisoned the RPC infrastructure of the sole LayerZero DVN to fabricate a cross-chain message, triggering a cascading WETH freeze across five chains and an Arbitrum Security Council forced state transition that raises questions about the actual trust boundaries of decentralized systems. Other incidents include a $242K MMR proof forgery on Hyperbridge, a $1.5M signed integer abuse on Dango, and an $18.4M circular swap path exploit on Rhea Finance's Burrowland protocol.

Weekly Web3 Security Incident Roundup | Apr 6 – Apr 12, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Apr 6 – Apr 12, 2026

This BlockSec weekly security report covers four DeFi attack incidents detected between April 6 and April 12, 2026, across Linea, BNB Chain, Arbitrum, Optimism, Avalanche, and Base, with total estimated losses of approximately $928.6K. Notable incidents include a $517K approval-related exploit where a user mistakenly approved a permissionless SquidMulticall contract enabling arbitrary external calls, a $193K business logic flaw in the HB token's reward-settlement logic that allowed direct AMM reserve manipulation, a $165.6K exploit in Denaria's perpetual DEX caused by a rounding asymmetry compounded with an unsafe cast, and a $53K access control issue in XBITVault caused by an initialization-dependent check that failed open. The report provides detailed vulnerability analysis and attack transaction breakdowns for each incident.