Am 3. August 2023 wurde ein MEV-Bot auf Arbitrum angegriffen, was zu einem Verlust von 800.000 US-Dollar führte. Die Grundursache für diesen Angriff war eine unzureichende Überprüfung der Benutzereingaben.
In Anbetracht der komplexen Interaktionen zwischen MEV-Bots und ihren nicht verifizierten Verträgen zeigt sich, dass dass der Verzicht auf Open-Source keine Sicherheit garantiert, insbesondere bei DeFi-Protokollen.
Hintergrund
MEV-Bot
Ein MEV-Bot (Maximum Extractable Value Bot) wurde entwickelt, um profitable Gelegenheiten auf der Blockchain zu identifizieren und zu nutzen. Er funktioniert durch die Analyse ausstehender Transaktionen (d. h. solche im Mempool) oder On-Chain-Zustände, um durch Arbitrage Gewinne zu erzielen.
Im Gegensatz zu typischen Front-Running- und Sandwich-Attack-MEV-Bots konzentrierte sich der bei diesem Angriff ins Visier genommene MEV-Bot auf die Ausführung von Strategien wie Dreiecksarbitrage und Schuldenliquidation. Diese Bots selbst tragen dazu bei, die Preise für AMMs zu stabilisieren und unterstützen Kreditprotokolle bei der Liquidation, um einen reibungslosen Betrieb zu gewährleisten – sie sind ein wesentlicher Bestandteil der gesunden Funktionsweise des DeFi-Ökosystems.
Flashloan
Ein Flashloan stellt eine einzigartige Innovation innerhalb des DeFi-Ökosystems dar – eine Form der unbesicherten Kreditvergabe. Sie können über einen Flashloan ohne jegliche Sicherheiten bis zu einer Milliarde Dollar leihen, vorausgesetzt, das Darlehen wird innerhalb derselben Transaktion zurückgezahlt. Wenn das Darlehen nicht innerhalb dieser Transaktion zurückgezahlt wird, wird es rückgängig gemacht, als ob die Transaktion nie stattgefunden hätte.
Dieser Mechanismus wird häufig für Arbitrage oder die Hebelung anderer DeFi-Strategien genutzt, um vorübergehende Marktineffizienzen auszunutzen.
Die Schwachstelle
Kurzfassung
Die unzureichende Validierung von Benutzereingabeparametern ermöglichte es dem Angreifer, einen FakeFlashloanProvider einzuschleusen. Der Tresor-Vertrag (Vault) nutzte diesen Provider, um einen Flashloan zu initiieren. Um den Flashloan anschließend zu begleichen, genehmigte der Tresor-Vertrag dem FakeFlashloanProvider Token-Transfers, was zur unbefugten Übertragung von Vermögenswerten aus dem Tresor führte.
Detaillierte Version
Die betroffenen Verträge sind:
Vault: Der angegriffene Vertrag 0xd614927acfb9744441180c2525faf4cedb70207f fungiert als „Vault“ (Tresor), stellt Reserven bereit und ermöglicht Flashloans von anderen Protokollen wie AAVE und Balancer.Arbitrage Bot: Der anfällige Vertrag 0x8db0efee6a7622cd9f46a2cf1aedc8505341a1a7 fungiert als „Arbitrage Bot“ und nimmt die Rolle des Kreditnehmers im „Vault“-Vertrag ein.
Die Funktion 0x0582f20f() im „Arbitrage Bot“ ist der Haupteinstiegspunkt für den Start von Arbitrage-Geschäften.
Sie ruft zuerst die borrow()-Funktion im „Vault“ auf, um das ursprüngliche Kapital zu erhalten, und führt dann die Arbitrage-Logik über einen delegatecall an einen externen Vertrag aus, der in den Calldata angegeben ist und keiner Validierung unterliegt.
function 0x0582f20f(...) {
...
v67, /* uint256 */ v68 = address(0xd614927acfb9744441180c2525faf4cedb70207f).borrow(address(v39), address(v9[0]), v29).gas(msg.gas);
...
// 0x4da91757 = swap(address,address,address,uint256,uint256,uint256,address)
MEM[MEM[64] + 32] = uint224(address(MEM[0 + v4[v69]])) | 0x4da9175700000000000000000000000000000000000000000000000000000000;
v82 = address(v76 >> 96).delegatecall(MEM[(MEM[64]) len 228], MEM[(MEM[64]) len 0]).gas(msg.gas);
...
v189 = v170.refund(0x410085df, address(v9[0]), address(v39), v68, address(v9[0]), v29, v186, 4 + MEM[64] + (varg2.length << 5) - (4 + MEM[64]) + 192).gas(msg.gas);
...
}
Anschließend ruft er 0x512b7351() im „Vault“ auf und startet einen Flashloan zum FakeFlashloanProvider-Vertrag des Angreifers.
Die Funktion 0x512b7351() erfordert, dass msg.sender auf der Zulassungsliste steht, aber dies wurde erfolgreich durch den vorangegangenen delegatecall umgangen, wodurch die Prüfung ausgehebelt wurde. Dies ist ein sehr kritischer Schritt.
function 0x512b7351(...) public nonPayable {
...
if (_borrow[msg.sender] >= 1) {
v0 = !_refund;
}
require(v0, Error('BBVault: FORBIDDEN'));
...
v38 = v23.length;
v39 = v23.data;
_refund = keccak256(v23);
...
<FakeFalshloanProvider>.flashloan(...);
...
}
Während des Flashloan-Callbacks überträgt die Funktion executeOperation() im „Vault“ zunächst die geliehenen Vermögenswerte an den „Arbitrage Bot“ (MEVBot 0x8db0ef) und ruft dann dessen 0x7fe3ba8b() auf.
function executeOperation(...) {
...
require(_refund == keccak256(v3.data), Error('BBVault: STATUS'));
Token.transfer(ArbitrageBot, amountBorrowed);
<ArbitrageBot>.call(0x7fe3ba8b...);
}
Der „Arbitrage Bot“ vertraut diesem externen Aufruf und überträgt die erhaltenen Vermögenswerte zurück an den FakeFlashloanProvider.
Der „Vault“ erkennt dies jedoch nicht und gewährt dem FakeFlashloanProvider am Ende von executeOperation() weiterhin die Genehmigung zur Rückzahlung des Flashloans.
Der Angriffsprozess
Angriffs-Tx: 0x864c8cfb8c54d3439613e6bd0d81a5ea2c5d0ad25c9af11afd190e5ea4dcfc1f
Der Angreifer ruft die Funktion 0x0582f20f() des „Arbitrage Bots“ auf, welcher wiederum einen Delegate-Call an den Vertrag des Angreifers durchführt.


Der hack_contract_2 ruft dann die Funktion 0x512b7351() des Opfer-Vertrags auf. Die Funktion 0x512b7351() erfordert, dass msg.sender auf der Zulassungsliste steht, was jedoch durch den vorherigen delegatecall erfolgreich umgangen wurde, wodurch die Prüfung ausgehebelt wurde.

Das Opfer ruft dann den FakeFlashloanProvider-Vertrag des Angreifers auf, überträgt alle per Flashloan geliehenen Mittel an das Opfer und ruft die executeOperation() des Opfers auf.

Die Funktion 0x7fe3ba8b() des „Arbitrage Bots“ führt erneut einen delegatecall an den Vertrag des Angreifers aus, wobei diesmal alle Vermögenswerte an den Angreifer zurücktransferiert werden.
An diesem Punkt wurden die vom Flashloan-Provider des Angreifers geliehenen Vermögenswerte zurückgezahlt.

Das Opfer („Vault“) genehmigt dem FakeFlashloanProvider Token-Transfers, möglicherweise in der Absicht, den Flashloan zurückzuzahlen.

Der Angreifer nutzt diese Genehmigung aus, um Profite zu erzielen, indem er transferFrom verwendet, um Gelder aus dem Opfer-Vertrag abzuziehen.
Sicherheitsempfehlungen
Nicht-Open-Source-Code garantiert keine Sicherheit
Der Glaube, dass nicht-quelloffener oder obfuskierter Code Sicherheit gewährleistet, ist ein Irrtum. Dieser MEV-Bot-Vorfall zeigt, dass Geheimhaltung nicht vor Exploits schützt und Entwicklern lediglich ein falsches Gefühl von Sicherheit vermitteln kann.
Strenge Eingabevalidierung
Es ist entscheidend, alle Vertragsinteraktionen und Calldata sorgfältig zu validieren, insbesondere beim Umgang mit Standardschnittstellen wie Flashloan- und Swap-Callbacks. Die Gewährleistung der Datenintegrität und Sicherheit sollte bei der Konzeption und Implementierung von Verträgen Priorität haben.
Lesen Sie weitere Artikel dieser Serie:
- Einleitung: Die zehn „beeindruckendsten“ Sicherheitsvorfälle im Jahr 2023
- #1: Ernte bei MEV-Bots durch Ausnutzung von Schwachstellen im Flashbots Relay
- #2: Euler Finance-Vorfall: Der größte Hack des Jahres 2023
- #3: KyberSwap-Vorfall: Meisterhafte Ausnutzung von Rundungsfehlern durch äußerst subtile Berechnungen
- #4: Curve-Vorfall: Compiler-Fehler erzeugt fehlerhaften Bytecode aus unbedenklichem Quellcode
- #5: Platypus Finance: Drei Angriffe mit einer Portion Glück überlebt
- #6: Hundred Finance-Vorfall: Katalysator für die Welle präzisionsbedingter Exploits in anfälligen Fork-Protokollen
- #7: ParaSpace-Vorfall: Ein Wettlauf gegen die Zeit, um den bisher kritischsten Angriff der Branche abzuwehren
- #8: SushiSwap-Vorfall: Ein ungeschickter Rettungsversuch führt zu einer Serie von Nachahmer-Angriffen
- #10: ThirdWeb-Vorfall: Inkompatibilität zwischen vertrauenswürdigen Modulen offenbart Schwachstelle



