Tere tulemast arukate lepingute auditeerimise juhendisse algajatele! Üks parimaid viise arukate lepingute auditeerimisega alustamiseks on hüpata ja vaadata mõnda levinumat nutikate lepingute haavatavust.
Oleks abiks, kui teil on juba põhiteadmised Ethereumi Solidity programmeerimiskeelest. Vaatleme mõningaid Noobi solidity programmeerijate kirjutatud koode.
Sissepääsu rünnak
Reaalse maailma stsenaarium:
Kujutage ette, et teil on 50 šokolaadi. Sul on ulakas väike õde, kellel oled lubanud endalt korraga võtta ainult 2 šokolaadi. Samuti ei taha te talle päevas rohkem kui 10 šokolaadi anda, kartes, et tal tekib hambakaaries. Selle tagamiseks loendate igal õhtul, kui palju šokolaadi on teiega kaasas. Kas sa arvad, et see toimiks? Või saaks teie väike õde häkkida?
Kahjuks see ei tööta! Su õde mõistab, et sa pole õhtuni teadlik, kui palju šokolaadi sul on. Nii et juba järgmisel päeval külastab teie väike õde teid 6 korda enne õhtut ja võtab iga kord 2 šokolaadi! Seda me nimetame taassisenemise rünnakuks.
Siin värskendate õhtuste šokolaadide arvu, selle asemel et värskendada loendust iga kord, kui teie õde võtab teilt 2 šokolaadi. See juhtub ka nutika lepinguga. Nutikas leping eeldab teatud tasakaalu, samal ajal kui ründaja on tegelikult hõivatud lepingust teatud koguse krüpto väljavõtmisega mitu korda.
Reaalse maailma koodi näide:
See kood kuulub nutikale lepingule nimega Unbanked. Igaüks võib pangakontota lepingust eetri välja võtta seni, kuni sõnumi saatja (st helistaja) saldod on withdraw
funktsioon ) on suurem või võrdne väljavõetava summaga.
function withdraw(uint _amount) { require(balances[msg.sender] >= _amount); msg.sender.call.value(_amount)(); balances[msg.sender] -= _amount;
}
Pange tähele, et vajaliku koguse eetri saatmiseks seadmesse kasutatakse kõne märksõna msg.sender
. Ründaja saab seda ära kasutada, luues lepingu nimega Thief, milles ta kutsub a-s väljatõmbumisfunktsiooni fallback()
funktsioon. A fallback()
Solidity funktsioon on spetsiaalne funktsioon, mis käivitatakse siis, kui nutikasse lepingusse saadetakse eeter.
See tähendab, et ründaja on võimeline rekursiivselt kutsuda väljatõmbamisfunktsiooni. Seega, enne nutika lepingu värskendusi, saldod msg.sender
koodi viimasel real on ründaja juba mitu korda eetri eemaldanud. Seda saab vältida, kui saldosid värskendatakse enne kõne märksõna kasutamist, järgides seega a kontrollid-mõjud-koosmõjud muster.
Mõju:
. esimene Reentrancy Attack juhtus 2016. aastal DAO-s (detsentraliseeritud autonoomne organisatsioon), mille tulemuseks oli umbes 50 miljoni dollari suurune häkkimine. Selle häkkimise ümberpööramiseks jagas Ethereumi kogukond Ethereumi plokiahela, millest sündisid ETC (Ethereum Classic) ja ETH (Ethereum).
Aritmeetiline üle- ja allavool
Reaalse maailma stsenaarium:
Mängime mõttemängu. See koosneb ratta keerutamisest ja võitja otsustatakse suurima arvu järgi, mille ta ratast keerutades suudab saada. Ratas on kõikjal tähistatud vahemikus 256 kuni -256.
Mängu reeglid on sellised, et kõigi mängijate osuti jääb iga keerutuse alguses 0-le. Ja mängijal on lubatud keerutada ainult negatiivsete numbrite suunas. Kuidas sa selle mängu võidad?
Hea strateegia selle mängu iga kord võitmiseks oleks ratast keerutada sellise võimsusega, et ratas pöörleb kuni -256 ja seejärel ühe hooga 256 peale. See on võimalik, sest 256 tuleb kohe pärast -256 roolil. Seda me nimetame aritmeetiliseks allavooluks. Ja aritmeetiline ületäitumine on just vastupidi.
Reaalse maailma koodi näide:
An alla- või ülevool juhtub siis, kui aritmeetiline tehe saavutab oma miinimumi või maksimumi.
function withdraw(uint _amount) public { require(balances[msg.sender] - _amount > 0); address payable to = payable(msg.sender); to.transfer(_amount); balances[msg.sender] -= _amount;
}
. _amount
tagasivõtmise funktsiooni parameeter on märgita täisarv. Saldode kaardistamise väärtus (mis on nagu sõnastik pythonis või võtme-väärtuste paar C++ või Java puhul) on samuti märgita täisarv.
mapping(address => uint256) public balances
Nõutav väljavõte kontrollib, kas saldod on msg.sender
on positiivne või mitte. Kuid see väide on alati tõsi, isegi kui summa on suurem kui saldod msg.sender
. Seda seetõttu, et mõlemad balances
ja _amount
muutujad on tüüpi märgita täisarv ja nende aritmeetiline tulemus (pärast allavoolu) on samuti märgita täisarv!
Ja nagu mäletate, on märgita täisarv alati positiivne. See tähendab, et ründajal on võimalik nutilepingust välja võtta piiramatu kogus Eetrit! Selle haavatavuse kohta leiate üksikasjaliku näite ja rakenduskoodi siin.
Teine oluline asi, mida siinkohal märkida, on see, et aritmeetiline tehe näiteks kahe märgita täisarvu vahel on samuti märgita täisarv. See võib olla ohtlik, kui seda nutikate lepingute puhul eiratakse, kuna see võib põhjustada soovimatuid turvarikkumisi!
function votes(uint postId, uint upvote, uint downvotes) { if (upvote - downvote < 0) { deletePost(postId) }
}
Nagu võisite ülaltoodud näites märgata, on if-lause üsna mõttetu as upvote - downvote
on alati positiivne. Ja postitus kustutatakse isegi siis, kui downvotes
on suurem kui upvotes
. Selliste rünnakute vältimiseks on soovitatav kasutada Solidity kompilaatori versiooni, mis on suurem kui 0.8.0.
Mõju:
Münt nimega PoWH münt lasti turule aastal 2017. Kuigi tegemist oli Ponzi mänguga, sai see ise häkitud aritmeetilise ülevooluvea tõttu, mille tulemusel kaotati toona umbes 866 ETH ehk 950,000 XNUMX dollarit. Selle kohta saate üksikasjalikult lugeda siin.
Pead lugema: Õppetunnid rünnakust Tinymani vastu, Algorandi suurim DEX
Teenuse keelamise rünnak
Reaalse maailma stsenaarium:
Kujutage ette, et olete Bitcoini tehnikaülikoolis. Kõik tundub hästi, välja arvatud see, et kõigile on ühine söögilaud. Ja kahjuks on vähe inimesi teisest klassist, kes jõuavad alati enne kedagi teie klassist söögilauda hõivata.
Praktilise stsenaariumi korral keelavad nad olulise teenuse osutamise kõigile, mille tulemuseks on väärtusliku ajakaotus. Seda me nimetame teenuse keelamise rünnakuks.
Reaalse maailma koodi näide:
Mängus nimega Eetri kuningas, igaüks võib saada kuningaks. Kuid kuningaks saamise reegel on see, et inimene peab talletama rohkem eetrit kui praegune kuningas. Seda saab teha helistades claimThrone()
Eetri kuninga lepingu funktsioon, mille kohaselt isik saadab eetri otse eelmisele kuningale ja temast saab uus kuningas.
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; }
Nagu võis arvata, on see kood DoS-i rünnaku suhtes haavatav, kuid kuidas? Selleks peate mõistma, et Ethereumis on kahte tüüpi aadresse – esimene on välise aadressi konto või lihtsalt rahakoti aadress ja teiseks on lepingu aadress. Nüüd saab eetrit saata mõlemalt aadressitüübilt.
Kui see, eeter saadetakse lepinguaadressil, saab lepingust kuningas. Kuid oletame, et sellel uuel lepingul pole a fallback()
funktsioon, mis on vajalik, kui leping soovib eetrit aktsepteerida. Siis kui uus inimene tuleb ja proovib helistada claimThrone()
funktsiooni, ebaõnnestub see alati!
Pange tähele, et see juhtub osaliselt ka seetõttu, et claimThrone()
funktsioon kontrollib selgesõnaliselt, kas eetri ülekanne oli teises nõutud avalduses edukas või mitte. Saate leida täieliku koodi ja teha sellele DoS-rünnaku siin.
Samuti on võimalik, et kood on DoS-i rünnaku suhtes haavatav, kui koodil on silmus suures massiivis. See juhtub seetõttu, gaasi piirmäär võib sellistel juhtudel ületada. Saate selle kohta lugeda siin.
Mõju:
Mängu nimetatakse GovernMental, mis oli ilmselt Ponzi skeem, jäi 1100 eetriga jänni, kuna väljamakse töötlemiseks oli vaja palju gaasi.
Ebakindel juhuslikkus
Reaalse maailma stsenaarium:
Elas kord mees nimega Hesky, kellega oli alati kaasas tema ahv Pesky. Hesky viis läbi loteriimänge ja teenis head kasumit. Ühel päeval märkas Alice, et Hesky vaatas pingsalt oma ahvi Peskyt. Siis nägi ta, et ta kirjutas midagi paberile ja sulges selle ümbrikusse. Uudishimulikuna otsustas ta asja edasi uurida.
Hiljem samal õhtul nägi Alice, et loterii võitja otsustati kinnise ümbriku avaliku avamise teel. Pärast teda mõnepäevast jälgimist sai Alice aru, et Hesky otsustas võitnud loteriinumbri, vaadates Pesky žeste (näiteks kui ahv kratsis pead, kirjutas Hesky üles 10)! Nüüd oli Alice'il iga loterii võidu valem ja tuli lihtsalt õige numbriga loteriipilet osta!
Hesky oli eeldanud, et tema "juhuslikku" viisi loterii võitja otsustamiseks ei saa kunagi välja mõelda, kuid ta oli tõepoolest vale.
Reaalse maailma koodi näide:
Selles näites genereeritakse juhuslik arv ploki numbri ja selle ploki ajatempli kombinatsiooni räsi põhjal. see räsi määratakse seejärel vastuse muutujale. Nüüd saavad kõik, kes selle (näiliselt) juhusliku arvu ära arvavad, 1 eetri. Kas see on teie arvates häkkimatu?
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"); } }
Ei! Ründaja võib selle juhusliku arvu siiski ära arvata, lihtsalt kopeerides kleepides koodi, et genereerida vastuse muutujale määratud väärtus, ja edastades sama vastuse muutuja guess()
funktsioon!
guessTheRandomNumber.guess(answer);
Täieliku koodi leiate siin. Selle rünnaku vältimiseks on soovitatav kasutada kontrollitavat juhuslikku funktsiooni, näiteks Ketilüli VRF.
Mõju:
Umbes 400 ETH läks kaduma rünnaku tõttu Nutikate miljardite loterii leping. Üllataval kombel oli isegi lepinguloterii ise Ponzi skeem (auh!).
Ajaga manipuleerimine
Reaalse maailma stsenaarium:
Satoshile meeldib küpsiseid süüa. Talle meeldivad igasugused küpsised, mida tema ema teeb. Tema ema on aga väga range ja tunneb, et liigne küpsiste söömine ei tee talle head. Nii teeb ta ema reegli, et ta saab küpsised alles kell 8 õhtul.
Samal päeval kell 7 jookseb Satoshi ema juurde ja küsib küpsiseid. Tema ema küsib: "Mis kell on?"
"Kell on kaheksa!" — vastab ta.
"Okei. Võtke siis minu kapist küpsised."
Ja seega suutis Satoshi 15 minutiga edukalt ajaga manipuleerida, et saaks oma küpsised kätte! Milline küpsise näljane plika!
Reaalse maailma koodi näide:
Ploki ajatemplit saab manipuleerida umbes 15 sekundit kaevandaja poolt. Sel viisil saab kaevandaja määrata soodsa ajatempli ja lisada oma tehingu samasse kaevandatavasse plokki. Funktsioon play()
kuulub mängulepingusse nimega G-Dot.
function play() public { require(now > 1640392200 && neverPlayed == true); neverPlayed = false; msg.sender.transfer(1500 ether);
}
Selle lepinguga premeeritakse 1500 eetrit mängijale, kes esimesena mängufunktsiooni kutsub. Kuid nagu näete, saab esitusfunktsiooni välja kutsuda ainult siis, kui selle tehingu nüüd või block.timestamp, mis sisaldab kõnet play()
funktsioon, on suurem kui ajastu aeg 1640392200.
Kaevur saab selle ajatempliga hõlpsasti manipuleerida ja lisada oma tehingu numbrile helistamiseks play()
funktsioon samas plokis nii, et ta ise on esimene mängija. Nii on garanteeritud, et kaevur võidab mängu!
Mõju:
Templit block.timestamp kasutati juhuslike arvude genereerimiseks Valitsus ja oli seega haavatav aja manipuleerimise rünnakute suhtes.
Võtke ühendust QuillAuditsiga
QuillAudits on turvaline nutikate lepingute auditi platvorm, mille on välja töötanud QuillHash
Tehnoloogiad.
See on auditeerimisplatvorm, mis analüüsib ja kontrollib hoolikalt nutikaid lepinguid, et kontrollida turvaauke, kasutades tõhusat käsitsi ülevaatust staatiliste ja dünaamiliste analüüsivahendite, gaasianalüsaatorite ja simulaatoritega. Lisaks hõlmab auditiprotsess ka ulatuslikku üksuse testimist ja struktuurianalüüsi.
Potentsiaali leidmiseks viime läbi nii nutikaid lepinguauditeid kui ka läbitungimisteste
turvanõrkused, mis võivad kahjustada platvormi terviklikkust.
Kui vajate nutikate lepingute auditeerimisel abi, võtke julgelt ühendust meie ekspertidega leiad siit!
Et olla meie tööga kursis, liituge meie kogukonnaga: -
puperdama | LinkedIn | Facebook | Telegramm
Postitus Aruka lepingute auditeerimise juhend algajatele: 1. osa ilmus esmalt Quillhashi ajaveeb.
Allikas: https://blog.quillhash.com/2022/01/19/beginners-guide-to-smart-contract-auditing-part-1/
- "
- &
- 000
- 2016
- 7
- MEIST
- konto
- aadress
- Materjal: BPA ja flataatide vaba plastik
- juba
- Kuigi
- analüüs
- audit
- autonoomne
- Algus
- BEST
- Bitcoin
- blockchain
- Bug
- ostma
- helistama
- juhtudel
- Kontroll
- klassika
- kood
- Münt
- kombinatsioon
- ühine
- kogukond
- sisaldab
- leping
- lepingud
- küpsised
- võiks
- loomine
- krüpto
- Praegune
- DAO
- päev
- Detsentraliseeritud
- Denial of Service
- detail
- Dex
- alla
- kergesti
- sööma
- ETH
- Eeter
- ethereum
- Ethereumi plokiahel
- Ethereum Classic
- näide
- Ekspluateeri
- lõpp
- esimene
- tasuta
- funktsioon
- mäng
- Mängud
- GAS
- tekitama
- GitHub
- läheb
- hea
- suunata
- näksima
- hacks
- hash
- juhataja
- siin
- Kuidas
- HTTPS
- uurima
- IT
- Java
- liituma
- hüppama
- kuningas
- keel
- suur
- joon
- Pikk
- otsin
- loterii
- mees
- miljon
- ema
- numbrid
- organisatsioon
- Paber
- Muster
- Maksma
- Inimesed
- tükk
- inimesele
- mängima
- mängija
- ponzi
- Ponzi skeem
- võim
- protsess
- Programmeerijad
- Programming
- avalik
- tagasikäik
- läbi
- Hüved
- eeskirjade
- Satoshi
- turvalisus
- komplekt
- nutikas
- arukas leping
- Tarkvaralepingud
- So
- kindlus
- midagi
- Spin
- jagada
- alustatud
- väljavõte
- Strateegia
- edukas
- Edukalt
- tech
- testid
- Läbi
- aeg
- töövahendid
- tehing
- panganduseta
- Ülikool
- Uudised
- väärtus
- Haavatavused
- haavatavus
- Haavatav
- rahakott
- M
- Ratas
- WHO
- võitma
- Töö
- kirjutamine