Während der letzten Woche (09.03.2026 - 15.03.2026) hat BlockSec acht Angriffsvorfälle erkannt und analysiert, mit geschätzten Gesamtschäden von ~1,66 Mio. USD. Die nachstehende Tabelle fasst diese Vorfälle zusammen, und detaillierte Analysen für jeden Fall werden in den folgenden Unterabschnitten aufgeführt.
| Datum | Vorfallsbeschreibung | Typ | Geschätzter Schaden |
|---|---|---|---|
| 09.03.2026 | EtherFreakers Vorfall | Fehlerhafte Geschäftslogik | ~$25K |
| 10.03.2026 | Alkemi Vorfall | Fehlerhafte Geschäftslogik | ~$89K |
| 10.03.2026 | MT Vorfall | Fehlerhafte Geschäftslogik | ~$242K |
| 11.03.2026 | AAVE Liquidationsvorfall | Fehlkonfiguration | ~$1,01 Mio. |
| 11.03.2026 | Planet Finance Vorfall | Fehlerhafte Geschäftslogik | ~$10K |
| 12.03.2026 | AM Vorfall | Fehlerhafte Geschäftslogik | ~$131K |
| 12.03.2026 | DBXen Vorfall | Fehlerhafte Geschäftslogik | ~$149K |
| 15.03.2026 | Goose Finance Vorfall | Fehlerhafte Geschäftslogik | ~$8K |
EtherFreakers Vorfall
Kurze Zusammenfassung
Am 9. März 2026 wurde EtherFreakers, ein NFT-Spiel auf Ethereum, aufgrund falscher doppelter Zählung ausgenutzt, was zu einem Verlust von ~25.000 USD führte. Jedes NFT im Spiel hat 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, überträgt aber das NFT, bevor seine Buchführung abgerechnet wird. 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 nutzte diese Erfassungsmechanik wiederholt aus, um den globalen Index zu steigern und dann das aufgeblähte Guthaben von einer Reihe von NFTs abzuziehen.
Hintergrund
EtherFreakers ist ein On-Chain-NFT-Spiel, bei dem jedes NFT (genannt "Freaker") ein abhebbares ETH-Guthaben namens energy besitzt. Das System funktioniert wie ein Dividendenpool: Wenn bestimmte Aktionen stattfinden, wird ein Bruchteil von ETH proportional an alle Freaker verteilt. Das abhebbare ETH jedes Freakers wird von einem globalen Akkumulator freakerIndex in Kombination mit einem Pro-Token-Anteilsgewicht fortune verfolgt.
Konkret lautet die Abrechnungsformel: 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 sollten Erhöhungen von freakerIndex immer durch reale Ether-Zuflüsse gedeckt sein. Wenn freakerIndex ohne entsprechende ETH-Zuflüsse wächst, können Freaker mehr Ether einlösen, als der Vertrag tatsächlich hält.
Schwachstellenanalyse
Die Grundursache 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) als direkte ETH-Überweisung an den Verteidiger aus. 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 Spiel-Logik 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 weiterhin das Guthaben vor der Auszahlung, und ein Teil der bereits ausgegebenen Energie wird in den Dividendenpool eingespeist. Sowohl die direkte ETH-Auszahlung in Schritt 1 als auch die Pool-Einspeisung in Schritt 2 stammen aus derselben Energie, wodurch freakerIndex ohne neue ETH-Deckung aufgebläht wird.
freakerIndex wächst, wann immer _dissipateEnergyIntoPool() aufgerufen wird:
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x89e24d...9abd2942.
-
Schritt 1: Borrows
1.700WETH. -
Schritt 2: Mintet zwei neue Freaker, Token
590und Token591, unter der Kontrolle des Angreifers. -
Schritt 3: Ruft wiederholt die Spielfunktion
attack(590, 591)auf und hält die Ausführungen im erfolgreichen Erfassungszweig. -
Schritt 4: Nach jeder erfolgreichen Erfassung wird Token
591zurück an den Helfer übertragen, damit dasselbe Paar wiederverwendet werden kann. -
Schritt 5: Jede erfolgreiche Schleife erhöht
freakerIndexüber den tatsächlich vom System gespeicherten Ether hinaus. -
Schritt 6: Sobald der Index hoch genug ist, wird eine Charge von zuvor kontrollierten Freakern entladen. Die Token-IDs
496bis520werden jeweils für0,278052246002402082Ether entladen. -
Schritt 7: Wrappt den abgezogenen Ether in
WETH, zahlt den Flash-Loan von1.700WETHzurück und behält etwa7,498WETHals Gewinn.
Schlussfolgerung
Die Grundursache liegt im erfolgreichen Erfassungsfluss von attack(): EtherFreakers zahlt targetCharge aus, bevor der Energiezustand des Ziel-Tokens abgerechnet ist. _transfer() löst dann _beforeTokenTransfer() aus, das veraltete energyOf(targetId) vor der Auszahlung liest und einen Teil davon in den Pool einspeist. Dies erhöht freakerIndex ohne neue Ether-Deckung, sodass dieselbe Zielenergie sowohl als Auszahlung als auch als Pool-Einspeisung gezählt wird. Dies ist ein Inflationsfehler der Geschäftslogik, kein Reentrancy-Fehler.
Um ähnliche Risiken zukünftig zu reduzieren:
-
Vermeiden Sie die Neuberechnung wirtschaftlicher Werte aus veränderlichem Zustand innerhalb von Transfer-Hooks, während dieselbe Transaktion noch abgerechnet wird.
-
Wenn der Transfer-Hook eine Zustandsvariable liest, stellen Sie sicher, dass die Ausführungsreihenfolge das Ergebnis nicht beeinflusst (z. B. den Zustand vor dem Ausführen des Hooks abgleichen, nicht danach).
Alkemi Vorfall
Kurze Zusammenfassung
Am 10. März 2026 wurde das Alkemi-Protokoll auf Ethereum ausgenutzt, was zu einem Verlust von ~89.000 USD führte. Die Grundursache ist ein Abrechnungsfehler und eine fehlerhafte Geschäftslogik. Die fehlerhafte Liquidationslogik ermöglicht es jedem, seine eigene Position innerhalb derselben Transaktion zu liquidieren und davon zu profitieren. Darüber hinaus verursacht ein Abrechnungsfehler, dass die Belastung des eigenen Kollaterals des Angreifers während der Liquidation überschrieben wird, wodurch der Angreifer Liquidationsprämien erhalten kann, ohne die beabsichtigten Kosten zu tragen.
Hintergrund
Alkemi ist ein Kreditprotokoll. Wenn die Position eines Kreditnehmers unterkollateralisiert wird, kann jeder liquidateBorrow() aufrufen, um einen Teil der Schulden zurückzuzahlen und Kollateral mit einem Rabatt zu beschlagnahmen. Um übermäßige Liquidierung zu verhindern, begrenzt das Protokoll den pro Transaktion zurückzahlbaren Betrag auf das Minimum von drei Werten:
- Der aktuelle Kreditbetrag des Kreditnehmers (
currentBorrowBalance_TargetUnderwaterAsset). - Die maximale Rückzahlung, die das Kollateral des Kreditnehmers nach Anwendung des Liquidationsrabatts abdecken kann (
calculateDiscountedBorrowDenominatedCollateral()). - Der Rückzahlungsbetrag, der erforderlich ist, um das Konto wieder an die Liquidationsgrenze zu bringen (
calculateDiscountedRepayToEvenAmount()), nur geprüft, wenn der MarktisSupportedist.
Schwachstellenanalyse
Die Grundursache 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 Wert, der von calculateDiscountedBorrowDenominatedCollateral() zurückgegeben wird, ebenfalls notwendigerweise größer als 0 ist, solange der Kreditnehmer Kollateral besitzt, 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 jedoch stattdessen eine globale Variable closeFactorMantissa, um eine Obergrenze für den Betrag der erlaubten Schuldenrückzahlung zu berechnen, und gibt diesen Wert zurück. Infolgedessen kann ein Angreifer leihen und seine eigene Position innerhalb derselben Transaktion sofort liquidieren.
Darüber hinaus werden in der Funktion liquidateBorrow() die Variablen supplyBalance_TargetCollateralAsset und supplyBalance_LiquidatorCollateralAsset auf denselben Speicherplatz verweisen, wenn der Liquidator und der Kreditnehmer dieselbe Adresse haben. Die Funktion berechnet dann getrennt einen "reduzierten Saldo" und einen "belohnten Saldo" auf der Grundlage desselben Anfangssaldos und schreibt diese anschließend nacheinander in denselben Speicherplatz zurück. Da der reduzierte Saldo zuerst geschrieben und der belohnte Saldo danach, wird der Reduktionseffekt überschrieben und geht verloren, wobei nur das belohnte Ergebnis übrig bleibt. 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-Loan von
51e18WETHvon Balancer auf. -
Schritt 2: Der Angreifer entpackt
51e18WETHinETHund zahlt diesen in das Alkemi-Protokoll ein. -
Schritt 3: Der Angreifer leiht sich
39,5e18ETHvon Alkemi. -
Schritt 4: Der Angreifer liquidiert seine eigene Position mit
39,5395e18ETH. -
Schritt 5: Der Angreifer zieht
93,5e18ETHvon Alkemi ab. -
Schritt 6: Der Angreifer zahlt den Flash-Loan zurück und erzielt einen Gewinn von
43,4e18ETH.
Schlussfolgerung
Die Grundursache liegt darin, dass die fehlerhafte Liquidationslogik es dem Angreifer ermöglicht, zu leihen und dann seine eigene Position innerhalb derselben Transaktion zu liquidieren, um einen Gewinn zu erzielen, während die falsche Buchhaltungslogik die Gewinne des Angreifers weiter steigert.
Um ähnliche Risiken zukünftig zu reduzieren:
- Für Saldoaktualisierungen des Kreditnehmers und des Liquidators sollte das Protokoll direkt auf Speicher variablen operieren, anstatt die Salden in temporäre Speicher variablen zu kopieren, um sie separat zu berechnen und zurückzuschreiben.
MT Vorfall
Kurze Zusammenfassung
Am 10. März 2026 wurde der MT Token, ein deflationärer Token auf BNB Chain, ausgenutzt, was zu einem Verlust von ~242.000 USD führte. Die Grundursache ist eine fehlerhafte Logik zur Handelsbeschränkung in Kombination mit einer inkonsistenten Handhabung von speziellen Transferbedingungen. Während der Deflationsphase beschränkt der Vertrag Kaufoperationen, wenn die Pool-Reserve einen festen Schwellenwert überschreitet. Die Überweisungen exakter Beträge (z. B. 2e17 MT) werden jedoch als auf Empfehlungsgeber bezogene Aktionen behandelt, wodurch der Angreifer die Kaufbeschränkung umgehen und anfängliche Token erwerben kann. Darüber hinaus beruht die Beschränkungslogik auf einer unvollständigen Pfaderkennung (isBuy) und deckt keine indirekten Swap-Routen wie Pair zu Router 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 Trades und zwang den Pool in einen abnormalen Zustand, in dem der Tokenpreis künstlich aufgebläht wurde.
Hintergrund
MT Token ist ein deflationärer Token auf 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 aktiviert. MT Token beinhaltet auch einen Empfehlungsmechanismus: Eine Überweisung von exakt 2e17 MT oder 1e17 MT wird als auf Empfehlungsgeber bezogene Aktion behandelt und nicht als normaler Handel.
Schwachstellenanalyse
Die Grundursache 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 exakt 2e17 MT als auf Empfehlungsgeber bezogene Aktion und nicht als Kauf, was es einem Angreifer ermöglicht, 2e17 MT zu kaufen und dabei die Kaufbeschränkung zu umgehen.
Zusätzlich stützt sich die Handelsbeschränkung auf den isBuy-Zweig, um Käufe zu blockieren, deckt aber nicht den "Pair zu Router"-Pfad ab. Da sowohl Router als auch Pair Whitelist-Adressen sind, werden solche Überweisungen bei der Whitelist-Prüfung verkürzt und erreichen niemals die Kaufbeschränkungslogik, wodurch es einem Angreifer ermöglicht wird, MT zu erwerben, indem er Käufe zum Router leitet und anschließend Token durch Entfernen von Liquidität zurück zu sich selbst zieht.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0xfb57...fca6.
-
Schritt 1: Der Angreifer hat
~358.681e18WBNBim Flash-Loan aufgenommen. -
Schritt 2: Der Angreifer kaufte
2e17MTund umging damit die Kaufbeschränkung. -
Schritt 3: Der Angreifer zahlte
4e12WBNBund2e17MTan das Pair ein, um Liquidität hinzuzufügen. Diese Überweisung umging aus demselben Grund die Gebührenlogik. -
Schritt 4: Der Angreifer kaufte
~10.000.000e18MT-Token vom Pair zum Router und umging damit sowohl die Kaufbeschränkung als auch die Gebührenlogik. -
Schritt 5: Der Angreifer zog die Hälfte seiner Liquiditätsposition ab, entnahm dabei alle vom Router gehaltenen
MT-Token und verkaufte dann die zurückgewonnenenMTgegenWBNB. In diesem Schritt wurdependingBurnAmountauf etwa9.000.000e18manipuliert. -
Schritt 6: Der Angreifer kaufte erneut
~10.000.000e18MT-Token und senkte damit dieMT-Reserve des Pools auf~6.756.516e18, was unterpendingBurnAmountlag. -
Schritt 7: Der Angreifer zog die restliche Hälfte seiner Liquiditätsposition ab, hob die gekauften
MT-Token ab und rief danndistributeDailyRewards()auf, umMTaus dem Pool zu verbrennen. Infolgedessen wurde dieMT-Reserve auf21.000e18reduziert. -
Schritt 8: Der Angreifer tauschte alle
MTzurück gegen~1.198e18WBNB, zahlte den Flash-Loan zurück und schloss den Gewinn ab.
Schlussfolgerung
Dieser Exploit wurde durch falsche Handelsbeschränkungen verursacht, die es dem Angreifer ermöglichten, das Kaufverbot zu umgehen, indem er exakt BINDING_AMOUNT MT-Token kaufte. Nach dem Erwerb von MT-Token konnte der Angreifer 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ückzuerhalten. Der Angreifer sammelte dann pendingBurnAmount durch Verkaufsoperationen und führte die Verbrennung durch, um die Pool-Reserven in einen abnormalen Zustand zu versetzen, wodurch er MT zu einem aufgeblähten Preis verkaufen und profitieren konnte.
Um ähnliche Risiken zukünftig zu reduzieren:
- Strikte Trennung zwischen Transfer-Semantik und Handelslogik erzwingen.
AAVE Liquidationsvorfall
Kurze Zusammenfassung
Am 11. März 2026 erlitt AAVE bei fehlerhaften Liquidationen auf Ethereum einen Schaden von 21 Millionen USD, was zu einem Verlust von ~1,01 Millionen USD führte. Die Grundursache war ein falscher Orakelpreis für wstETH, der dazu führte, dass ursprünglich gesunde Positionen unterkollateralisiert wurden. Infolgedessen wurden die Positionen der Benutzer liquidiert, was zu finanziellen Verlusten führte.
Hintergrund
AAVE verwendet Orakeladapter zur Preisbildung von gewickelten Vermögenswerten wie wstETH. 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 die Manipulation des Verhältnisses zu verhindern, wendet CAPO eine Snapshot-basierte Wachstumsbegrenzung an:
maxRatio = snapshotRatio + maxGrowthPerSecond x (currentTime - snapshotTimestamp)
und begrenzt die Ausgabe von getRatio(). Dieser Mechanismus begrenzt effektiv die maximale Aufwärtsentwicklung des Verhältnisses und des resultierenden Preises.
Schwachstellenanalyse
Die Grundursache war ein Zeit-Verhältnis-Mismatch in der CAPO-Orakel-Ankerkonfiguration (0xe1D9...61Ef): Der Snapshot-Zeitstempel und das Snapshot-Verhältnis wurden festgelegt, aber das Snapshot-Verhältnis wurde unterhalb des tatsächlichen wstETH/ETH-Verhältnisses konfiguriert. Infolgedessen fiel das vom Adapter berechnete maxRatio unter das Live-Verhältnis und begrenzte getRatio() nach unten, was den wstETH/USD-Orakelpreis systematisch unterbewertete. 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 mit einem Flash-Loan
~6304e18WETHaufgenommen und den Kreditnehmer liquidiert. -
Schritt 2: Der Liquidator hat den Flash-Loan zurückgezahlt und die Liquidation abgeschlossen.
Schlussfolgerung
Diese Liquidation wurde durch eine falsche Orakelpreis-Konfiguration verursacht, die Kreditnehmer, die gesund geblieben wären, fälschlicherweise in einen ungesunden Zustand brachte und dadurch die Liquidation ihrer Positionen auslöste.
Um ähnliche Risiken zukünftig zu reduzieren:
-
Stellen Sie sicher, dass kritische Parameter vor jeder Aktualisierung auf Korrektheit überprüft werden.
-
Fügen Sie Validierungsprüfungen in die Implementierung ein, um fehlerhafte Parameter abzulehnen und die erfolgreiche Anwendung fehlerhafter Konfigurationen zu verhindern.
Planet Finance Vorfall
Kurze Zusammenfassung
Am 11. März 2026 wurde Planet Finance auf BNB Chain ausgenutzt, was zu einem geschätzten Verlust von ~10.000 USD führte. Die Grundursache war, dass das Protokoll Erhöhungen des gespeicherten Kreditbetrags eines Kreditnehmers fälschlicherweise als aufgelaufene Zinsen behandelte, wodurch ein Angreifer wiederholt leihen und eine Rabattabrechnung auslösen konnte, um seine aufgezeichneten Schulden zu unterschätzen.
Hintergrund
Planet Finance ist ein Kreditprotokoll, das es Kreditnehmern ermöglicht, mit einem Zinsrabatt zurückzuzahlen. Der Rabatt ist gestaffelt und wird durch das Verhältnis zwischen dem eingesetzten GAMMA eines Benutzers und seinem eingesetzten Wert in anderen Vermögenswerten bestimmt: Je höher dieses Verhältnis, desto höher der Rückzahlungsrabatt. Der Rabattplan umfasst drei Stufen, von 0 % (Minimum) bis 50 % (Maximum).
Schwachstellenanalyse
Die Grundursache war, dass bei der Abrechnung eines Kreditnehmerrabatts in changeUserBorrowDiscount(), das Protokoll (0x4c9E...F467) fälschlicherweise die Erhöhung des gespeicherten Kreditbetrags eines Kreditnehmers als neu aufgelaufene Zinsen behandelte. Infolgedessen wurde der Rabatt, der nur für aufgelaufene Zinsen gelten sollte, fälschlicherweise auf das neu geliehene Kapital angewendet, wodurch die aufgezeichnete Schuld des Kreditnehmers unsachgemäß reduziert wurde. Ein Angreifer konnte die Schleife borrow dann changeUserBorrowDiscount wiederholt durchführen, um übermäßige Rabatte anzuhäufen, wodurch die On-Chain aufgezeichnete Verbindlichkeit durchweg niedriger war als der tatsächliche geliehene Betrag, und letztendlich von der Diskrepanz profitierte.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x5f45...5ec9.
-
Schritt 1: Der Angreifer hat mit einem Flash-Loan
200.000e18USDTaufgenommen. -
Schritt 2: Der Angreifer kaufte mit
5.000e18USDTWBNBund kaufte dann mit dem erworbenenWBNB~8.726.524e18GAMMA. -
Schritt 3: Der Angreifer stakte zunächst alle erworbenen
GAMMAim gGAMMA-Markt, zahlte dann den verbleibendenUSDTals Kollateral ein, was seinen Rückzahlungsrabatt auf 5 % erhöhte und die anschließende Kreditaufnahme ermöglichte. -
Schritt 4: Der Angreifer rief wiederholt
borrowund dannupdateUserDiscountauf, um seine aufgezeichnete Schuld kontinuierlich zu reduzieren. -
Schritt 5: Der Angreifer zahlte schließlich die Schuld zurück, löste das Kollateral ein und realisierte den Gewinn.
Schlussfolgerung
Dieser Vorfall wurde durch die fehlerhafte Rabatt-Abrechnungslogik 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 aufgezeichnete Schuld zu unterschätzen und letztendlich weniger als die tatsächliche Verbindlichkeit zurückzuzahlen, um Profit zu erzielen.
Um ähnliche Risiken zukünftig zu reduzieren:
- Unterscheiden Sie Zinsen und neue Kredite im Kreditprotokoll.
AM Vorfall
Kurze Zusammenfassung
Am 12. März 2026 wurde der AM Token, ein deflationärer Token auf BNB Chain, mit einem geschätzten Verlust von ~131.000 USD ausgenutzt. Der 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 die Gesamtmenge zu reduzieren. Die Verbrennung wird jedoch nicht sofort ausgeführt - stattdessen wird der volle Verkaufbetrag als toBurnAmount aufgezeichnet und die tatsächliche Verbrennung auf den nächsten Verkauf verschoben. Diese Verzögerung schafft ein Fenster zwischen Aufzeichnung 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 verzögerte Verbrennung auslöst, wird die gesamte AM-Reserve gelö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 BNB Chain. Bei jedem Verkauf zeichnet der Vertrag den im Tausch involvierten AM-Betrag als toBurnAmount auf und verbrennt diesen aufgezeichneten Betrag aus dem Liquiditätspool während des nächsten Verkaufs. Effektiv lösen Verkäufe eine verzögerte Verbrennung aus, die die AM-Reserve des Pools reduziert. Darüber hinaus tauscht das Protokoll vor der Ausführung der Verbrennung den angesammelten totalTokenFee in USDT und verteilt ihn gemäß seiner Gebührenallokationslogik.
Schwachstellenanalyse
Die Grundursache war, dass die Verkaufslogik des Tokens (0x27f9...213f) den gesamten getauschten AM-Betrag als toBurnAmount ansammelt und die Verbrennung erst beim nächsten Verkauf ausführt, indem er Token aus dem AM/USDT-Paar entfernt und pair.sync() aufruft, 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 zu profitieren.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0xd0d1...f859.
-
Schritt 1: Der Angreifer hat mit einem Flash-Loan
~27.265.119e18USDCund~361.710e18WBNBaufgenommen und diese dann gegen~100.423.811e18USDTgetauscht. -
Schritt 2: Der Angreifer tauschte
~5.062e18AM-Token gegenUSDT, was den aufgezeichnetentoBurnAmountdes Vertrags auf~4.303e18manipulierte. -
Schritt 3: Der Angreifer tauschte
USDTgegen AM Token und senkte damit dieAM-Reserve des Pools auf~4.303e18. -
Schritt 4: Der Angreifer übertrug
6 weiAMan den Pool, was die Verkaufs-Pfad-Verbrennungslogik auslöste. Infolgedessen verbrannte der Vertrag das gesamteAM-Guthaben aus dem Pool und reduzierte dieAM-Reserve auf 0. 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ühren-Swap fehl. Da er in einem Try/Catch eingebettet ist, revertiert der Fehler die Transaktion nicht. 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 verbleibendenUSDTund1 weiAMin den Pool. Da beide Token gleichzeitig übertragen wurden, behandelte der Vertrag dies alsaddLiquidity, sodasstoBurnAmountnicht angesammelt wurde. DieAM-Reserve wurde auf 7 aktualisiert. -
Schritt 6: Der Angreifer tauschte die verbleibenden
AM-Token gegenUSDT. Bei diesem Tausch löste die Übertragung vonAMin das Pair die Verkaufs-Pfad-Verbrennungslogik aus und reduzierte dieAM-Reserve auf 1. DatotalFeeAmountin Schritt 4 auf 0 zurückgesetzt worden war, wurde die Gebühr zuUSDT-Konvertierung nicht mehr ausgeführt, wodurch der AngreiferAMzu einem künstlich aufgeblähten Preis verkaufen konnte. -
Schritt 7: Der Angreifer zahlte den Flash-Loan 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 sammelt 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 abzuziehen.
Um ähnliche Risiken zukünftig 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 Vorfall
Kurze Zusammenfassung
Am 12. März 2026 wurde DBXen, ein Burn-to-Earn-Protokoll auf Ethereum und BNB Chain, mit einem Gesamtverlust von ~149.000 USD ausgenutzt. Die Grundursache 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) aufgezeichnet, aber die Zykluszähler werden auf msg.sender (dem forwarder) aktualisiert. Diese Trennung ermöglicht es dem Angreifer, Prämien und Gebühren gegen veraltete Zyklusaufzeichnungen zu beanspruchen, was zu abnormal großen Auszahlungen führt.
Hintergrund
DBXen ist ein Burn-to-Earn-Protokoll: Benutzer verbrennen XEN-Token im Austausch gegen DXN-Prämien 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()) aufgezeichnet, und (2) der XEN-Vertrag ruft DBXen über onTokenBurned() zurück, um die Zyklusaufzeichnungen des Aufrufers (Verbrennungszyklus und lastFeeUpdateCycle) auf den aktuellen Zyklus zu aktualisieren.
Prämien und Gebühren werden über updateStats() abgerechnet. Die Prämie ist proportional zum Anteil des Benutzers an den gesamten in seinem Verbrennungszyklus verbrannten XEN. Die Gebühr basiert auf den kumulierten Protokollgebühren, die seit dem letzten aufgezeichneten Zyklus des Benutzers angefallen sind. Beide Berechnungen hängen davon ab, dass die Zyklusaufzeichnungen des Benutzers aktuell sind.
Schwachstellenanalyse
Die Grundursache 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. 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 sowohl den Verbrennungszyklus-Datensatz des forwarder als auch den Gebührenaktualisierungs-Zyklus-Datensatz auf den aktuellen Zyklus aktualisiert. Gleichzeitig zeichnet das Protokoll jedoch den verbrannten XEN-Betrag unter der Adresse auf, die _msgSender() entspricht.
Danach ruft der Angreifer claimFees() auf, was updateStats() aufruft. Da die Zyklusaufzeichnungen der _msgSender()-Adresse nie aktualisiert wurden (sowohl der Verbrennungszyklus als auch lastFeeUpdateCycle bleiben bei 0), berechnet updateStats() Prämien im aktuellen Zyklus und berechnet Gebühren, die seit Zyklus 0 angefallen sind - was die gesamte Gebührenhistorie des Protokolls abdeckt. 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, was nachfolgende Aufrufe vonForwarder.execute()ermöglichte. -
Schritt 2: Der Angreifer tauschte
0,14e18ETHgegen13.900.000.000e18XENin einem Uniswap V2 Pool. -
Schritt 3: Der Angreifer übertrug
13.900.000.000e18XENan denForwarder-Vertrag. -
Schritt 4: Der Angreifer nutzte
Forwarder.execute(), um DBXen zu autorisieren, die vonForwardergehaltenen13.900.000.000e18XENauszugeben. -
Schritt 5: Der Angreifer nutzte
Forwarder.execute(), umDBXen.burnBatch()aufzurufen und verbrannte13.900.000.000e18XEN. Der Verbrennungsbetrag wurde unter der Adresse0x425D3eC2DCeBE2c04bA1687504D43AFC6be7328daufgezeichnet, während während der VerbrennungsausführungXENüberonTokenBurned()zurück inDBXenrief und die relevanten Zyklusaufzeichnungen auf demForwarderaktualisierte. -
Schritt 6: Der Angreifer nutzte
Forwarder.execute(), umDBXen.claimFees()aufzurufen und erhielt65,36e18ETH. -
Schritt 7: Der Angreifer nutzte
Forwarder.execute(), umDBXen.claimRewards()aufzurufen und prägte2.305,4e18DXN.
Schlussfolgerung
Die Grundursache dieses Vorfalls war, dass das DBXen-Protokoll _msgSender() und msg.sender inkonsistent verwendete. Da diese beiden Werte unterschiedlich sein konnten, wurde die interne Buchführung des Protokolls inkonsistent, was es dem Angreifer ermöglichte, die Diskrepanz zum Profit auszunutzen.
Um ähnliche Risiken zukünftig 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 Vorfall
Kurze Zusammenfassung
Am 15. März 2026 wurde Goose Finance, ein Yield-Farming-Protokoll auf BNB Chain, für etwa 8.000 USD ausgenutzt. Die Grundursache war ein Fehler in der Aktienpreisordnung in StrategyGooseEgg: deposit() prägt Aktien, bevor die geernteten Prämien in der Buchführung abgerechnet werden, sodass der Gesamtanlagen-Nenner für die Aktienpreisbildung diese Prämien ausschließt und niedriger ist als der tatsächliche Wert. Dies bedeutet, dass Einleger mehr Aktien erhalten, als sie sollten. Wenn withdraw() aufgerufen wird, löst dies eine Prämienernte aus, die die Gesamtaktiva erhöht und jede Aktie wertvoller macht. Durch das Schleifen von Einlagen und Auszahlungen in einer einzigen Transaktion prägte der Angreifer wiederholt überteuerte Aktien und löste sie zum korrigierten (höheren) Wert ein, wobei er die Differenz als Gewinn extrahierte.
Hintergrund
Goose Finance ist ein Yield-Farming-Protokoll auf BNB Chain, bei dem Benutzergelder von einem Vault in eine Strategie fließen, die Vermögenswerte in MasterChef stakt, um EGG-Prämien zu verdienen.
Die für diesen Vorfall relevanten Komponenten sind:
-
VaultChef(0x3f64...): verfolgt Benutzerpositionen und leitet Kapital anStrategyGooseEggweiter. -
StrategyGooseEgg(0x0980...): führt die Buchführung auf Strategieebene mitsharesTotalundwantLockedTotal. -
MasterChef(0xe70e...): empfängt gestakte Vermögenswerte und zahltEGG-Prämien aus. -
WrappedEgg(0xb815...): wickeltEGG1:1 inWEGGzum Staken.
Betrieblich werden Einlagen von VaultChef an StrategyGooseEgg weitergeleitet, dann in MasterChef gestakt. Auszahlungen werden von VaultChef initiiert und von der Strategie ausgeführt.
Eine wichtige buchhalterische Erwartung ist, dass die Aktienpreisbildung die gesamten Strategievermögenswerte zum Zeitpunkt der Preisbildung widerspiegeln sollte (gestaktes Kapital plus im Besitz der Strategie befindliche Idle-Prämien). In StrategyGooseEgg prägt deposit() jedoch Aktien, bevor _farm() Idle-Vermögenswerte in wantLockedTotal abwickelt, während withdraw() eine Prämienernte aus MasterChef auslösen kann. Diese Reihenfolge ist die Grundlage für die nachstehend analysierte Schwachstelle.
Schwachstellenanalyse
Die Grundursache ist eine buchhalterische Desynchronisation in StrategyGooseEgg (0x0980...b26b) zwischen Prämienernte und Aktienpreisbildung.
In StrategyGooseEgg verwendet die Aktienpreisbildung wantLockedTotal als Nenner: shares = deposit * sharesTotal / wantLockedTotal. Damit dies fair ist, muss wantLockedTotal alle Vermögenswerte widerspiegeln, die die Strategie tatsächlich hält, einschließlich aller Idle-EGG-Prämien, die im Vertrag liegen. deposit() prägt jedoch Aktien, bevor _farm() Idle-Prämien in wantLockedTotal abwickelt. Das bedeutet, dass der Nenner nicht erfasste Prämien ausschließt und niedriger ist als die tatsächlichen Gesamtaktiva, wodurch der Einleger mehr Aktien erhält, als er sollte.
Darüber hinaus ruft withdraw() MasterChef.withdraw() auf, was den gestakten Kapitalbetrag zuzüglich ausstehender EGG-Prämien an die Strategie zurückgibt. Die Buchführung der Strategie zieht nur den angeforderten _wantAmt von wantLockedTotal ab, sodass die geernteten Prämien im Bestand der Strategie verbleiben, ohne in wantLockedTotal reflektiert zu werden. Dies vergrößert die Lücke zwischen den tatsächlich gehaltenen Vermögenswerten und dem aufgezeichneten wantLockedTotal, wodurch jede nachfolgende deposit()-Aktienpreisbildung noch ungenauer wird.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x86efdf...ce316223.
-
Schritt 1: Der Angreifer hat
EGGaus zwei Pancake-Paaren per Flash-Loan geliehen. -
Schritt 2: Erste Einzahlung in
VaultChef/StrategyGooseEgg(10.170.000e18EGG). -
Schritt 3: Die erste Auszahlung (
12.593.884e18EGG) erntet Prämien vonMasterChef;359.561e18EGGwerden anStrategyGooseEggübertragen und bleiben als Idle/nicht erfasster Wert (R > 0). -
Schritt 4: Die zweite Einzahlung verwendet das abgezogene Kapital (
12.593.884e18EGG). Die Aktien werden vor der Abrechnung des Idle-Werts gepreist, daher ist dies der Schritt der Über-Prägung. -
Schritt 5: Die zweite Auszahlung (
12.826.027e18EGG) realisiert den Gewinn aus über-geprägten Aktien (d. h.232.143EGGüber dem Einzahlungsbetrag aus Schritt 4). -
Schritt 6: Der Angreifer zahlt die Flash-Swaps zurück und behält die Netto-Differenz.
Schlussfolgerung
Der Exploit stammt aus einem Fehler in der Aktienpreisordnung von StrategyGooseEgg: deposit() prägt Aktien, bevor _farm() wantLockedTotal aktualisiert, während withdraw() Prämien von MasterChef ernten kann, die vorübergehend Idle 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 zukünftig zu reduzieren:
-
Prämien abwickeln und Buchhaltung aktualisieren, bevor sowohl Aktien-Präge- als auch Aktien-Einlösungsberechnungen durchgeführt werden.
-
Aktien gegen eine einzige
totalAssets(gestakt + Idle) zum genauen Berechnungszeitpunkt bewerten. -
Invariantentests für
shares_minted <= D * S / (A + R)unter Bedingungen mit nicht-null Idle-Prämien hinzufügen.
Über BlockSec
BlockSec ist ein Full-Stack-Anbieter für Blockchain-Sicherheit und Krypto-Compliance. 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 Hacks blockiert, um mehr als 20 Millionen Dollar zu retten, und Kryptowährungen im Wert von Milliarden gesichert.
-
Offizielle Website: https://blocksec.com/
-
Offizielles Twitter-Konto: https://twitter.com/BlockSecTeam



