Willkommen beim Einsteigerleitfaden zur intelligenten Vertragsprüfung! Eine der besten Möglichkeiten, um mit der Prüfung intelligenter Verträge zu beginnen, besteht darin, sich ein paar gängige Arten von Schwachstellen in intelligenten Verträgen anzusehen.
Es wäre hilfreich, wenn Sie bereits über ein grundlegendes Verständnis der Programmiersprache Solidity von Ethereum verfügen. Wir werden uns einige der Codes ansehen, die von Solidity-Programmierern von Noob geschrieben wurden.
Re-Entrancy-Angriff
Szenario aus der realen Welt:
Stellen Sie sich vor, Sie haben 50 Pralinen. Du hast eine ungezogene kleine Schwester, der du erlaubt hast, dir immer nur 2 Pralinen zu nehmen. Sie sollten ihr auch nicht mehr als 10 Pralinen an einem Tag geben, weil Sie befürchten, dass sie Karies bekommt. Um dies zu gewährleisten, zählen Sie jeden Abend, wie viele Pralinen noch bei Ihnen sind. Glaubst du, das würde funktionieren? Oder würdest du von deiner kleinen Schwester gehackt werden?
Leider wird es nicht funktionieren! Ihre Schwester findet heraus, dass Sie bis zum Abend nicht wissen, wie viele Pralinen Sie haben. Schon am nächsten Tag besucht Sie Ihre kleine Schwester 6 Mal vor dem Abend und nimmt jedes Mal 2 Pralinen mit! Dies nennen wir einen Re-Entrancy-Angriff.
Hier aktualisieren Sie die Zählung der Pralinen, die Sie abends haben, anstatt die Zählung jedes Mal zu aktualisieren, wenn Ihre Schwester 2 Pralinen von Ihnen nimmt. Dies geschieht auch mit Smart Contracts. Der Smart Contract geht von einem bestimmten Saldo aus, während der Angreifer tatsächlich damit beschäftigt ist, mehrmals eine gewisse Menge an Krypto aus dem Vertrag abzuheben.
Codebeispiel aus der realen Welt:
Dieser Code gehört zu einem Smart Contract namens Ohne Bankkonto. Jeder kann Ether von einem Unbanked-Vertrag abheben, solange das Guthaben des msg.senders (d.h. des Anrufers von withdraw
Funktion ) größer oder gleich dem Betrag ist, der zur Auszahlung angefordert wird.
function withdraw(uint _amount) { require(balances[msg.sender] >= _amount); msg.sender.call.value(_amount)(); balances[msg.sender] -= _amount;
}
Beachten Sie, dass es ein Call-Schlüsselwort gibt, das verwendet wird, um die erforderliche Menge an Ether an die zu senden msg.sender
. Ein Angreifer kann dies ausnutzen, indem er einen Vertrag namens Thief erstellt, in dem er die Abhebungsfunktion in a aufruft fallback()
Funktion. EIN fallback()
Funktion in Solidity ist eine spezielle Funktion, die ausgeführt wird, wenn Ether an den Smart Contract gesendet wird.
Dies bedeutet, dass ein Angreifer in der Lage ist rufen Sie rekursiv die Funktion remove auf. Daher werden vor den Smart-Contract-Updates die Salden von msg.sender
In der letzten Codezeile hat der Angreifer bereits mehrfach Ether zurückgezogen. Dies könnte vermieden werden, wenn die Salden aktualisiert werden, bevor das Schlüsselwort call verwendet wird, also nach a Checks-Effekte-Wechselwirkungen Muster.
Einfluss:
Das allererste Reentrancy Attack geschah 2016 bei einer DAO (Decentralized Autonomous Organization), die zu Hacks in Höhe von etwa 50 Millionen US-Dollar führte. Um diesen Hack rückgängig zu machen, teilte die Ethereum-Community die Ethereum-Blockchain, wodurch ETC (Ethereum Classic) und ETH (Ethereum) entstanden.
Arithmetischer Überlauf und Unterlauf
Szenario aus der realen Welt:
Lass uns ein Gedankenspiel spielen. Es besteht aus einem Spin-the-Wheel, und der Gewinner wird anhand der größten Zahl ermittelt, die er beim Drehen des Rads erreichen kann. Das Rad ist überall von 256 bis -256 markiert.
Die Spielregeln sind, dass der Zeiger für alle Spieler zu Beginn jeder Drehung auf 0 ruht. Und ein Spieler darf nur in Richtung negativer Zahlen drehen. Wie werden Sie dieses Spiel gewinnen?
Eine gute Strategie, um dieses Spiel jedes Mal zu gewinnen, wäre, das Rad mit einer solchen Kraft zu drehen, dass sich das Rad bis auf -256 dreht und sich dann auf einmal auf 256 dreht. Dies ist möglich, weil 256 kurz nach -256 auf dem Rad kommt. Dies nennen wir einen arithmetischen Unterlauf. Und arithmetischer Überlauf ist genau das Gegenteil davon.
Codebeispiel aus der realen Welt:
An Unterlauf oder Überlauf passiert, wenn eine arithmetische Operation ihr Minimum oder Maximum erreicht.
function withdraw(uint _amount) public { require(balances[msg.sender] - _amount > 0); address payable to = payable(msg.sender); to.transfer(_amount); balances[msg.sender] -= _amount;
}
Das _amount
Der Parameter der Rückzugsfunktion ist eine ganze Zahl ohne Vorzeichen. Der Wert der Saldenzuordnung (die wie ein Wörterbuch in Python oder ein Schlüssel-Wert-Paar in C++ oder Java ist) ist ebenfalls eine Ganzzahl ohne Vorzeichen.
mapping(address => uint256) public balances
Die geforderte Abrechnung prüft, ob die Salden von msg.sender
positiv ist oder nicht. Aber diese Aussage wird immer wahr sein, auch wenn der Betrag größer ist als das Guthaben msg.sender
. Dies liegt daran, dass sowohl die balances
und _amount
Variablen sind vom Typ Ganzzahl ohne Vorzeichen und ihr arithmetisches Ergebnis (nach Unterlauf) wird auch eine Ganzzahl ohne Vorzeichen sein!
Und wie Sie sich vielleicht erinnern, ist eine Ganzzahl ohne Vorzeichen immer positiv. Dies bedeutet, dass ein Angreifer eine unbegrenzte Menge an Ether aus dem Smart Contract abziehen kann! Sie finden ein detailliertes Beispiel und Implementierungscode für diese Schwachstelle hier.
Eine weitere wichtige Sache, die hier zu beachten ist, ist, dass die arithmetische Operation zwischen beispielsweise zwei Ganzzahlen ohne Vorzeichen auch eine Ganzzahl ohne Vorzeichen ist. Es kann gefährlich sein, wenn dies in Smart Contracts übersehen wird, da dies zu unerwünschten Sicherheitsverletzungen führen kann!
function votes(uint postId, uint upvote, uint downvotes) { if (upvote - downvote < 0) { deletePost(postId) }
}
Wie Sie vielleicht im obigen Beispiel bemerkt haben, ist die if-Anweisung ziemlich sinnlos upvote - downvote
wird immer positiv sein. Und der Beitrag wird auch dann gelöscht downvotes
größer ist als upvotes
. Um solche Angriffe zu vermeiden, wird empfohlen, eine Solidity-Compiler-Version größer als zu verwenden 0.8.0.
Einfluss:
Eine Münze rief PoWH-Münze wurde 2017 eingeführt. Obwohl es sich um ein Ponzi-Spiel handelte, wurde es selbst aufgrund eines arithmetischen Überlauffehlers gehackt, der zu einem Verlust von etwa 866 ETH oder 950,000 $ zu diesem Zeitpunkt führte. Darüber können Sie ausführlich nachlesen hier.
Muss lesen: Lehren aus dem Angriff auf Tinyman, größter DEX auf Algorand
Denial-of-Service-Angriff
Szenario aus der realen Welt:
Stellen Sie sich vor, Sie befinden sich an einer Bitcoin Tech University. Alles scheint in Ordnung zu sein, außer dass es einen gemeinsamen Esstisch für alle gibt. Und leider schaffen es nur wenige aus einer anderen Klasse, den Esstisch immer vor jemandem aus Ihrer Klasse zu besetzen.
In der Praxis verweigern sie allen den wesentlichen Dienst, was zu einem Verlust wertvoller Zeit führt. Dies nennen wir einen „Denial-of-Service-Angriff“.
Codebeispiel aus der realen Welt:
Im Spiel aufgerufen König des Äthers, jeder kann ein König werden. Aber die Regel, um König zu werden, ist, dass eine Person mehr Äther hinterlegen sollte als der aktuelle König. Dies kann durch einen Anruf erfolgen claimThrone()
Funktion des King of Ether-Vertrags, bei dem die Person Ether direkt an den vorherigen König sendet und der neue König wird.
function claimThrone() external payable { require(msg.value > balance, "Need to pay more to become the king"); (bool sent, ) = king.call{value: balance}(""); require(sent, "Failed to send Ether"); balance = msg.value; king = msg.sender; }
Wie Sie vielleicht vermutet haben, ist dieser Code anfällig für einen DoS-Angriff, aber wie? Dazu müssen Sie verstehen, dass es in Ethereum zwei Arten von Adressen gibt – die erste ist die Adresse eines extern eigenen Konto oder einfach die Adresse einer Brieftasche, und zweitens ist die Vertragsadresse. Jetzt kann der Ether von jedem dieser Adresstypen gesendet werden.
Wenn dieser Ether von der Vertragsadresse gesendet wird, wird der Vertrag zum König. Aber nehmen wir an, dass dieser neue Vertrag keine hat fallback()
Funktion, die notwendig ist, wenn der Vertrag Ether akzeptieren will. Wenn dann eine neue Person vorbeikommt und versucht die anzurufen claimThrone()
funktionieren, es wird immer fehlschlagen!
Beachten Sie, dass dies teilweise auch geschieht, weil die claimThrone()
Die Funktion prüft in der zweiten erforderlichen Anweisung explizit, ob die Übertragung von Ether erfolgreich war oder nicht. Sie können den vollständigen Code finden und einen DoS-Angriff darauf durchführen hier.
Es ist auch möglich, dass ein Code für einen DoS-Angriff anfällig ist, wenn der Code eine Schleife über ein Array großer Größen aufweist. Dies geschieht, weil die Gaslimit kann in solchen Fällen überschritten werden. Sie können darüber lesen hier.
Einfluss:
Ein Spiel namens Regierung, das anscheinend ein Ponzi-Schema war, blieb bei 1100 Ether hängen, weil eine große Menge Gas benötigt wurde, um die Auszahlung zu verarbeiten.
Unsichere Zufälligkeit
Szenario aus der realen Welt:
Es war einmal ein Mann namens Hesky, der immer von seinem Affen Pesky begleitet wurde. Hesky führte Lotteriespiele durch und machte gute Gewinne. Eines Tages bemerkte Alice, dass Hesky seinen Affen Pesky aufmerksam anstarrte. Dann sah sie, wie er etwas auf ein Stück Papier schrieb und es in einen Umschlag steckte. Neugierig beschloss sie, weitere Nachforschungen anzustellen.
Später an diesem Abend sah Alice, dass der Gewinner der Lotterie ermittelt wurde, indem der versiegelte Umschlag öffentlich geöffnet wurde. Nachdem sie ihn ein paar Tage beobachtet hatte, fand Alice heraus, dass der Hesky die Lottogewinnzahl entschied, indem er auf Peskys Gesten schaute (wenn sich der Affe zum Beispiel am Kopf kratzte, schrieb Hesky 10 auf)! Jetzt hatte Alice die Formel, um jede Lotterie zu gewinnen, und musste nur noch den Lottoschein mit der richtigen Nummer kaufen!
Hesky hatte angenommen, dass seine „zufällige“ Art, den Gewinner der Lotterie zu bestimmen, niemals herausgefunden werden kann, aber er lag tatsächlich falsch.
Codebeispiel aus der realen Welt:
In diesem Beispiel wird eine Zufallszahl basierend auf dem Hash der Kombination aus der Nummer eines Blocks und seinem Blockzeitstempel generiert. dieser Hash wird dann der Antwortvariablen zugewiesen. Nun wird jeder, der diese (scheinbar) Zufallszahl errät, mit 1 Ether belohnt. Glaubst du, das ist nicht hackbar?
function guess(uint _guess) public { uint answer = uint( keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp)) ); if (_guess == answer) { (bool sent, ) = msg.sender.call{value: 1 ether}(""); require(sent, "Failed to send Ether"); } }
NÖ! Ein Angreifer kann diese Zufallszahl immer noch erraten, indem er einfach den Code kopiert und einfügt, um den der Antwortvariablen zugewiesenen Wert zu generieren, und dieselbe Antwortvariable an die übergibt guess()
Funktion!
guessTheRandomNumber.guess(answer);
Den kompletten Code findest du hier. Um diesen Angriff zu vermeiden, wird empfohlen, eine verifizierbare Zufallsfunktion wie die zu verwenden Kettenglied-VRF.
Einfluss:
Etwa 400 ETH gingen durch einen Angriff auf die verloren Smart Billions Lotterie Vertrag. Überraschenderweise war sogar die Vertragslotterie selbst ein Schneeballsystem (autsch!).
Zeitmanipulation
Szenario aus der realen Welt:
Satoshi isst gerne Kekse. Er liebt alle Arten von Keksen, die seine Mutter macht. Aber seine Mutter ist sehr streng und hat das Gefühl, dass zu viele Kekse nicht gut für ihn sind. Also macht seine Mutter eine Regel, dass er die Kekse erst um 8 Uhr bekommt.
An diesem Tag um 7:45 Uhr rennt Satoshi zu seiner Mutter und fragt nach Keksen. Seine Mutter fragt: "Wie spät ist es?"
"Es ist 8 Uhr!" - er antwortet.
"Okay. Dann nimm die Kekse aus meinem Schrank.“
Und so konnte Satoshi die Zeit erfolgreich um 15 Minuten manipulieren, damit er seine Kekse bekommen konnte! Was für ein kekshungriger Kerl!
Codebeispiel aus der realen Welt:
Der Zeitstempel eines Blocks kann um etwa manipuliert werden 15 Sekunden von einem Bergmann. Auf diese Weise kann ein Miner einen günstigen Zeitstempel setzen und seine Transaktion in denselben Block aufnehmen, den er abbaut. Die Funktion play()
gehört zu einem Spielvertrag namens G-Dot.
function play() public { require(now > 1640392200 && neverPlayed == true); neverPlayed = false; msg.sender.transfer(1500 ether);
}
Dieser Vertrag belohnt den Spieler, der als erster die Spielfunktion aufruft, mit 1500 Ether. Aber wie Sie sehen können, kann die Play-Funktion nur aufgerufen werden, wenn der now- oder block.timestamp der Transaktion, die den Aufruf enthält, die play()
Funktion, ist größer als die Epoche Zeit 1640392200
Ein Miner kann diesen Zeitstempel leicht manipulieren und seine Transaktion zum Aufrufen der play()
Funktion im selben Block, so dass er selbst der erste Spieler ist. Auf diese Weise ist garantiert, dass der Miner das Spiel gewinnt!
Einfluss:
Der block.timestamp wurde verwendet, um Zufallszahlen in der zu generieren Governmental und war somit anfällig für Zeitmanipulationsangriffe.
Kontaktieren Sie QuillAudits
QuillAudits ist eine sichere Plattform für intelligente Vertragsprüfungen, die von . entwickelt wurde QuillHasch
Technologien
Es handelt sich um eine Auditing-Plattform, die Smart Contracts rigoros analysiert und verifiziert, um durch effektive manuelle Überprüfung mit statischen und dynamischen Analysetools, Gasanalysatoren sowie Simulatoren auf Sicherheitslücken zu prüfen. Darüber hinaus umfasst der Auditprozess auch umfangreiche Unit-Tests sowie Strukturanalysen.
Wir führen sowohl Smart Contract Audits als auch Penetrationstests durch, um Potenziale zu finden
Sicherheitslücken, die die Integrität der Plattform beeinträchtigen könnten.
Wenn Sie Unterstützung bei der Prüfung von Smart Contracts benötigen, können Sie sich gerne an unsere Experten wenden hier!
Um über unsere Arbeit auf dem Laufenden zu sein, treten Sie unserer Community bei:-
Twitter | LinkedIn | Facebook | Telegram
Die Post Anfängerleitfaden für Smart Contract Auditing: Teil 1 erschien zuerst auf Quillhash-Blog.
Quelle: https://blog.quillhash.com/2022/01/19/beginners-guide-to-smart-contract-auditing-part-1/
- "
- &
- 000
- 2016
- 7
- Über uns
- Konto
- Adresse
- Alle
- bereits
- Obwohl
- Analyse
- Prüfung
- Autonom
- Anfang
- BESTE
- Bitcoin
- Blockchain
- Fehler
- Kaufe
- rufen Sie uns an!
- Fälle
- Schecks
- klassisch
- Code
- Münze
- Kombination
- gemeinsam
- community
- enthält
- Vertrag
- Verträge
- Cookies
- könnte
- Erstellen
- Krypto
- Strom
- DAO
- Tag
- dezentralisiert
- Denial of Service
- Detail
- Dex
- nach unten
- leicht
- essen
- ETH
- Äther
- Astraleum
- Ethereum Blockchain
- Astraleum Klassik
- Beispiel
- Ausnutzen
- Ende
- Vorname
- Frei
- Funktion
- Spiel
- Games
- GAS
- erzeugen
- GitHub
- gehen
- gut
- Guide
- hacken
- Hacks
- Hash-
- ganzer
- hier
- Ultraschall
- HTTPS
- untersuchen
- IT
- Javac
- join
- springen
- King
- Sprache
- grosse
- Line
- Lang
- suchen
- Lotterie
- Mann
- Million
- Mutter
- Zahlen
- Organisation
- Papier
- Schnittmuster
- AUFMERKSAMKEIT
- Personen
- Stück
- Plattform
- Play
- Spieler
- Ponzi
- Ponzi-Schema
- Werkzeuge
- Prozessdefinierung
- Programmierer
- Programmierung
- Öffentlichkeit
- rückgängig machen
- Überprüfen
- Belohnung
- Ohne eine erfahrene Medienplanung zur Festlegung von Regeln und Strategien beschleunigt der programmatische Medieneinkauf einfach die Rate der verschwenderischen Ausgaben.
- Satoshi
- Sicherheitdienst
- kompensieren
- smart
- Smart-Vertrag
- Smart Contracts
- So
- solide
- etwas
- Wirbelsäule ... zu unterstützen.
- gespalten
- begonnen
- Erklärung
- Strategie
- erfolgreich
- Erfolgreich
- Tech
- Tests
- Durch
- Zeit
- Werkzeuge
- Transaktion
- unbanked
- Universität
- Updates
- Wert
- Sicherheitslücken
- Verwundbarkeit
- Verwundbar
- Wallet
- Was
- Rad
- WHO
- gewinnen
- Arbeiten
- Schreiben