Enkele valkuilen met smart contracts in Ethereum

Ethereum is het populairste blockchainplatform voor smart contracts. Dit zijn in feite stukjes code die gedistribueerd worden uitgevoerd binnen een blockchainnetwerk. Voor iemand met een beetje programmeerachtergrond ziet een smart contract in Ethereum eruit als normale code. Toch zijn er specifieke valkuilen waarop je moet letten en waar zelfs kenners zich tegen bezondigen. Twee denkfouten hieronder geven aan dat de realiteit toch wat complexer is dan ze op het eerste zicht doet vermoeden.

Denkfout 1: alle parameters mee in de blockchain?
Eind 2016, op een seminar over smart contracts, probeerde een van de sprekers ons te overtuigen van de eenvoud van deze technologie. Helaas maakte hij zelf een fundamentele fout. Daaruit bleek dat hij eigenlijk – net zoals het publiek – nog onvoldoende de details over zijn onderwerp beheerste.

 Verkeerd doorgeven van parameters
Figuur 1: Verkeerd doorgeven van parameters

De spreker vertelde het volgende: een smart contract liet een notaris toe om aan te geven dat een document verwerkt was. De code wordt – licht vereenvoudigd – weergegeven in figuur 1. De notaris registreert een document via de functie 'notarize()'. Deze functie voegt normaliter aan de variabele ‘proofs’ een element toe dat bestaat uit de unieke SHA-256-vingerafdruk van het document (32 bytes-hash), en de waarde ‘true’. Op het eerste gezicht lijkt dit prima.

Het oproepen van een functie die de contracttoestand wijzigt, gebeurt hier echter via een transactie die op de blockchain terechtkomt. Om de notarize()-functie uit te voeren, creëert de notaris met zijn private sleutel een transactie. Daarin zit onder meer het adres van het smart contract, de identificatiesleutel van de functie, en ook – dit is essentieel hier – de parameters die aan de functie meegegeven worden.

Hoewel enkel de vingerafdruk van het document in het smart contract terechtkomt, wordt dus het volledige document (!) in een transactie op de blockchain bewaard. Dat maakt niet enkel de blockchain al gauw onhandelbaar groot. Ook worden alle verwerkte documenten, die uiteraard gevoelige gegevens bevatten, voor de hele wereld toegankelijk. Eens een document in de Ethereum-blockchain terechtkomt, kan het in principe niet meer verwijderd of gewijzigd worden.

Maar er is meer. Wanneer een notaris code wil uitvoeren op een smart contract, dan moet hij daarvoor betalen. Ethereum-miners zullen immers alleen bereid zijn om je transactie te verwerken als ze daarvoor een voldoende hoge vergoeding krijgen. Je betaalt meer voor transacties die meer data bevatten, en je betaalt ook meer wanneer er meer rekenkracht en/of opslag vereist is voor het uitvoeren van de code zelf. Samen zou het oproepen van deze notarize()-functie voor een document van 1MB eind december 2017 al een kleine 2.000 dollar gekost hebben.

Figuur 2. Gecorrigeerd, maar niet zo nuttig smart contract
Figuur 2. Gecorrigeerd, maar niet zo nuttig smart contract

Al deze zaken kunnen eenvoudig verholpen worden door de vingerafdruk (hash) op de client te berekenen en enkel dit als parameter mee te geven aan de notarize()-functie. Dat resulteert in de code in figuur 2. De ironie is dat we in het smart contract nu gewoon sleutelparen opslaan – wat evengoed kan zonder smart contracts. Een erg overtuigend voorbeeld om de meerwaarde van smart contracts aan te tonen, is dit dus helaas niet.

Denkfout 2: een contract is zelf ook een rekening
In het voorjaar van 2016 werd met blockchain een decentraal risicokapitaalfonds opgericht, genaamd The DAO. De basis is een set van smart contracts waarop je met Ether, de cryptomunt van Ethereum, stemrecht koopt. Hoe meer geld je in het contract stort, hoe meer stemrecht je hebt. Er konden projecten ingediend worden en wanneer een project voldoende ja-stemmen haalde, kreeg het financiering.

Op een gegeven moment bevatte het fonds 168 miljoen dollar aan Ether, wat gelijk was aan 14% van alle op dat moment bestaande Ether. Helaas bevatte het smart contract een bug, waardoor er 54 miljoen dollar weglekte naar de aanvaller. De meerderheid van de miners ging akkoord om de blockchain terug te draaien, waardoor de recentste geschiedenis van de blockchain collectief werd geschrapt en de aanval dus, volgens de blockchain althans, nooit gebeurd was.

Waar liep het fout? Om te participeren in open, publieke blockchainnetwerken, zoals bitcoin en Ethereum, registreer je eerst een externe account. Je maakt lokaal een publiek-privaat sleutelpaar aan. De private sleutel houd je geheim. Een vingerafdruk van je publieke sleutel (20 bytes-hash) is je adres. Met dit adres als pseudoniem ben je gekend op de blockchain. Anderen kunnen dan cryptogeld storten naar dit adres en met je private sleutel kun je dit geld transfereren naar andere adressen, of smart contracts publiceren en/of gebruiken.

Maar, ook een contract heeft een adres en is in staat om cryptogeld te ontvangen, vast te houden en te spenderen. In dit geval spreken we van een 'contract account'. Wanneer een smart contract geld ontvangt, zonder dat expliciet gevraagd wordt om een bepaalde functie in het smart contract uit te voeren, dan wordt de basisfunctie uitgevoerd. Die noteren we als: function (){…}.

Wanneer een externe account de functie splitDAO() oproept, zoals in figuur 3, kan onrechtstreeks de payOut()-functie opgeroepen worden, die een bedrag (_amount) naar het adres van de oproeper stort. Pas nadien zal de functie splitDAO() onder andere de balans van de gebruiker in het smart contract overeenkomstig op nul zetten.

Figuur 3. Zolang de splitDAO uitgevoerd wordt door een external account is er geen probleem.
Figuur 3. Zolang de splitDAO uitgevoerd wordt door een external account is er geen probleem.

Het loopt fout wanneer de oproeper van de functie splitDAO() geen externe account is, maar zélf een contract account. Daardoor wordt een recursieve aanval mogelijk, zoals geïllustreerd in figuur 4:

  1. Het contract van de aanvaller roept de splitDAO()-functie op.

  2. Daardoor stort The DAO een bedrag (_amount) naar het contract van de aanvaller.

  3. Dit resulteert in het oproepen van de basisfunctie van het aanvallende contract.

  4. De basisfunctie van het aanvallende contract voert opnieuw de splitDAO()-functie uit. We springen opnieuw naar stap 2.

Figuur 4. Wanneer splitDAO uitgevoerd wordt door een contract account, is er een probleem.
Figuur 4. Wanneer splitDAO uitgevoerd wordt door een contract account, is er een probleem.

Deze aanval kan een tijdje doorgaan zonder dat de laatste regels van de splitDAO()-functie uitgevoerd worden – dus zonder dat de balans van het aanvallende contract (balances[msg.sender]) op nul wordt gezet en waardoor steeds hetzelfde bedrag naar het aanvallende contract gestort wordt.

Uiteindelijk stopt de uitvoering: hetzij omdat het geld dat de aanvaller meestuurt om code uit te voeren is opgebruikt, hetzij omdat de stacklimiet is bereikt, hetzij omdat er geen geld meer in The DAO aanwezig is. Behalve in het laatste geval kan de aanval probleemloos herhaald worden.

Conclusies
Dit artikel gaat in op twee programmeervalkuilen in Ethereum-smart contracts. Er zijn nog heel wat andere voorbeelden van – achteraf gezien – triviale bugs, waarmee soms veel geld verloren ging. In november 2017 ging nog zo’n 300 miljoen dollar verloren. Om het risico op bugs te reduceren, laat u uw smart contract voor publicatie dus het best nakijken door een deskundige.

Bovendien blijven er ook klassieke aanvallen bestaan, waarbij bijvoorbeeld de aanvaller de website van een bedrijf hackt en het adres van een smart contract van het bedrijf vervangt door een adres van zijn eigen smart contract. Ook phising blijft een klassieker: de aanvaller stuurt een mail die afkomstig lijkt van een serieus bedrijf, met de vraag om cryptogeld te investeren in een interessant smart contract. Uiteraard is dit niet het smart contract van het bedrijf, maar wel van de aanvaller.

Kristof Verslype is privacy, crypto & blockchain researcher bij Smals.

Tag

Onderwerp



Niet gevonden? Vraag het de redactie!

Heeft u het antwoord op uw vraag niet gevonden, of bent u op zoek naar specifieke informatie? Laat het ons weten! Dan zorgen we ervoor dat deze content zo snel mogelijk wordt toegevoegd, of persoonlijk aan u wordt geleverd!

Stel uw vraag