Velkommen til nybegynnerveiledningen til smart kontraktrevisjon! En av de beste måtene å komme i gang med smart kontraktrevisjon er å hoppe inn og se på noen få vanlige typer sårbarheter i smarte kontrakter.
Det ville være nyttig hvis du allerede har en grunnleggende forståelse av Ethereums programmeringsspråk Solidity. Som vi skal se på noen av kodene skrevet av Noob solidity-programmerere.
Re-entrancy Attack
Scenario i den virkelige verden:
Tenk deg at du har 50 sjokolader. Du har en slem lillesøster som du har tillatt å ta bare 2 sjokolader fra deg til enhver tid. Du vil heller ikke gi mer enn 10 sjokolader til henne på en dag, i frykt for at hun skal få tannråte. For å sikre dette, teller du hver kveld hvor mange sjokolader som er igjen hos deg. Tror du dette vil fungere? Eller ville du blitt hacket av lillesøsteren din?
Dessverre vil det ikke fungere! Søsteren din finner ut at du ikke er klar over hvor mye sjokolade du har før det er kveld. Så allerede dagen etter besøker lillesøsteren din deg 6 ganger før kvelden og tar 2 sjokolader hver gang! Dette er det vi kaller et Re-entrancy-angrep.
Her oppdaterer du antallet sjokolader du har på kvelden i stedet for å oppdatere antallet hver gang søsteren din tar 2 sjokolader fra deg. Dette er også hva som skjer med smart kontrakt. Den smarte kontrakten forutsetter en spesiell balanse mens angriperen faktisk er opptatt med å trekke ut en viss mengde krypto fra kontrakten flere ganger.
Eksempel på ekte verdenskode:
Denne koden tilhører en smart kontrakt kalt unbanked. Hvem som helst kan trekke eter fra en ubanket kontrakt så lenge saldoen til msg.sender (dvs. den som ringer til withdraw
funksjon ) er større enn eller lik beløpet som er bedt om å ta ut.
function withdraw(uint _amount) { require(balances[msg.sender] >= _amount); msg.sender.call.value(_amount)(); balances[msg.sender] -= _amount;
}
Legg merke til at det er et anropsnøkkelord som brukes til å sende den nødvendige mengden eter til msg.sender
. En angriper kan utnytte dette ved å lage en kontrakt kalt Thief der han kaller tilbaketrekningsfunksjonen i en fallback()
funksjon. EN fallback()
funksjon i Solidity er en spesiell funksjon som blir utført når eter sendes til den smarte kontrakten.
Dette betyr at en angriper er i stand til det kaller tilbaketrekningsfunksjonen rekursivt. Dermed, før den smarte kontrakten oppdateres, vil saldoene på msg.sender
på siste kodelinje har angriperen allerede trukket tilbake eter flere ganger. Dette kan unngås hvis saldoene oppdateres før du bruker anropsnøkkelordet, og dermed følger en sjekker-effekter-interaksjoner mønster.
Innvirkning:
De tidenes første Reentrancy Attack skjedde i 2016 på en DAO (Decentralized Autonomous Organization) som resulterte i hacks på omtrent $50 millioner. For å reversere dette hacket delte Ethereum-fellesskapet Ethereum-blokkjeden som ga opphav til ETC (Ethereum Classic) og ETH (Ethereum).
Aritmetisk overløp og underløp
Scenario i den virkelige verden:
La oss spille et tankespill. Den består av et Spin-the-hjul, og vinneren avgjøres basert på det største tallet han kan få ved å snurre hjulet. Hjulet er merket over alt fra 256 til -256.
Reglene for spillet er at pekeren for alle spillerne hviler på 0 i begynnelsen av hvert spinn. Og en spiller har lov til å spinne bare i retning av negative tall. Hvordan vil du vinne dette spillet?
En god strategi for å vinne dette spillet hver gang vil være å snurre hjulet med en slik kraft at hjulet snurrer opp til -256 og deretter blir 256 på én gang. Dette er mulig fordi 256 kommer like etter -256 på hjulet. Dette er det vi kaller et aritmetisk underløp. Og aritmetisk overløp er bare omvendt av dette.
Eksempel på ekte verdenskode:
An underløp eller overløp skjer når en aritmetisk operasjon når sitt minimum eller maksimum.
function withdraw(uint _amount) public { require(balances[msg.sender] - _amount > 0); address payable to = payable(msg.sender); to.transfer(_amount); balances[msg.sender] -= _amount;
}
De _amount
parameteren til uttaksfunksjonen er et heltall uten fortegn. Verdien av balansekartleggingen (som er som en ordbok i python eller et nøkkelverdi-par i C++ eller Java) er også et heltall uten fortegn.
mapping(address => uint256) public balances
Den nødvendige oppgaven kontrollerer om saldoene på msg.sender
er positivt eller ikke. Men dette utsagnet vil alltid være sant selv om beløpet er større enn saldoene på msg.sender
. Dette er fordi både balances
og _amount
variabler er av typen heltall uten fortegn og deres aritmetiske resultat (etter underflyt) vil også være et heltall uten fortegn!
Og som du kanskje husker, er et usignert heltall alltid positivt. Dette betyr at en angriper kan ta ut et ubegrenset antall Ether fra smartkontrakten! Du kan finne et detaljert eksempel og implementeringskode for dette sikkerhetsproblemet her..
En annen viktig ting å merke seg her er at den aritmetiske operasjonen mellom si to heltall uten fortegn også er et heltall uten fortegn. Det kan være farlig om dette blir oversett i smarte kontrakter, da det kan resultere i uønskede sikkerhetsbrudd!
function votes(uint postId, uint upvote, uint downvotes) { if (upvote - downvote < 0) { deletePost(postId) }
}
Som du kanskje har lagt merke til i eksemplet ovenfor, er if-setningen ganske meningsløs som upvote - downvote
kommer alltid til å være positivt. Og innlegget vil bli slettet selv om downvotes
er større enn upvotes
. For å unngå slike angrep anbefales det å bruke en Solidity-kompilatorversjon større enn 0.8.0.
Innvirkning:
En mynt som heter PoWH mynt ble lansert i 2017. Selv om det var et Ponzi-spill, ble det selv hacket på grunn av en aritmetisk overløpsfeil som resulterte i et tap på rundt 866 ETH eller $950,000 XNUMX på den tiden. Du kan lese om dette i detalj her..
Må lese: Lærdom fra angrepet på Tinyman, største DEX på Algorand
Denial of Service Attack
Scenario i den virkelige verden:
Tenk deg at du er på et Bitcoin Tech University. Alt virker greit bortsett fra at det er felles spisebord for alle. Og dessverre er det få personer fra en annen klasse som alltid klarer å innta spisebordet før noen fra klassen din.
I det praktiske scenariet nekter de den essensielle tjenesten til alle, noe som resulterer i dyrebar tidstap. Dette er det vi kaller et «Denial of Service-angrep».
Eksempel på ekte verdenskode:
I spillet kalt Eterens konge, hvem som helst kan bli konge. Men regelen for å bli konge er at en person skal deponere mer eter enn den nåværende kongen. Dette kan gjøres ved å ringe til claimThrone()
funksjonen til King of Ether-kontrakten der personen sender eter direkte til den forrige kongen og blir den nye kongen.
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; }
Som du kanskje har gjettet, er denne koden sårbar for et DoS-angrep, men hvordan? For dette må du forstå at det er to typer adresser i Ethereum - først er adresse til en ekstern eid konto eller rett og slett adressen til en lommebok, og den andre er kontraktsadresse. Nå kan eteren sendes fra en av disse adressetypene.
Hvis dette, eter sendes av kontraktsadressen, vil kontrakten bli kongen. Men la oss anta at denne nye kontrakten ikke har en fallback()
funksjon som er nødvendig hvis kontrakten ønsker å akseptere eter. Så hvis en ny person kommer og prøver å ringe claimThrone()
funksjon, vil den alltid mislykkes!
Legg merke til at dette også skjer delvis fordi claimThrone()
funksjonen sjekker eksplisitt om overføringen av eter var vellykket eller ikke i den andre påkrevde uttalelsen. Du kan finne hele koden og gjøre et DoS-angrep på den her..
Det er også mulig for en kode å være sårbar for et DoS-angrep hvis koden har en sløyfe over en rekke store størrelser. Dette skjer fordi gassgrense kan overskrides i slike tilfeller. Du kan lese om det her..
Innvirkning:
Et spill som heter Regjeringsmessig, som tilsynelatende var et Ponzi-opplegg, ble sittende fast med 1100 eter fordi en stor mengde gass var nødvendig for å behandle utbetalingen.
Usikker tilfeldighet
Scenario i den virkelige verden:
En gang var det en mann som het Hesky som alltid ble ledsaget av apen Pesky. Hesky drev lotterispill og hadde god fortjeneste. En dag la Alice merke til at Hesky stirret intenst på apen Pesky. Så så hun at han skrev noe på et papir og forseglet det i en konvolutt. Nysgjerrig bestemte hun seg for å undersøke nærmere.
Senere samme kveld så Alice at vinneren av lotteriet ble avgjort ved å åpne den forseglede konvolutten offentlig. Etter å ha sett ham i noen dager, fant Alice ut at Hesky bestemte vinnerlotteriet ved å se på Peskys bevegelser (hvis apen for eksempel klørte seg i hodet, skrev Hesky ned 10)! Nå hadde Alice formelen for å vinne hvert lotteri og måtte bare kjøpe lodd med riktig nummer!
Hesky hadde antatt at hans "tilfeldige" måte å avgjøre vinneren av lotteriet aldri kan finne ut, men han var faktisk feil.
Eksempel på ekte verdenskode:
I dette eksemplet genereres et tilfeldig tall basert på hashen til kombinasjonen av blokkens nummer og blokktidsstempelet. denne hashen tilordnes deretter svarvariabelen. Nå får alle som gjetter dette (tilsynelatende) tilfeldige tallet 1 Ether. Tror du dette er uhacks?
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"); } }
Nei! En angriper kan fortsatt gjette dette tilfeldige tallet ved å kopiere og lime inn koden for å generere verdien som er tildelt svarvariabelen, og sende den samme svarvariabelen til guess()
funksjon!
guessTheRandomNumber.guess(answer);
Du kan finne hele koden her.. For å unngå dette angrepet, anbefales det å bruke en verifiserbar tilfeldig funksjon som f.eks Chainlink VRF.
Innvirkning:
Omtrent 400 ETH gikk tapt på grunn av et angrep på Smart Billions-lotteri kontrakt. Overraskende nok var selve kontraktslotteriet et Ponzi-opplegg (au!).
Tidsmanipulasjon
Scenario i den virkelige verden:
Satoshi elsker å spise småkaker. Han elsker alle typer kaker som moren hans lager. Men moren hans er veldig streng og føler at det ikke er bra for ham å spise for mange småkaker. Så moren hans lager en regel om at han får kakene først klokken 8.
Den dagen klokken 7 løper Satoshi til moren sin og ber om informasjonskapsler. Moren hans spør: "Hva er klokken?"
"Klokken er 8"! – svarer han.
"Greit. Ta så kakene fra skapet mitt.»
Og dermed var Satoshi i stand til å manipulere tiden med 15 minutter slik at han kunne få informasjonskapslene sine! For en kakesulten kar!
Eksempel på ekte verdenskode:
Tidsstemplet til en blokk kan manipuleres med ca 15 sekunder av en gruvearbeider. På denne måten kan en gruvearbeider sette et gunstig tidsstempel og inkludere sin transaksjon i den samme blokken han miner. Funksjonen play()
tilhører en spillkontrakt kalt G-Dot.
function play() public { require(now > 1640392200 && neverPlayed == true); neverPlayed = false; msg.sender.transfer(1500 ether);
}
Denne kontrakten belønner 1500 eter til spilleren som er den første som ringer spillefunksjonen. Men som du kan se, kan avspillingsfunksjonen bare kalles hvis nå eller blokk.tidsstempel for transaksjonen som inneholder anropet til play()
funksjon, er større enn epoketid 1640392200.
En gruvearbeider kan enkelt manipulere dette tidsstemplet og inkludere transaksjonen hans med å ringe play()
fungere i samme blokk slik at han selv er den første spilleren. På denne måten er det garantert at gruvearbeideren vinner spillet!
Innvirkning:
Block.timestamp ble brukt til å generere tilfeldige tall i statlig og var dermed sårbar for tidsmanipulasjonsangrep.
Ta kontakt med QuillAudits
QuillAudits er en sikker smart kontraktrevisjonsplattform designet av QuillHash
Technologies.
Det er en revisjonsplattform som grundig analyserer og verifiserer smarte kontrakter for å se etter sikkerhetssårbarheter gjennom effektiv manuell gjennomgang med statiske og dynamiske analyseverktøy, gassanalysatorer og assimulatorer. I tillegg inkluderer revisjonsprosessen omfattende enhetstesting samt strukturelle analyser.
Vi gjennomfører både smarte kontraktrevisjoner og penetrasjonstester for å finne potensiale
sikkerhetssårbarheter som kan skade plattformens integritet.
Hvis du trenger hjelp til revisjonen av smarte kontrakter, ta gjerne kontakt med ekspertene våre her!
Bli med i fellesskapet vårt for å være oppdatert med arbeidet vårt:-
Twitter | Linkedin | Facebook | Telegram
Innlegget Nybegynnerveiledning til smart kontraktrevisjon: del 1 dukket først på Quillhash-blogg.
Kilde: https://blog.quillhash.com/2022/01/19/beginners-guide-to-smart-contract-auditing-part-1/
- "
- &
- 000
- 2016
- 7
- Om oss
- Logg inn
- adresse
- Alle
- allerede
- Selv
- analyse
- revisjon
- autonom
- Begynnelsen
- BEST
- Bitcoin
- blockchain
- Bug
- kjøpe
- ring
- saker
- Sjekker
- Classic
- kode
- Coin
- kombinasjon
- Felles
- samfunnet
- inneholder
- kontrakt
- kontrakter
- cookies
- kunne
- Opprette
- krypto
- Gjeldende
- DAO
- dag
- desentralisert
- Denial of Service
- detalj
- Dex
- ned
- lett
- spise
- ETH
- Eter
- ethereum
- Ethereum blockchain
- Ethereum Classic
- eksempel
- Exploit
- slutt
- Først
- Gratis
- funksjon
- spill
- Games
- GAS
- generere
- GitHub
- skal
- god
- veilede
- hack
- hacks
- hash
- hode
- her.
- Hvordan
- HTTPS
- undersøke
- IT
- Java
- bli medlem
- hoppe
- konge
- Språk
- stor
- linje
- Lang
- ser
- lotteri
- mann
- millioner
- mor
- tall
- organisasjon
- Papir
- Mønster
- Betale
- porsjoner
- brikke
- plattform
- Spille
- spiller
- ponzi
- Ponzi-ordningen
- makt
- prosess
- programmerere
- Programmering
- offentlig
- reversere
- anmeldelse
- Belønninger
- regler
- Satoshi
- sikkerhet
- sett
- Smart
- smart kontrakt
- Smarte kontrakter
- So
- soliditet
- noe
- Snurre rundt
- splittet
- startet
- Uttalelse
- Strategi
- vellykket
- vellykket
- tech
- tester
- Gjennom
- tid
- verktøy
- Transaksjonen
- unbanked
- universitet
- oppdateringer
- verdi
- Sikkerhetsproblemer
- sårbarhet
- Sårbar
- lommebok
- Hva
- Hjul
- HVEM
- vinne
- Arbeid
- skriving