Hur förlorade Qubit Finance 80 miljoner dollar på en dag till hackare?

Svar: dålig ingångsvalidering i smarta kontrakt.

Historien om smarta kontrakt börjar i oktober 2008, när första whitepaper för bitcoin släpps av Satoshi Nakamoto. Även om namnet är allmänt känt så är det fortfarande okänt vem som ligger bakom det. Några månader senare, i januari 2009, lanserade Satoshi Nakamoto bitcoin-nätverket, släppte referensimplementeringen och genererade genesis-blocket.

Med detta föddes en ny teknik: blockkedjan. Bitcoin slog ihop sina föregångares tillvägagångssätt till en framgångsrik teknik som kan lösa det bysantinska generalproblemet i ett distribuerat system. I det här problemet måste varje deltagare komma till samma slutsats utan hjälp av en central part. Dessutom, i det specifika fallet med blockchain, kan deltagare vara illvilliga, så de kan ljuga medan de kommunicerar med de andra.

Observera att vi inte alls nämnde pengar eller bankverksamhet i samband med det bysantinska generalproblemet (The Byzantine Generals Problem BGP) . Det beror på att det ursprungliga problemet handlade om information och inte pengar. Men nuförtiden är bank bara en siffra i en reskontra, så nu handlar det om information. Som en konsekvens är manipulering av reskontran ett påtagligt hot. Och det är här decentralisering och det bysantinska generalproblemet kommer in i bilden. Om man skulle vilja skapa en huvudbok utan ett centralt parti, bör de först lösa det bysantinska generalproblemet.

Bitcoin är ett exempel på decentraliserade digitala pengar, som vi i allmänhet kallar kryptovalutor. I det här specifika fallet är namnet för den valutan också namnet på tekniken: Bitcoin (BTC). Vi använder det underliggande nätverket för att hantera pengar och därför är det intresse för alla som har pengar på sin reskontra att hålla igång nätet utan fel. Annars skulle deras pengar bli värdelösa. Bitcoin motiverar också deltagarna att underhålla nätverket genom att belöna dem när en av dem skapar ett nytt block för kedjan. För att en deltagare ska kunna skapa ett nytt block måste de först lösa ett komplext matematiskt problem. Genom att presentera beviset på sin lösning (därav namnet Proof of Work) måste andra erkänna det, och systemet kommer att belöna lösarens konto hos BTC.

More bits, more coins

Efter lanseringen använde folk inte Bitcoin i så stor utsträckning. Men efter ett tag blev det oerhört populärt, framför allt som en investering. Och naturligtvis, eftersom det blev lönsamt, kopierade många andra – eller åtminstone försökte kopiera – dess framgång och startade sina egna nätverk. Dessa nätverk använde samma idé (t.ex. blockchain med Proof of Work), eller en ändrad version av den (t.ex. blockchain med Proof of Stake). Det finns också många andra nätverk som använder någon icke-blockkedjebaserad idé (t.ex. Bysantine Paxos från 1999, eller Directed Acyclic Graph) för att lösa det bysantinska generalproblemet. Alla dessa teknologier tillsammans kallar vi Distributed Ledger Technologies (DLT).

Under åren, efter lanseringen av Bitcoin, uppstod många andra kryptovalutor. I allmänhet hänvisar vi till dem som altcoins (alternativa mynt). Nuförtiden finns det tusentals altcoins och deras antal växer fortfarande. 2014 var Ethereum den första DLT som implementerade en Turing-komplett smart kontraktsplattform. Frasen smart kontrakt var inte en ny term: den användes först av Nick Szabo 1994, men den blev allmänt känd först efter att Ethereum släpptes.

Är smarta kontrakt smarta nog?

Så vad är ett smart kontrakt? Det är i grunden ett program skrivet i något programmeringsspråk som körs automatiskt baserat på några fördefinierade villkor. Detta program uttrycker villkoren för en köpare och en säljare, såväl som konsekvenserna av att utföra kontraktet (vanligtvis utlöser en penningtransaktion). Dessutom, om vi lagrar det här programmet på en DLT, finns det inget behov av en central myndighet, allt kommer att utföras själv. Det är helt säkert, eller hur?

Buggar. Det handlar alltid om buggar. Smarta kontrakt är fortfarande bara program – och program är (oftast fortfarande) skrivna av människor som tyvärr gör misstag. Och hackare (som bär vita, grå, svarta eller vilka hattar som helst) söker kontinuerligt efter dessa svagheter.

Det finns många fall där buggar i ett DLT-ekosystem orsakade förlusten av en enorm summa pengar. Ta till exempel historien om Ethereum Classic, DAO Hack. En decentraliserad autonom organisation (därav namnet DAO) är ett DLT-baserat kooperativ där reglerna är formulerade och styrs av ett smart kontrakt. Så, vad händer om ett icke-modifierbart smart kontrakt innehåller en bugg i en sådan miljö? I så fall kan man möjligen använda den för att tappa lite pengar från sina (rättmätiga) ägare. I det här specifika fallet har några skurkar stulit eterkrypteringsvaluta värd 60 miljoner dollar på grund av en sårbarhet som kallas det rekursiva samtalsfelet. I det associerade attackscenariot bör en angripare sätta in ett belopp på en sårbar kontraktsinstans och sedan dra tillbaka det direkt. Under detta uttag anropas en uppsåtligt definierad reservfunktion, som kan ta ut beloppet igen, på grund av ett logiskt fel: saldot i den ursprungliga uttagsfunktionen minskas endast efter att reservfunktionen anropas, och inte före detta samtal. Sådana anrop kan till och med vara kapslade, därav den “rekursiva” i buggens namn.

Som ett svar beslutade en stor del av Ethereum-communityt att rulla tillbaka före de skadliga transaktionerna och starta ett separat nätverk. Genom att göra detta gjorde de en hård gaffel i systemet. Det gamla nätverket döptes om till Ethereum Classic, och det gaffelformade nätverket började som Ethereum igen.

Qubit Finance

Tyvärr var DAO Hack inte det enda hacket sedan 2009. Det fanns många fall där sårbara smarta kontrakt tillät att stjäla kryptovalutor. Ta till exempel fallet med en penningmarknadsplattform – Qubit Finance – som hackades den 27 januari 2022. Som en konsekvens av incidenten förlorade de Binance Coin (BNB) värt 80 miljoner dollar.

Qubit Finance är en plattform för en decentraliserad penningmarknad som kopplar samman långivare och låntagare på ett effektivt och dessutom – som de hävdade – säkert sätt. Bland annat tillhandahåller de också en brygga mellan Ethereum-nätverket och Binance Smart Chain (BSC), med vilken man kan flytta sina pengar mellan de två nätverken. Men på grund av en bugg kan man få en godtycklig mängd eter (ETH) till sitt förfogande i Binance Smart Chain utan att deponera några riktiga ETH:er i Ethereum-nätverket. Låt oss se hur.

I huvudsak, på grund av felaktig validering, kunde man deponera noll eter genom att anropa deposit()-funktionen och fortfarande få ett godtyckligt antal av dem i BSC, eftersom denna funktion inte svarade på en felaktig inmatning korrekt. På grund av att det indikerades en lyckad insättning, dök det önskade beloppet upp i BSC. Stegen var följande:

  1. Användaren bifogar någon ETH när han anropar deposit()-funktionen på Ethereum-nätverket. Parametrar inkluderar resurs-ID (från vilket tokenkontraktsadressen härrör), insättaren (angriparen i det här fallet) och mängden ETH man vill överföra (kodad i dataparametern).
  2. Den smarta kontraktskoden – specifikt deposit()-funktionen – validerar sedan den givna adressen (härledd från resursID) av en godkännandelista och anropar metoden safeTransferFrom() på den om allt är OK.
  3. En händelse avges att överföringen lyckades.
    Den problematiska deposit()-funktionen visas i följande kodavsnitt (källkoden är från ovan nämnda uppskrivning aforementioned writeup)

Lärdom igen: indatavalidering är viktigt!

På 1600-talet sa general Raimondo Montecuccoli att man behöver tre saker för krig: 1) pengar, 2) pengar, 3) pengar. Vi har i princip samma ordspråk när det kommer till mjukvarusäkerhet: du behöver tre saker: 1) validering, 2) validering och 3) ännu mer validering.

Så först och främst måste du göra validering. Men – som exemplet ovan visar tydligt – det räcker inte att ha det. Det måste också vara korrekt! Den måste stoppa dålig input och ska bara släppa igenom de värden som dina algoritmer är förberedda på. Vad är bra input och vad är dåligt? Tja, det beror på logiken i algoritmen.

Principen om fullständig medling (och en annan om försvar på djupet) säger att data inte bara ska valideras när de kommer in i systemet. Du bör validera den varje gång du är på väg att röra (använda) den – eftersom det är det bästa stället för koden att veta vad den ska valideras för. I linje med detta bör du inte vara rädd för ens överflödiga valideringar: mer validering är alltid bättre än ingen validering alls. Men återigen, som exemplet visar, kan en smart angripare ta sig igenom flera skyddslager, om de alla är felaktiga.

För denna specifika historia är korrekt validering ännu viktigare vid smarta kontrakt. Vi lagrar dem trots allt på blockkedjan och därför är de “oföränderliga”. När de väl kommer dit kan ingen ändra på dem. En svaghet förblir en svaghet för alltid.

Sammanfattningsvis kan programmerare ha undvikit denna stöld om den smarta kontraktskoden bara hade kontrollerat giltigheten av datan korrekt (åtminstone i en av kontrollerna), anpassad till indatavalideringens bästa praxis och principer. Eftersom indatavalidering är kärnan i säker kodning kan du lära dig hur du gör det i bokstavligen alla våra kurser.

Våra kurser:

Secure Coding in C and C++

Security testing C and C++ applications

Security testing Python Web applications

Security testing Java Web applications

Security testing C# Web applications

Web application security in Java

Web application security in C#