In der vergangenen Woche (09.03.2026 - 15.03.2026) hat BlockSec acht Angriffsvorfälle erkannt und analysiert, mit geschätzten Gesamtschäden von ca. 1,66 Mio. $. Die folgende Tabelle fasst diese Vorfälle zusammen, und detaillierte Analysen für jeden Fall sind in den folgenden Unterabschnitten aufgeführt.
| Datum | Vorfall | Typ | Geschätzter Schaden |
|---|---|---|---|
| 09.03.2026 | EtherFreakers Incident | Fehlerhafte Geschäftslogik | ~$25K |
| 10.03.2026 | Alkemi Incident | Fehlerhafte Geschäftslogik | ~$89K |
| 10.03.2026 | MT Incident | Fehlerhafte Geschäftslogik | ~$242K |
| 11.03.2026 | AAVE Liquidation Incident | Fehlkonfiguration | ~$1,01M |
| 11.03.2026 | Planet Finance Incident | Fehlerhafte Geschäftslogik | ~$10K |
| 12.03.2026 | AM Incident | Fehlerhafte Geschäftslogik | ~$131K |
| 12.03.2026 | DBXen Incident | Fehlerhafte Geschäftslogik | ~$149K |
| 15.03.2026 | Goose Finance Incident | Fehlerhafte Geschäftslogik | ~$8K |
EtherFreakers Incident
Kurze Zusammenfassung
Am 9. März 2026 wurde EtherFreakers, ein NFT-Spiel auf Ethereum, aufgrund einer fehlerhaften Doppelzählung ausgenutzt, was zu einem Verlust von ca. 25.000 $ führte. Jedes NFT im Spiel enthält ein abhebbares ETH-Guthaben (genannt "Energie"). Als Spielmechanik können Spieler attack() verwenden, um ein NFT ein anderes erfassen zu lassen und die Energie des Ziels zu beanspruchen. Der Vertrag zahlt jedoch das Guthaben des Ziels aus und überträgt das NFT, bevor er seine Buchhaltung abschließt. Ein Transfer-Hook liest dann veraltete, vor der Auszahlung liegende Daten und speist einen Teil davon zurück in einen globalen Dividendenpool, wodurch der Pool ohne neue ETH-Deckung aufgebläht wird. Der Ausnutzer schleifte diesen Erfassungsmechanismus, um den globalen Index aufzublähen, und zog dann das aufgeblähte Guthaben von einer Charge von NFTs ab.
Hintergrund
EtherFreakers ist ein On-Chain-NFT-Spiel, bei dem jedes NFT (ein "Freaker" genannt) ein abhebbares ETH-Guthaben namens energy enthält. Das System funktioniert wie ein Dividendenpool: Wenn bestimmte Aktionen stattfinden, wird ein Bruchteil von ETH proportional an alle Freaker verteilt. Das abrufbare ETH jedes Freakers wird von einem globalen Akkumulator freakerIndex in Kombination mit einem Token-spezifischen Anteilgewicht fortune verfolgt.
Konkret ist die Buchhaltungsformel: energyOf = basic + (freakerIndex - index) * fortune. Der freakerIndex erhöht sich, wenn _dissipateEnergyIntoPool(amount) ausgeführt wird, wobei 80 % von amount an alle Freaker und 20 % an die Ersteller verteilt werden. Direkte Einzahlungen über charge() erhöhen nur basic, ohne freakerIndex zu beeinflussen. Daher müssen Erhöhungen des freakerIndex immer durch reales Ether gedeckt sein, das in das System fließt. Wenn der freakerIndex ohne entsprechende ETH-Zuflüsse wächst, können Freaker mehr Ether einlösen, als der Vertrag tatsächlich hält.
Schwachstellenanalyse
Die Hauptursache ist eine falsche Ausführungsreihenfolge im EtherFreak-Vertrag (0x3A27...c0f33). Wenn eine Erfassung erfolgreich ist, führt die Funktion attack() die folgenden Schritte in dieser Reihenfolge aus:
- Zeile 237: Zahlt
targetCharge(die volle Energie des Ziel-NFTs) direkt per ETH-Überweisung an den Verteidiger. Die Energie ist nun verbraucht. - Zeile 240: Ruft
_transfer(defender, capturer, targetId)auf, um das NFT zu verschieben. Intern ruft_transfer()den ERC-721-Hook_beforeTokenTransfer()auf, der_dissipateEnergyIntoPool()mit 0,1 % vonenergyOf(targetId)aufruft. Dies ist der erste Aufruf von_dissipateEnergyIntoPool(), und er liest einen veralteten Wert, da Schritt 5 noch nicht stattgefunden hat. - Zeile 241: Ruft explizit
_dissipateEnergyIntoPool(sourceSpent)auf. Dies ist der zweite Aufruf, der Teil der normalen Spiellogik ist. - Zeilen 244-251: Aktualisiert
energyBalancessowohl fürsourceIdals auch fürtargetId.
Der Fehler liegt in Schritt 2: Da energyBalances[targetId] noch nicht aktualisiert wurde, sieht der Hook immer noch das Guthaben vor der Auszahlung und leitet einen Teil der bereits ausgegebenen Energie in den Dividendenpool. Die direkte ETH-Auszahlung in Schritt 1 und die Pool-Einleitung in Schritt 2 entnehmen beide die gleiche Energie, wodurch der freakerIndex ohne neue ETH-Deckung aufgebläht wird.
freakerIndex wächst jedes Mal, wenn _dissipateEnergyIntoPool() aufgerufen wird:
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x89e24d...9abd2942.
-
Schritt 1: Leihen von 1.700
WETH. -
Schritt 2: Prägen von zwei neuen Freakers, Token
590und591, unter Adressen, die vom Angreifer kontrolliert werden. -
Schritt 3: Wiederholtes Aufrufen der Spielfunktion
attack(590, 591)und Beibehalten der Ausführungen im erfolgreichen Erfassungszweig. -
Schritt 4: Nach jedem Erfolg wird Token
591an den Helfer zurückübertragen, damit dasselbe Paar wiederverwendet werden kann. -
Schritt 5: Jede erfolgreiche Schleife bläht den
freakerIndexüber das tatsächlich vom System erhaltene Ether hinaus auf. -
Schritt 6: Sobald der Index hoch genug ist, werden eine Charge von zuvor kontrollierten Freakers entladen. Die Token-IDs
496bis520werden jeweils für0,278052246002402082Ether entladen. -
Schritt 7: Das abgezogene Ether wird in
WETHumgewandelt, der Flash-Kredit von 1.700WETHzurückgezahlt und etwa 7,498WETHals Gewinn behalten.
Schlussfolgerung
Die Hauptursache liegt im erfolgreichen Erfassungsfluss von attack(): EtherFreakers zahlt targetCharge aus, bevor der Energiezustand des Zieltokens abgerechnet ist. _transfer() löst dann _beforeTokenTransfer() aus, das vor der Auszahlung liegende, veraltete energyOf(targetId) liest und einen Teil davon in den Pool verteilt. Dies erhöht den freakerIndex ohne neue Ether-Deckung, so dass die gleiche Zielenergie sowohl als Auszahlung als auch als Pool-Einzahlung gezählt wird. Dies ist ein Inflationsfehler in der Geschäftslogik, kein Reentrancy-Fehler.
Um ähnliche Risiken in Zukunft zu reduzieren:
-
Vermeiden Sie die Neuberechnung wirtschaftlicher Werte aus veränderlichem Zustand innerhalb von Übertragungs-Hooks, während die gleiche Transaktion noch abgewickelt wird.
-
Wenn der Übertragungs-Hook eine Zustandsvariable liest, stellen Sie sicher, dass die Ausführungsreihenfolge das Ergebnis nicht beeinflusst (z. B. den Zustand vor dem Hook abwickeln, nicht danach).
Alkemi Incident
Kurze Zusammenfassung
Am 10. März 2026 wurde das Alkemi-Protokoll auf Ethereum ausgenutzt, was zu einem Verlust von ca. 89.000 $ führte. Die Hauptursache ist ein Abrechnungsfehler und eine fehlerhafte Geschäftslogik. Die fehlerhafte Liquidierungslogik erlaubt es jedem, seine eigene Position innerhalb derselben Transaktion zu liquidieren und davon zu profitieren. Darüber hinaus führt ein Abrechnungsfehler dazu, dass die Kollateralreduzierung des Angreifers während der Liquidation überschrieben wird, was es dem Angreifer ermöglicht, Liquidierungsprämien zu erhalten, ohne die beabsichtigten Kosten zu tragen.
Hintergrund
Alkemi ist ein Kreditprotokoll. Wenn eine Position eines Kreditnehmers unterbesichert wird, kann jeder liquidateBorrow() aufrufen, um einen Teil der Schuld zurückzuzahlen und die Kollateral mit einem Rabatt zu beschlagnahmen. Um übermäßige Liquidierung zu verhindern, begrenzt das Protokoll den pro Transaktion rückzahlbaren Betrag auf das Minimum von drei Werten:
- Der aktuelle Schuldenbetrag des Kreditnehmers (
currentBorrowBalance_TargetUnderwaterAsset). - Die maximale Rückzahlung, die die Kollateral des Kreditnehmers nach Anwendung des Liquidierungsrabatts abdecken kann (
calculateDiscountedBorrowDenominatedCollateral()). - Der Rückzahlungsbetrag, der erforderlich ist, um das Konto wieder auf die Liquidierungsgrenze zu bringen (
calculateDiscountedRepayToEvenAmount()), geprüft nur, wenn der MarktisSupportedist.
Schwachstellenanalyse
Die Hauptursache ist eine fehlerhafte Geschäftslogik und ein Abrechnungsfehler im Alkemi-Protokoll (0x4822...a888). Da currentBorrowBalance_TargetUnderwaterAsset notwendigerweise größer als 0 ist, solange der Kreditnehmer eine ausstehende Schuld hat, und der von calculateDiscountedBorrowDenominatedCollateral() zurückgegebene Wert ebenfalls notwendigerweise größer als 0 ist, solange der Kreditnehmer eine Kollateral hat, verlässt sich das AlkemiEarnPublic-Protokoll effektiv auf calculateDiscountedRepayToEvenAmount(), um zu bestimmen, ob ein bestimmtes Darlehen liquidiert werden kann. In dieser Funktion sollte der zu liquidierende Schuldenbetrag anhand einer Variablen namens accountShortfall_TargetUser berechnet werden.
In der tatsächlichen Implementierung verwendet die Funktion stattdessen jedoch eine globale Variable closeFactorMantissa, um eine Obergrenze für den zulässigen Rückzahlungsbetrag zu berechnen, und gibt diesen Wert zurück. Infolgedessen kann ein Angreifer seinen eigenen Kredit aufnehmen und ihn sofort innerhalb derselben Transaktion liquidieren.
Darüber hinaus zeigt sich in der Funktion liquidateBorrow(), dass die Variablen supplyBalance_TargetCollateralAsset und supplyBalance_LiquidatorCollateralAsset auf denselben Speicherplatz verweisen, wenn der Liquidator und der Kreditnehmer dieselbe Adresse haben. Die Funktion berechnet dann separat ein "reduziertes Guthaben" und ein "belohntes Guthaben" basierend auf demselben Anfangsguthaben und schreibt sie anschließend nacheinander in denselben Speicherplatz zurück. Da das reduzierte Guthaben zuerst geschrieben und das belohnte Guthaben danach geschrieben wird, geht der Reduktionseffekt verloren und es bleibt nur das belohnte Ergebnis. Dies ermöglicht es dem Angreifer, seinen Gewinn weiter zu steigern.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0xa170...6d9d.
-
Schritt 1: Der Angreifer nimmt einen Flash-Kredit von 51e18
WETHvon Balancer auf. -
Schritt 2: Der Angreifer wickelt 51e18
WETHinETHab und liefert ihn an das Alkemi-Protokoll. -
Schritt 3: Der Angreifer leiht 39,5e18
ETHvon Alkemi. -
Schritt 4: Der Angreifer liquidiert seine eigene Position mit 39,5395e18
ETH. -
Schritt 5: Der Angreifer zieht 93,5e18
ETHaus Alkemi ab. -
Schritt 6: Der Angreifer zahlt den Flash-Kredit zurück und erzielt einen Gewinn von 43,4e18
ETH.
Schlussfolgerung
Die Hauptursache ist, dass die fehlerhafte Liquidierungslogik es dem Angreifer ermöglicht, seinen eigenen Kredit aufzunehmen und dann innerhalb derselben Transaktion zu liquidieren, um einen Gewinn zu erzielen, während die fehlerhafte Abrechnungslogik die Gewinne des Angreifers weiter steigert.
Um ähnliche Risiken in Zukunft zu reduzieren:
- Für Guthabenaktualisierungen des Kreditnehmers und des Liquidators sollte das Protokoll direkt auf Speichervariablen operieren, anstatt die Guthaben in temporäre Speicher-Variablen zu kopieren, um separate Berechnungen und Rückschreibungen durchzuführen.
MT Incident
Kurze Zusammenfassung
Am 10. März 2026 wurde MT Token, ein deflationärer Token auf der BNB Chain, ausgenutzt, was zu einem Verlust von ca. 242.000 $ führte. Die Hauptursache ist eine fehlerhafte Logik zur Einschränkung des Handels in Kombination mit inkonsistenter Handhabung spezieller Transferbedingungen. Während der Deflationsphase schränkt der Vertrag Kaufoperationen ein, wenn die Poolreserve einen festen Schwellenwert überschreitet. Der Vertrag behandelt jedoch Überweisungen exakter Beträge (z. B. 2e17 MT) als Empfehlung-bindende Aktionen, wodurch der Angreifer die Kaufbeschränkung umgehen und anfängliche Token erwerben kann. Darüber hinaus stützt sich die Beschränkungslogik auf eine unvollständige Pfaderkennung (isBuy) und deckt indirekte Swap-Routen wie Pair zu Router nicht ab, während Whitelist-Prüfungen kritische Validierungen weiter verkürzen. Der Angreifer sammelte MT-Token an, ohne Beschränkungen oder Gebühren auszulösen, manipulierte pendingBurnAmount durch kontrollierte Liquiditätsoperationen und Handelsgeschäfte und zwang den Pool in einen abnormalen Zustand, in dem der Tokenpreis künstlich aufgebläht war.
Hintergrund
MT Token ist ein deflationärer Token auf der BNB Chain mit integrierten Handelsbeschränkungen. Während der Deflationsphase blockiert der Vertrag Kaufoperationen, wenn die MT-Reserve im Pool 21.000e18 überschreitet. Sobald die Reserve unter diesen Schwellenwert fällt, endet die Deflationsphase und der Kauf wird wieder ermöglicht. MT Token enthält auch einen Empfehlungsmechanismus: eine Überweisung von genau 2e17 MT oder 1e17 MT wird als empfehlungsbindende Aktion und nicht als normaler Handel behandelt.
Schwachstellenanalyse
Die Hauptursache war ein fehlerhaftes Design der Kaufbeschränkung im MT-Vertrag (0x037E...b449). Unter normalen Bedingungen sollten Angreifer während der eingeschränkten Phase keine MT als Startkapital erwerben können. Der Vertrag behandelt jedoch eine Überweisung von genau 2e17 MT als Empfehlungsbindung und nicht als Kauf, was es einem Angreifer ermöglicht, 2e17 MT zu kaufen und dabei die Kaufbeschränkung zu umgehen.
Darüber hinaus stützt sich die Handelsbeschränkung auf den isBuy-Zweig, um Käufe zu blockieren, deckt aber nicht den "Pair to Router"-Pfad ab. Da sowohl der Router als auch das Paar Whitelist-Adressen sind, umgehen solche Überweisungen bei der Whitelist-Prüfung und erreichen nie die Kaufbeschränkungslogik, wodurch ein Angreifer MT erwerben kann, indem er Käufe an den Router leitet und anschließend Token durch Entfernen von Liquidität zurückzieht.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0xfb57...fca6.
-
Schritt 1: Der Angreifer hat einen Flash-Kredit von ~358.681e18
WBNBaufgenommen. -
Schritt 2: Der Angreifer kaufte 2e17
MT, umging damit die Kaufbeschränkung. -
Schritt 3: Der Angreifer lieferte 4e12
WBNBund 2e17MTan das Paar, um Liquidität hinzuzufügen. Diese Überweisung umging aus demselben Grund wie oben die Gebührenlogik. -
Schritt 4: Der Angreifer kaufte ~10.000.000e18
MT-Token vom Paar zum Router, umging damit sowohl die Kaufbeschränkung als auch die Gebührenlogik. -
Schritt 5: Der Angreifer entfernte die Hälfte seiner Liquiditätsposition, zog dabei alle vom Router gehaltenen
MT-Token ab und verkaufte dann die zurückgewonnenenMTgegenWBNB. In diesem Schritt wurdependingBurnAmountauf etwa 9.000.000e18 manipuliert. -
Schritt 6: Der Angreifer kaufte erneut ~10.000.000e18
MT-Token, wodurch dieMT-Reserve des Pools auf ~6.756.516e18 gesenkt wurde, was unterpendingBurnAmountlag. -
Schritt 7: Der Angreifer entfernte die verbleibende Hälfte seiner Liquiditätsposition, zog die gekauften
MT-Token ab und rief danndistributeDailyRewards()auf, umMTaus dem Pool zu verbrennen. Infolgedessen wurde dieMT-Reserve auf 21.000e18 reduziert. -
Schritt 8: Der Angreifer tauschte alle
MTgegen ~1.198e18WBNBzurück, zahlte den Flash-Kredit zurück und realisierte den Gewinn.
Schlussfolgerung
Dieser Exploit wurde durch fehlerhafte Handelsbeschränkungen verursacht, die es dem Angreifer ermöglichten, das Kaufverbot zu umgehen, indem er genau BINDING_AMOUNT von MT-Token kaufte. Nach dem Erhalt von MT-Token konnte der Angreifer weiter sowohl die Gebührenlogik als auch die Kaufbeschränkung umgehen, indem er zuerst Liquidität hinzufügte, dann MT in den Router kaufte und schließlich Liquidität entfernte, um die Token zurückzufordern. Der Angreifer sammelte dann pendingBurnAmount durch Verkaufsoperationen und führte den Burn aus, um die Poolreserven in einen abnormalen Zustand zu versetzen, wodurch er MT zu einem aufgeblähten Preis verkaufen und Gewinn erzielen konnte.
Um ähnliche Risiken in Zukunft zu reduzieren:
- Erzwingen Sie eine strikte Trennung zwischen Transfersemantik und Handelslogik.
AAVE Liquidation Incident
Kurze Zusammenfassung
Am 11. März 2026 erlitt AAVE auf Ethereum 21 Millionen US-Dollar an fehlerhaften Liquidationen, was zu einem Verlust von ca. 1,01 Mio. $ führte. Die Hauptursache war ein fehlerhafter Oracle-Preis für wstETH, der dazu führte, dass ursprünglich gesunde Positionen unterbesichert wurden. Infolgedessen wurden die Positionen der Benutzer liquidiert, was zu finanziellen Verlusten führte.
Hintergrund
AAVE verwendet Oracle-Adapter, um gewickelte Assets wie wstETH zu bepreisen. Der Adapter CAPO (Capped Price Oracle) leitet den wstETH-Preis ab, indem er den Basispreis ETH/USD mit einem Umrechnungsverhältnis (getRatio(), d.h. wie viel ETH ein wstETH wert ist) multipliziert. Um eine Manipulation des Verhältnisses zu verhindern, wendet CAPO eine Snapshots-basierte Wachstumsbegrenzung an:
maxRatio = snapshotRatio + maxGrowthPerSecond x (currentTime - snapshotTimestamp)
und klemmt die Ausgabe von getRatio() während der Bepreisung ein (wenn currentRatio > maxRatio, wird maxRatio verwendet). Dieser Mechanismus begrenzt effektiv den maximalen Aufwärtsdruck des Verhältnisses und des daraus resultierenden Preises.
Schwachstellenanalyse
Die Hauptursache war ein Zeit-Verhältnis-Fehler in der CAPO-Oracle-Anchor-Konfiguration (0xe1D9...61Ef): Der Snapshot-Zeitstempel und das Snapshot-Verhältnis wurden gesetzt, aber das Snapshot-Verhältnis wurde unterhalb des tatsächlichen wstETH/ETH-Verhältnisses konfiguriert. Infolgedessen lag das vom Adapter berechnete maxRatio unter dem Live-Verhältnis und klemmte getRatio() nach unten ein, wodurch der wstETH/USD-Oracle-Preis systematisch unterbewertet wurde. Diese gedrückte Kollateralbewertung reduzierte den Gesundheitsfaktor von Positionen, die wstETH als Kollateral nutzten, wodurch ansonsten gesunde Konten fälschlicherweise als ungesund eingestuft und liquidiert wurden.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x9064...8a9c.
-
Schritt 1: Der Liquidator hat einen Flash-Kredit von ~6304e18
WETHaufgenommen und den Kreditnehmer liquidiert. -
Schritt 2: Der Liquidator zahlte den Flash-Kredit zurück und schloss damit die Liquidation ab.
Schlussfolgerung
Diese Liquidation wurde durch eine fehlerhafte Oracle-Preis-Konfiguration verursacht, die Kreditnehmer, die gesund hätten bleiben sollen, fälschlicherweise in einen ungesunden Zustand versetzte und damit die Liquidation ihrer Positionen auslöste.
Um ähnliche Risiken in Zukunft zu reduzieren:
-
Stellen Sie sicher, dass kritische Parameter vor jeder Aktualisierung auf Korrektheit überprüft werden.
-
Fügen Sie Validierungsprüfungen in der Implementierung hinzu, um fehlerhafte Parameter abzulehnen und die Anwendung fehlerhafter Konfigurationen zu verhindern.
Planet Finance Incident
Kurze Zusammenfassung
Am 11. März 2026 wurde Planet Finance auf der BNB Chain ausgenutzt, was zu einem geschätzten Verlust von ca. 10.000 $ führte. Die Hauptursache war, dass das Protokoll die Erhöhung des gespeicherten Kreditbetrags eines Kreditnehmers fälschlicherweise als aufgelaufene Zinsen behandelte, wodurch ein Angreifer wiederholt Kredite aufnehmen und eine Rabattabrechnung auslösen konnte, um seine erfasste Schuld zu unterzeichnen.
Hintergrund
Planet Finance ist ein Kreditprotokoll, das es Kreditnehmern erlaubt, mit einem Zinsrabatt zurückzuzahlen. Der Rabatt ist gestaffelt und wird durch das Verhältnis zwischen dem gestakten GAMMA eines Benutzers und seinem gestakten Wert in anderen Assets bestimmt: Je höher dieses Verhältnis, desto höher der Rückzahlungsrabatt. Der Rabattplan umfasst drei Stufen, die von 0 % (minimum) bis 50 % (maximum) reichen.
Schwachstellenanalyse
Die Hauptursache war, dass das Protokoll (0x4c9E...F467) bei der Abrechnung des Kreditnehmer-Rabattes in changeUserBorrowDiscount() fälschlicherweise die Erhöhung des gespeicherten Kreditbetrags des Kreditnehmers als neu aufgelaufene Zinsen behandelte. Infolgedessen wurde der Rabatt, der nur für aufgelaufene Zinsen gelten sollte, fälschlicherweise auf das neu aufgenommene Kapital angewendet, wodurch die erfasste Schuld des Kreditnehmers ordnungswidrig reduziert wurde. Ein Angreifer konnte wiederholt die Schleife borrow und dann changeUserBorrowDiscount durchführen, um übermäßige Rabatte anzuhäufen, was dazu führte, dass die On-Chain erfasste Verbindlichkeit durchweg niedriger war als der tatsächlich aufgenommene Betrag, und letztendlich aus der Diskrepanz Profit zu schlagen.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x5f45...5ec9.
-
Schritt 1: Der Angreifer hat einen Flash-Kredit von 200.000e18
USDTaufgenommen. -
Schritt 2: Der Angreifer verwendete 5.000e18
USDT, umWBNBzu kaufen, und verwendete dann das erworbeneWBNB, um ~8.726.524e18GAMMAzu kaufen. -
Schritt 3: Der Angreifer setzte zuerst das gesamte erworbene
GAMMAin den gGAMMA-Markt, lieferte dann den verbleibendenUSDTals Kollateral, was seinen Rückzahlungsrabatt auf 5 % erhöhte und die nachfolgende Kreditaufnahme ermöglichte. -
Schritt 4: Der Angreifer rief wiederholt
borrowund dannupdateUserDiscountauf, um seine erfasste Schuld kontinuierlich zu reduzieren. -
Schritt 5: Der Angreifer zahlte schließlich die Schuld zurück, löste die Kollateral ein und realisierte den Gewinn.
Schlussfolgerung
Dieser Vorfall wurde durch die fehlerhafte Rabattabrechnungslogik von Planet Finance in changeUserBorrowDiscount() verursacht, die fälschlicherweise die Erhöhung des gespeicherten Kreditbetrags eines Kreditnehmers als neu aufgelaufene Zinsen behandelt und den Zinsrabatt auf diese Differenz anwendet. Ein Angreifer kann wiederholt borrow gefolgt von updateUserDiscount aufrufen, um seine erfasste Schuld zu unterschätzen und letztendlich weniger zurückzuzahlen als die tatsächliche Verbindlichkeit, um Profit zu ziehen.
Um ähnliche Risiken in Zukunft zu reduzieren:
- Unterscheiden Sie Zinsen und neue Kredite im Kreditprotokoll.
AM Incident
Kurze Zusammenfassung
Am 12. März 2026 wurde AM Token, ein deflationärer Token auf der BNB Chain, mit einem geschätzten Verlust von ca. 131.000 $ ausgenutzt. AM Token implementiert einen deflationären Mechanismus, bei dem jeder Verkauf eine zusätzliche Verbrennung aus dem Liquiditätspool auslöst, wodurch Token dauerhaft entfernt werden, um das Gesamtangebot zu reduzieren. Die Verbrennung wird jedoch nicht sofort ausgeführt - stattdessen wird der gesamte Verkaufsbetrag als toBurnAmount erfasst und die tatsächliche Verbrennung auf den nächsten Verkauf verschoben. Diese Verzögerung schafft ein Zeitfenster zwischen Erfassung und Ausführung, in dem ein Angreifer AM zurückkaufen kann, um die AM-Reserve des Pools auf toBurnAmount zu reduzieren. Wenn der nächste Verkauf die verschobene Verbrennung auslöst, wird die gesamte AM-Reserve ausgelöscht, was den Preis auf ein extremes Niveau treibt und es dem Angreifer ermöglicht, AM gewinnbringend zu verkaufen.
Hintergrund
AM Token ist ein deflationärer Token auf der BNB Chain. Bei jedem Verkauf erfasst der Vertrag den am Tausch beteiligten AM-Betrag als toBurnAmount und verbrennt diesen erfassten Betrag während des nächsten Verkaufs aus dem Liquiditätspool. Effektiv lösen Verkäufe eine verzögerte Verbrennung aus, die die AM-Reserve des Pools schrumpfen lässt. Darüber hinaus tauscht das Protokoll, bevor es die Verbrennung ausführt, den angesammelten totalTokenFee in USDT und verteilt ihn gemäß seiner Gebührenallokationslogik.
Schwachstellenanalyse
Die Hauptursache war, dass die Verkaufslogik des Tokens (0x27f9...213f) den gesamten getauschten AM-Betrag als toBurnAmount ansammelt und die Verbrennung erst beim nächsten Verkauf durchführt, indem Token aus dem AM/USDT-Paar entfernt und pair.sync() aufgerufen werden, um die Reserven zu aktualisieren. Dieses Design ermöglicht es einem Angreifer, die AM-Reserven des Pools zu manipulieren, den On-Chain-Preis zu verzerren und durch Arbitrage Gewinn zu erzielen.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0xd0d1...f859.
-
Schritt 1: Der Angreifer hat einen Flash-Kredit von ~27.265.119e18
USDCund ~361.710e18WBNBaufgenommen und sie dann gegen ~100.423.811e18USDTgetauscht. -
Schritt 2: Der Angreifer tauschte ~5.062e18
AM-Token gegenUSDT, was den erfasstentoBurnAmountdes Vertrags auf ~4.303e18 manipulierte. -
Schritt 3: Der Angreifer tauschte
USDTgegen AM Token, wodurch dieAM-Reserve des Pools auf ~4.303e18 gesenkt wurde. -
Schritt 4: Der Angreifer übertrug 6 wei
AMan den Pool, was die Verkaufs-Pfad-Verbrennungslogik auslöste. Infolgedessen verbrannte der Vertrag den gesamtenAM-Bestand aus dem Pool, wodurch dieAM-Reserve auf 0 sank. Hinweis: Das Protokoll versucht zuerst, die angesammelten Gebühren inUSDTzu tauschen, bevor die Verbrennung erfolgt. Dieser Gebührenumrechnungspfad löst ebenfalls die Verkaufs-Pfad-Verbrennungslogik aus. Nachdem die Verbrennung ausgeführt wurde und dieAM-Reserve 0 erreicht, schlägt der Gebührentausch fehl. Da er in einem Try/Catch-Block eingekapselt ist, schlägt die Transaktion nicht fehl. Stattdessen wird die Ausführung fortgesetzt und der Gebührenakkumulator auf 0 zurückgesetzt. -
Schritt 5: Der Angreifer rief
pool.sync()auf und übertrug die verbleibendenUSDTund 1 weiAMin den Pool. Da beide Token gleichzeitig übertragen wurden, behandelte der Vertrag dies alsaddLiquidity, so dasstoBurnAmountnicht angesammelt wurde. DieAM-Reserve wurde auf 7 aktualisiert. -
Schritt 6: Der Angreifer tauschte die verbleibenden
AM-Token gegenUSDT. Während dieses Tauschs löste die Übertragung vonAMin das Paar die Verkaufs-Pfad-Verbrennungslogik aus und reduzierte dieAM-Reserve auf 1. DatotalFeeAmountin Schritt 4 auf 0 zurückgesetzt worden war, wurde die Gebühr-zu-USDT-Konvertierung nicht mehr ausgeführt, wodurch der AngreiferAMzu einem künstlich aufgeblähten Preis verkaufen konnte. -
Schritt 7: Der Angreifer zahlte den Flash-Kredit zurück und realisierte den verbleibenden Gewinn.
Schlussfolgerung
Dieser Vorfall wurde durch den fehlerhaften Verbrennungsmechanismus von AM Token verursacht, der den von jedem Verkauf betroffenen AM-Betrag als toBurnAmount ansammelt und diesen Betrag dann beim nächsten Verkauf aus dem AM/USDT-Paar verbrennt, während pool.sync() aufgerufen wird. Dies ermöglicht es einem Angreifer, die AM-Reserven des Paares auf ein extremes Niveau zu manipulieren und AM zu einem künstlich aufgeblähten Preis zu verkaufen, um USDT abzuschöpfen.
Um ähnliche Risiken in Zukunft zu reduzieren:
- Begrenzen Sie den maximalen Verbrennungsbetrag pro Transaktion und begrenzen Sie die Häufigkeit, mit der eine Verbrennung ausgelöst werden kann, um zu verhindern, dass Angreifer einen großen Teil der Token-Reserven des Pools in kurzer Zeit verbrauchen.
DBXen Incident
Kurze Zusammenfassung
Am 12. März 2026 wurde DBXen, ein Burn-to-Earn-Protokoll auf Ethereum und BNB Chain, mit einem Gesamtschaden von ca. 149.000 $ ausgenutzt. Die Hauptursache war eine Inkonsistenz zwischen _msgSender() und msg.sender. Wenn burnBatch() über den forwarder aufgerufen wird, wird der verbrannte XEN-Betrag unter _msgSender() (vom Angreifer kontrolliert) erfasst, aber die Zykluserfassung wird auf msg.sender (dem forwarder) aktualisiert. Diese Trennung ermöglicht es dem Angreifer, Prämien und Gebühren gegen veraltete Zyklusdatensätze zu beanspruchen, was zu ungewöhnlich hohen Auszahlungen führt.
Hintergrund
DBXen ist ein Burn-to-Earn-Protokoll: Benutzer verbrennen XEN-Token im Austausch gegen DXN-Belohnungen und einen Anteil an angesammelten Protokollgebühren. Der Schlüsselmechanismus funktioniert in Zyklen. Wenn ein Benutzer burnBatch() aufruft, geschehen zwei Dinge: (1) der verbrannte XEN-Betrag wird unter der Adresse des Aufrufers (identifiziert durch _msgSender()) erfasst, und (2) der XEN-Vertrag ruft DBXen über onTokenBurned() zurück, um die Zyklusdatensätze des Aufrufers (Burn-Zyklus und lastFeeUpdateCycle) auf den aktuellen Zyklus zu aktualisieren.
Belohnungen und Gebühren werden über updateStats() abgerechnet. Die Belohnung ist proportional zum Anteil des Benutzers am gesamten in seinem Burn-Zyklus verbrannten XEN. Die Gebühr basiert auf den kumulativen Protokollgebühren, die seit dem letzten erfassten Zyklus des Benutzers angefallen sind. Beide Berechnungen hängen davon ab, dass die Zyklusdatensätze des Benutzers auf dem neuesten Stand sind.
Schwachstellenanalyse
Die Hauptursache ist eine fehlerhafte Geschäftslogik im DBXen-Protokoll (0xf5c8...2abd). Die Funktion _msgSender() prüft, ob msg.sender der forwarder ist. Wenn ja, gibt sie die letzten 20 Bytes von calldata zurück, und dieser zurückgegebene Wert kann im forwarder-Kontext beliebig gesteuert werden. Die Funktion burnBatch() verbrennt jedoch direkt das von msg.sender gehaltene XEN. Infolgedessen kann ein Angreifer burnBatch() über den forwarder aufrufen, wodurch das Protokoll das vom forwarder gehaltene XEN verbrennt und die Burn-Zyklus- und Gebühren-Update-Zyklusdatensätze des forwarder auf den aktuellen Zyklus aktualisiert. Gleichzeitig erfasst das Protokoll jedoch den verbrannten XEN-Betrag unter der Adresse, die _msgSender() entspricht.
Danach ruft der Angreifer claimFees() auf, was updateStats() aufruft. Da die Zyklusdatensätze der _msgSender()-Adresse nie aktualisiert wurden (sowohl Burn-Zyklus als auch lastFeeUpdateCycle bleiben bei 0), berechnet updateStats() die Belohnungen im aktuellen Zyklus und berechnet die seit Zyklus 0 angefallenen Gebühren - die gesamte Gebührenhistorie des Protokolls abdeckend. Der Angreifer profitiert dann, indem er claimFees() und claimRewards() aufruft.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x914a5a...b808bc37.
-
Schritt 1: Der Angreifer rief zuerst die Funktion
registerDomainSeparator()desForwarder-Vertrags auf und ermöglichte damit nachfolgende Aufrufe anForwarder.execute(). -
Schritt 2: Der Angreifer tauschte 0,14e18
ETHgegen 13.900.000.000e18XENin einem Uniswap V2-Pool. -
Schritt 3: Der Angreifer übertrug 13.900.000.000e18
XENan denForwarder-Vertrag. -
Schritt 4: Der Angreifer nutzte
Forwarder.execute(), um DBXen zu genehmigen, die13.900.000.000e18XENdesForwarderauszugeben. -
Schritt 5: Der Angreifer nutzte
Forwarder.execute(), umDBXen.burnBatch()aufzurufen und verbrannte 13.900.000.000e18XEN. Der Burn-Betrag wurde unter der Adresse0x425D3eC2DCeBE2c04bA1687504D43AFC6be7328derfasst, während während der Burn-AusführungXENüberonTokenBurned()zurück inDBXenrief und die relevanten Zyklusdaten auf demForwarderaktualisierte.
-
Schritt 6: Der Angreifer nutzte
Forwarder.execute(), umDBXen.claimFees()aufzurufen und erhielt 65,36e18ETH. -
Schritt 7: Der Angreifer nutzte
Forwarder.execute(), umDBXen.claimRewards()aufzurufen und prägte 2.305,4e18DXN.
Schlussfolgerung
Die Hauptursache dieses Vorfalls war, dass das DBXen-Protokoll _msgSender() und msg.sender inkonsistent verwendete. Da diese beiden Werte unterschiedlich sein konnten, wurde die interne Buchhaltung des Protokolls inkonsistent, was es dem Angreifer ermöglichte, die Diskrepanz gewinnbringend auszunutzen.
Um ähnliche Risiken in Zukunft zu reduzieren:
- Verwenden Sie
_msgSender()konsistent in allen Logikpfaden oder stellen Sie sicher, dassmsg.sender-abhängige Operationen und_msgSender()-abhängige Buchhaltungen immer dieselbe Adresse referenzieren.
Goose Finance Incident
Kurze Zusammenfassung
Am 15. März 2026 wurde Goose Finance, ein Yield-Farming-Protokoll auf der BNB Chain, für etwa 8.000 $ ausgenutzt. Die Hauptursache war ein Fehler in der Share-Pricing-Reihenfolge in StrategyGooseEgg: deposit() prägt Shares, bevor die geernteten Erträge in die Buchhaltung übernommen werden, so dass der für das Share-Pricing verwendete Gesamtvermögensnenner diese Erträge ausschließt und niedriger ist als der tatsächliche Wert. Dies bedeutet, dass Einleger mehr Shares erhalten, als sie sollten. Wenn withdraw() aufgerufen wird, löst es eine Ertrags-Ernte aus, die das Gesamtvermögen erhöht und jeden Share wertvoller macht. Durch das Schleifen von Deposit und Withdraw in einer einzigen Transaktion prägte der Angreifer wiederholt überteuerte Shares und löste sie zum korrigierten (höheren) Wert ein, wobei die Differenz als Gewinn entnommen wurde.
Hintergrund
Goose Finance ist ein Yield-Farming-Protokoll auf der BNB Chain, bei dem Benutzergelder von einem Vault in eine Strategie fließen, die Assets im MasterChef staket, um EGG-Belohnungen zu verdienen.
Die für diesen Vorfall relevanten Komponenten sind:
-
VaultChef(0x3f64...): verfolgt Benutzerpositionen und leitet Kapital anStrategyGooseEggweiter. -
StrategyGooseEgg(0x0980...): verwaltet die Buchhaltung auf Strategieebene mitsharesTotalundwantLockedTotal. -
MasterChef(0xe70e...): empfängt gestakte Assets und zahltEGG-Belohnungen. -
WrappedEgg(0xb815...): wickeltEGG1:1 inWEGGzum Staking ein.
Operationell werden Einlagen vom VaultChef an StrategyGooseEgg geleitet, dann im MasterChef gestaket. Abhebungen werden vom VaultChef initiiert und von der Strategie ausgeführt.
Eine wichtige buchhalterische Erwartung ist, dass die Share-Preisgestaltung die Gesamtstrategie-Assets zum Zeitpunkt der Preisgestaltung widerspiegeln sollte (gestaktes Kapital plus im Ruhezustand befindliche Erträge, die bereits von der Strategie gehalten werden). In StrategyGooseEgg prägt deposit() jedoch Shares, bevor _farm() im Ruhezustand befindliche Erträge in wantLockedTotal verrechnet. withdraw() kann eine Ertrags-Ernte vom MasterChef auslösen. Diese Reihenfolge ist die Grundlage für die nachfolgend analysierte Schwachstelle.
Schwachstellenanalyse
Die Hauptursache ist eine Abrechnungsdesynchronisation in StrategyGooseEgg (0x0980...b26b) zwischen Ertrags-Ernte und Share-Preisgestaltung.
In StrategyGooseEgg verwendet die Share-Preisgestaltung wantLockedTotal als Nenner: shares = deposit * sharesTotal / wantLockedTotal. Damit dies fair ist, muss wantLockedTotal alle Assets widerspiegeln, die die Strategie tatsächlich hält, einschließlich aller im Ruhezustand befindlichen EGG-Erträge im Vertrag. deposit() prägt jedoch Shares, bevor _farm() im Ruhezustand befindliche Erträge in wantLockedTotal verrechnet. Dies bedeutet, dass der Nenner nicht erfasste Erträge ausschließt und niedriger ist als die tatsächlichen Gesamtvermögenswerte, wodurch der Einleger mehr Shares erhält, als er sollte.
Darüber hinaus ruft withdraw() MasterChef.withdraw() auf, was das gestakte Kapital zuzüglich ausstehender EGG-Erträge an die Strategie zurückgibt. Die Buchhaltung der Strategie zieht nur den angeforderten _wantAmt von wantLockedTotal ab, so dass die geernteten Erträge im Bestand der Strategie verbleiben, ohne in wantLockedTotal reflektiert zu werden. Dies vergrößert die Lücke zwischen den tatsächlich gehaltenen Assets und dem erfassten wantLockedTotal, wodurch jede nachfolgende deposit()-Share-Preisgestaltung noch ungenauer wird.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x86efdf...ce316223.
-
Schritt 1: Der Angreifer hat
EGGaus zwei Pancake-Paaren per Flash-Kredit geliehen. -
Schritt 2: Erste Einzahlung in
VaultChef/StrategyGooseEgg(10.170.000e18EGG). -
Schritt 3: Die erste Auszahlung (
12.593.884e18EGG) erntet Erträge vomMasterChef; 359.561e18EGGwerden anStrategyGooseEggübertragen und bleiben als im Ruhezustand befindlicher/nicht erfasster Wert (R > 0). -
Schritt 4: Die zweite Einzahlung verwendet das abgehobene Kapital (
12.593.884e18EGG) wieder. Shares werden bepreist, bevor der im Ruhezustand befindliche Wert verrechnet wird, dies ist also der Schritt der Überprägung. -
Schritt 5: Die zweite Auszahlung (
12.826.027e18EGG) realisiert Gewinne aus überprägten Shares (d. h. 232.143EGGüber dem Einzahlungsbetrag von Schritt 4). -
Schritt 6: Der Angreifer zahlte Flash-Swaps zurück und behielt die Netto-Differenz.
Schlussfolgerung
Der Exploit ergibt sich aus einem Fehler in der Share-Preisgestaltung in StrategyGooseEgg: deposit() prägt Shares, bevor _farm() wantLockedTotal aktualisiert, während withdraw() Erträge vom MasterChef ernten kann, die vorübergehend im Ruhezustand und nicht erfasst bleiben. Dies ermöglicht es Einzahlungen, gegen einen veralteten Nenner zu prägen und später gegen aktualisierte Vermögenswerte abzuheben.
Um ähnliche Risiken in Zukunft zu reduzieren:
-
Verrechnen Sie Erträge und aktualisieren Sie die Buchhaltung vor allen Berechnungen von Share-Mint und Share-Burn.
-
Bepreisen Sie Shares mit einer einzigen
totalAssets(gestaket + im Ruhezustand) zum exakten Berechnungspunkt. -
Fügen Sie Invariantentests für
shares_minted <= D * S / (A + R)unter Bedingungen mit nicht-null Erträgen im Ruhezustand hinzu.
Über BlockSec
BlockSec ist ein Anbieter von Blockchain-Sicherheit und Krypto-Compliance aus einer Hand. Wir entwickeln Produkte und Dienstleistungen, die Kunden bei der Durchführung von Code-Audits (einschließlich Smart Contracts, Blockchain und Wallets), der Echtzeit-Abwehr von Angriffen, der Analyse von Vorfällen, der Rückverfolgung illegaler Gelder und der Erfüllung von AML/CFT-Verpflichtungen über den gesamten Lebenszyklus von Protokollen und Plattformen hinweg unterstützen.
BlockSec hat mehrere Blockchain-Sicherheitsarbeiten auf renommierten Konferenzen veröffentlicht, mehrere Zero-Day-Angriffe auf DeFi-Anwendungen gemeldet, mehrere Hacking-Angriffe blockiert, um mehr als 20 Millionen Dollar zu retten, und Milliarden von Kryptowährungen gesichert.
-
Offizielle Website: https://blocksec.com/
-
Offizieller Twitter-Account: https://twitter.com/BlockSecTeam



