Überlauf / Sudo Null IT-News

Ein Überlauf ist eine numerische Berechnung, die die für die Speicherung zugewiesene Speichermenge überschreitet. In Solidity ist der Bereich, den der uint8-Datentyp darstellen kann, 256 Zahlen von 0 bis 255. Wenn der uint8-Typ verwendet wird, um 255 + 1 zu berechnen, tritt ein Überlauf auf, sodass das Ergebnis der Berechnung 0 ist, der kleinste Wert die der Typ uint8 darstellen kann.

Besteht im Vertrag eine Überlauf-Schwachstelle, kann das tatsächliche Ergebnis der Berechnung erheblich vom erwarteten Ergebnis abweichen. Dies wirkt sich auf die normale Vertragslogik aus und kann zu Geldverlusten führen. Allerdings gibt es Versionseinschränkungen für die Überlauf-Schwachstelle. In Versionen von Solidity < 0.8 wird der Überlauf keinen Fehler melden, aber in Versionen >= 0.8 wird der Überlauf einen Fehler auslösen.

Beispiel

// SPDX-Lizenz-Identifier: MIT pragma solidity ^0.7.6; Vertrag TimeLock { Zuordnung (Adresse => uint) öffentliche Guthaben; Zuordnung (Adresse => uint) öffentliche Sperrzeit; Funktion deposit() extern zahlbar { Salden[msg.sender] += msg.value; Sperrzeit[msg.sender] = Block.Zeitstempel + 1 Woche; } Funktion raiseLockTime(uint _secondsToIncrease) public { lockTime[msg.sender] += _secondsToIncrease; } Funktion Abheben() public {require(salden[msg.sender] > 0, „Unzureichende Mittel“); require(block.timestamp > lockTime[msg.sender], „Sperrzeit nicht abgelaufen“); Einheitsbetrag = Salden[msg.sender]; Salden[msg.sender] = 0; (bool gesendet, ) = msg.sender.call{Wert: Betrag}(“”); require(gesendet, “Ether konnte nicht gesendet werden”); } }

Schwachstellenanalyse

Wir können sehen, dass der TimeLock-Vertrag als Zeitspeicher fungiert. Benutzer können Gelder in den Vertrag einzahlen und einfrieren, indem sie die Funktion deposit() verwenden, die für mindestens eine Woche gesperrt wird. Natürlich kann der Benutzer die Aufbewahrungszeit noch mit der Funktion raiseLockTime() erhöhen. Der Benutzer kann im TimeLock-Vertrag gesperrte Token nicht vor Ablauf der festgelegten Aufbewahrungsfrist widerrufen.

Wenn wir uns die Funktionen raiseLockTime und deposit ansehen, sehen wir, dass sie arithmetische Operationen enthalten. Die vom Vertrag unterstützte Version ist mit Version 0.7.6 kompatibel, sodass dieser Vertrag keinen Überlauffehler meldet. Analysieren wir zwei Funktionen, raiseLockTime und die Einzahlungsfunktion.

  1. Die Einzahlungsfunktion besteht aus zwei Operationen. Die erste betrifft das vom Benutzer eingegebene Guthaben. Die hier übergebenen Parameter sind kontrollierbar, es besteht also die Gefahr eines Überlaufs. Eine andere Möglichkeit besteht darin, die Sperrzeit des Benutzers zu beeinflussen. Die Berechnungslogik hier ist, dass jedes Mal, wenn eine Einzahlung aufgerufen wird, um Token einzuzahlen, die Sperrzeit um eine Woche verlängert wird. Da die Parameter hier festgelegt sind, besteht bei dieser Berechnung keine Gefahr eines Überlaufs.

  2. Die Funktion raiseLockTime führt Berechnungen basierend auf dem vom Benutzer übergebenen Parameter _secondsToIncrease durch, um die Sperrzeit für die hinterlegten Token des Benutzers zu ändern. Da der Parameter _secondsToIncrease verwaltet wird, besteht die Gefahr eines Überlaufs.

Schauen wir uns den Parameter balances genauer an. Ein erheblicher Geldbetrag (22⁵⁶ um genau zu sein) muss auf unser Konto eingezahlt werden, um einen Überlauf zu erzeugen. Dadurch werden die Guthaben auf unserem Konto überlaufen und auf Null reduziert, was den Eindruck erweckt, dass dort nichts ist.

Konzentrieren wir uns nun auf den Parameter _secondsToIncrease. Dieser Parameter wird übergeben, wenn wir die Funktion raiseLockTime aufrufen, um die Haltezeit zu erhöhen. Diese Einstellung kann bestimmen, wann wir Gelder im Vertrag einzahlen und sperren. Sie wird direkt aus der dem Konto zugeordneten Sperrzeit berechnet. Wir können den Parameter _secondsToIncrease so manipulieren, dass er einen Überlauf verursacht und auf Null zurückkehrt, wodurch wir das Guthaben vor dem Ablaufdatum abheben können.

Angreifervertrag

import ‘./overflow.sol’; Vertrag Angriff { TimeLock timeLock; Konstruktor (TimeLock _timeLock) { timeLock = TimeLock (_timeLock); } fallback() extern zahlbar {} function attack() öffentlich zahlbar { timeLock.deposit{value: msg.value}(); timeLock.increaseLockTime(type(uint).max + 1 – timeLock.lockTime(address(this))); timeLock.withdraw (); } }

Ausnutzung von Schwachstellen

1. Stellen Sie zuerst den TimeLock-Vertrag bereit.

2. Erweitern Sie den Attack-Vertrag und übergeben Sie die Adresse des TimeLock-Vertrags.

3. Rufen Sie die Attack.attack-Funktion auf; Es ruft dann die Funktion TimeLock.deposit auf, um Eth in den TimeLock-Vertrag einzuzahlen (zu diesem Zeitpunkt wird Eth von TimeLock für eine Woche gesperrt). Anschließend ruft es die Funktion TimeLock.increaseLockTime erneut auf. Er übergibt den maximalen Wert, der durch den uint-Typ (22⁵⁶-1) plus eins minus der im aktuellen temporären Sperrvertrag aufgezeichneten Sperrzeit dargestellt werden kann. Zu diesem Zeitpunkt ist das Ergebnis der Sperrzeit in der Funktion TimeLock.increaseLockTime 22⁵⁶. Da die Zahl 22⁵⁶ überläuft, ist der Rückgabewert 0. Zu diesem Zeitpunkt haben wir den Wert einfach im TimeLock-Vertrag gespeichert, und die zurückgegebene Sperrzeit für den Vertrag wird 0.

4. Zu diesem Zeitpunkt löst Attack.attack den Zeitblock erneut aus. Die Ausgabefunktion wird die Sperre erfolgreich passieren. Zeitstempel > Sperrzeit [msg.sender]. Diese Prüfung ermöglicht uns eine erfolgreiche Vorablöschung, wenn die Aufbewahrungszeit noch nicht abgelaufen ist.

Algorithmus

Vertragsprüfung

Entwickler

Wirtschaftsprüfer

Verwenden Sie SafeMath-Bibliotheken, um einen Überlauf zu verhindern

Überprüfen Sie die Solidity-Version

Verwenden Sie Solidity 8.0 und höher

Wenn die Vertragsversion unter Solidity 0.8 liegt, müssen Sie prüfen, ob sich der Vertrag auf SafeMath bezieht.

Das Umwandeln in einen anderen Typ muss mit Vorsicht verwendet werden. Wenn Sie beispielsweise die Konvertierung eines Parameters vom Typ uint256 in uint8 erzwingen, kann dies aufgrund der unterschiedlichen Bereiche der beiden Typen zu einem Überlauf führen.

Beim Einsatz von SafeMath müssen wir darauf achten, ob im Vertrag eine zwingende Typkonvertierung vorgesehen ist. In diesem Fall besteht die Gefahr des Überlaufens.

Wenn SafeMath nicht verwendet wird und der Vertrag arithmetische Operationen enthält, können wir daraus schließen, dass dieser Vertrag ein Überlaufrisiko haben kann.

Verknüpfungen

Similar Posts

Leave a Reply

Your email address will not be published.