Dobrodošli v vodniku za začetnike po revidiranju pametnih pogodb! Eden najboljših načinov, da začnete z revizijo pametnih pogodb, je, da skočite in si ogledate nekaj pogostih vrst ranljivosti v pametnih pogodbah.
Koristno bi bilo, če že imate osnovno razumevanje programskega jezika Ethereum Solidity. Ogledali si bomo nekaj kod, ki so jih napisali programerji solidity Noob.
Napad ponovnega vstopa
Scenarij iz resničnega sveta:
Predstavljajte si, da imate 50 čokolad. Imate poredno sestrico, ki ste ji dovolili, da vam naenkrat vzame samo 2 čokoladi. Prav tako ji ne dajte več kot 10 čokoladic na dan, saj se bojite, da bo dobila zobno gnilobo. Da bi to zagotovili, vsak večer preštejte, koliko čokolad je ostalo pri vas. Mislite, da bi to delovalo? Ali pa bi vas vdrla vaša mlajša sestra?
Na žalost ne bo šlo! Tvoja sestra je ugotovila, da se ne zavedaš, koliko čokolad imaš, dokler ne zvečeri. Torej že naslednji dan vas sestrica pred večerom obišče 6-krat in vsakič vzame 2 čokoladi! Temu pravimo napad ponovnega vstopa.
Tukaj posodabljate število čokolad, ki jih imate zvečer, namesto da posodabljate število vsakič, ko vam sestra vzame 2 čokoladi. To se zgodi tudi s pametno pogodbo. Pametna pogodba predvideva določeno ravnotežje, medtem ko je napadalec dejansko zaposlen z večkratnim umikom določene količine kripto iz pogodbe.
Primer kode iz resničnega sveta:
Ta koda spada v pametno pogodbo, imenovano Brez banke. Vsakdo lahko dvigne ether iz pogodbe Unbanked, dokler je stanje pošiljatelja msg.sender (tj. klicatelja withdraw
funkcija ) je večji ali enak zahtevanemu znesku za dvig.
function withdraw(uint _amount) { require(balances[msg.sender] >= _amount); msg.sender.call.value(_amount)(); balances[msg.sender] -= _amount;
}
Upoštevajte, da obstaja ključna beseda klica, ki se uporablja za pošiljanje zahtevane količine etra na msg.sender
. Napadalec lahko to izkoristi tako, da ustvari pogodbo z imenom Thief, v kateri pokliče funkcijo umika v a fallback()
funkcijo. A fallback()
funkcija v Solidityju je posebna funkcija, ki se izvede, ko je eter poslan v pametno pogodbo.
To pomeni, da lahko napadalec rekurzivno pokličite funkcijo za umik. Tako se pred posodobitvijo pametne pogodbe stanje msg.sender
v zadnji vrstici kode je napadalec že večkrat dvignil ether. Temu bi se lahko izognili, če bi stanja posodobili pred uporabo ključne besede klic, torej po a pregledi-učinki-interakcije vzorec.
Učinek:
O prvi povratni napad v zgodovini zgodil leta 2016 na DAO (decentralizirana avtonomna organizacija), kar je povzročilo vdore v vrednosti približno 50 milijonov dolarjev. Da bi odpravila ta vdor, je skupnost Ethereum razdelila verigo blokov Ethereum, kar je povzročilo ETC (Ethereum Classic) in ETH (Ethereum).
Aritmetično prelivanje in prelivanje
Scenarij iz resničnega sveta:
Igrajmo se miselno igro. Sestavljen je iz vrtenja kolesa, zmagovalec pa se določi na podlagi največjega števila, ki ga lahko doseže pri vrtenju kolesa. Kolo je označeno od 256 do -256.
Pravila igre so, da kazalec vseh igralcev stoji na 0 na začetku vsakega vrtljaja. In igralec se lahko vrti le v smeri negativnih števil. Kako boste zmagali v tej igri?
Dobra strategija za vsakokratno zmago v tej igri bi bila vrtenje kolesa s takšno močjo, da se kolo zavrti do -256 in se nato v enem zamahu obrne na 256. To je mogoče, ker 256 pride takoj za -256 na kolesu. Temu pravimo aritmetični pretok. In aritmetični preliv je ravno obratno od tega.
Primer kode iz resničnega sveta:
An podtok ali preliv se zgodi, ko aritmetična operacija doseže svoj minimum ali 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;
}
O _amount
parameter funkcije umika je celo število brez predznaka. Vrednost preslikave bilanc (ki je kot slovar v pythonu ali par ključ-vrednost v C++ ali Javi) je prav tako celo število brez predznaka.
mapping(address => uint256) public balances
Zahtevana izjava preveri, ali so stanja msg.sender
je pozitiven ali ne. Toda ta izjava bo vedno resnična, tudi če je znesek večji od bilanc msg.sender
. To je zato, ker oba balances
in _amount
spremenljivke so tipa nepredznačeno celo število in njihov aritmetični rezultat (po spodnjem toku) bo prav tako nepredznačeno celo število!
In kot se morda spomnite, je celo število brez predznaka vedno pozitivno. To pomeni, da lahko napadalec iz pametne pogodbe dvigne neomejeno količino etra! Najdete lahko podroben primer in implementacijsko kodo za to ranljivost tukaj.
Druga ključna stvar, ki jo je treba upoštevati, je, da je aritmetična operacija med recimo dvema celima številoma brez predznaka prav tako celo število brez predznaka. Lahko je nevarno, če se to pri pametnih pogodbah spregleda, saj lahko povzroči neželene kršitve varnosti!
function votes(uint postId, uint upvote, uint downvotes) { if (upvote - downvote < 0) { deletePost(postId) }
}
Kot ste morda opazili v zgornjem primeru, je stavek if precej nesmiseln kot upvote - downvote
bo vedno pozitivno. In objava bo izbrisana, tudi če downvotes
je večja kakor upvotes
. Da bi se izognili takšnim napadom, je priporočljivo, da uporabite različico prevajalnika Solidity, večjo od 0.8.0.
Učinek:
Kovanec imenovan PoWH kovanec je bila predstavljena leta 2017. Čeprav je šlo za igro Ponzi, so vanjo vdrli zaradi napake pri aritmetičnem prelivanju, ki je takrat povzročila izgubo približno 866 ETH ali 950,000 $. O tem si lahko podrobno preberete tukaj.
Morati prebrati: Lekcije iz napada na Tinyman, največji DEX na Algorandu
Napad zavrnitve storitve
Scenarij iz resničnega sveta:
Predstavljajte si, da ste na Bitcoin Tech University. Vse se zdi v redu, le da je skupna jedilna miza za vse. In na žalost je malo ljudi iz drugega razreda, ki vedno uspejo zasesti jedilno mizo pred vsemi iz vašega razreda.
V praktičnem scenariju onemogočajo bistvene storitve vsem, kar povzroči izgubo dragocenega časa. Temu pravimo 'napad zavrnitve storitve'.
Primer kode iz resničnega sveta:
V igri imenovani Kralj etra, vsak lahko postane kralj. Toda pravilo, da postaneš kralj, je, da mora oseba položiti več etra kot trenutni kralj. To lahko storite tako, da pokličete claimThrone()
funkcija pogodbe King of Ether, v kateri oseba pošlje ether neposredno prejšnjemu kralju in postane novi kralj.
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; }
Kot ste morda uganili, je ta koda ranljiva za napad DoS, toda kako? Za to boste morali razumeti, da obstajata dve vrsti naslovov v Ethereumu – prvi je naslov naslov zunanjega lastniški račun ali preprosto naslov denarnice, drugi pa je naslov pogodbe. Zdaj je mogoče eter poslati s katere koli od teh vrst naslovov.
Če je ta eter poslan s pogodbenega naslova, bo pogodba postala kralj. Toda predpostavimo, da ta nova pogodba nima fallback()
funkcija, ki je potrebna, če želi pogodba sprejeti ether. Potem, če pride nova oseba in poskuša poklicati claimThrone()
funkcija, bo vedno odpovedala!
Upoštevajte, da se to deloma zgodi tudi zato, ker claimThrone()
funkcija izrecno preveri, ali je bil prenos etra uspešen ali ne v drugem zahtevanem stavku. Najdete lahko celotno kodo in nanjo izvedete DoS napad tukaj.
Možno je tudi, da je koda ranljiva za napad DoS, če ima koda zanko čez niz velikih velikosti. To se zgodi, ker meja plina se lahko v takih primerih preseže. Lahko preberete o tem tukaj.
Učinek:
Igra, imenovana vladni, ki je bila očitno Ponzijeva shema, se je zataknilo pri 1100 ether, ker je bila za obdelavo izplačila potrebna velika količina plina.
Negotova naključnost
Scenarij iz resničnega sveta:
Nekoč je bil človek po imenu Hesky, ki ga je vedno spremljala njegova opica Pesky. Hesky je izvajal loterijske igre in dobro zaslužil. Nekega dne je Alice opazila Heskyja, kako pozorno strmi v svojo opico Pesky. Potem ga je videla, kako nekaj piše na kos papirja, in to zaprla v kuverto. Ker je bila radovedna, se je odločila nadalje raziskati.
Kasneje tistega večera je Alice videla, da je zmagovalec loterije odločen z javnim odpiranjem zapečatene ovojnice. Ko ga je opazovala nekaj dni, je Alice ugotovila, da je Hesky odločil zmagovalno loterijsko številko tako, da je pogledal Peskyjeve kretnje (na primer, če se je opica popraskala po glavi, je Hesky zapisal 10)! Zdaj je Alice imela formulo za zmago na vsaki loteriji in morala je le kupiti srečko s pravo številko!
Hesky je domneval, da njegovega "naključnega" načina odločanja o zmagovalcu loterije ni mogoče nikoli ugotoviti, vendar se je res motil.
Primer kode iz resničnega sveta:
V tem primeru se naključno število ustvari na podlagi zgoščene vrednosti kombinacije številke bloka in njegovega časovnega žiga bloka. ta zgoščena vrednost je nato dodeljena spremenljivki odgovora. Vsakdo, ki ugane to (na videz) naključno številko, prejme nagrado z 1 Etherjem. Mislite, da je tega nemogoče vdreti?
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"); } }
Ne! Napadalec lahko še vedno ugane to naključno število tako, da preprosto kopira in prilepi kodo, da ustvari vrednost, dodeljeno spremenljivki odgovora, in posreduje isto spremenljivko odgovora guess()
funkcija!
guessTheRandomNumber.guess(answer);
Najdete lahko celotno kodo tukaj. Da bi se izognili temu napadu, je priporočljivo uporabiti preverljivo naključno funkcijo, kot je Chainlink VRF.
Učinek:
Približno 400 ETH je bilo izgubljenih zaradi napada na Loterija Smart Billions pogodba. Presenetljivo je, da je bila celo sama pogodbena loterija Ponzijeva shema (ojoj!).
Manipulacija s časom
Scenarij iz resničnega sveta:
Satoshi rad jedo piškote. Obožuje vse vrste piškotov, ki jih pripravlja njegova mama. Toda njegova mama je zelo stroga in meni, da preveč piškotkov ni dobro zanj. Zato njegova mama postavi pravilo, da bo piškote dobil šele ob 8. uri.
Isti dan ob 7 Satoshi steče k mami in zahteva piškotke. Njegova mati vpraša: "Koliko je ura?"
"Ura je 8'!" – odgovori.
"V redu. Potem pa vzemi piškote iz moje omare.”
In tako je Satoshi lahko uspešno manipuliral s časom za 15 minut, da je lahko dobil svoje piškote! Kakšen piškotkov lačen fant!
Primer kode iz resničnega sveta:
Časovni žig bloka je mogoče spreminjati s približno 15 sekund s strani rudarja. Na ta način lahko rudar nastavi ugoden časovni žig in vključi svojo transakcijo v isti blok, ki ga rudari. Funkcija play()
pripada pogodbi o igri, imenovani G-Dot.
function play() public { require(now > 1640392200 && neverPlayed == true); neverPlayed = false; msg.sender.transfer(1500 ether);
}
Ta pogodba nagrajuje 1500 ether igralca, ki prvi kliče funkcijo igranja. Toda kot lahko vidite, je funkcijo predvajanja mogoče poklicati le, če je zdaj ali block.timestamp transakcije, ki vsebuje klic play()
funkcijo, je večja od epoha čas 1640392200.
Rudar lahko zlahka manipulira s tem časovnim žigom in vključi svojo transakcijo klica play()
deluje v istem bloku tako, da je sam prvi igralec. Na ta način je zagotovljeno, da bo rudar zmagal!
Učinek:
Block.timestamp je bil uporabljen za ustvarjanje naključnih števil v Vladni in je bil tako ranljiv za napade s časovno manipulacijo.
Obrnite se na QuillAudits
QuillAudits je varna platforma za revizije pametnih pogodb, ki jo je zasnoval QuillHash
Tehnologije.
Je revizijska platforma, ki natančno analizira in preverja pametne pogodbe, da preveri varnostne ranljivosti z učinkovitim ročnim pregledom z orodji za statično in dinamično analizo, analizatorji plinov in simulatorji. Poleg tega revizijski proces vključuje tudi obsežno testiranje enot in strukturno analizo.
Izvajamo revizije pametnih pogodb in teste prodora, da bi našli potencial
varnostne ranljivosti, ki bi lahko škodovale celovitosti platforme.
Če potrebujete kakršno koli pomoč pri reviziji pametnih pogodb, se obrnite na naše strokovnjake tukaj!
Če želite biti na tekočem z našim delom, se pridružite naši skupnosti: -
Twitter | LinkedIn | Facebook | Telegram
Pošta Priročnik za revizijo pametnih pogodb za začetnike: 1. del pojavil prvi na Blog Quillhash.
Vir: https://blog.quillhash.com/2022/01/19/beginners-guide-to-smart-contract-auditing-part-1/
- "
- &
- 000
- 2016
- 7
- O meni
- Račun
- Naslov
- vsi
- že
- Čeprav
- Analiza
- Revizija
- avtonomno
- Začetek
- BEST
- Bitcoin
- blockchain
- Bug
- nakup
- klic
- primeri
- Pregledi
- klasična
- Koda
- Coin
- kombinacija
- Skupno
- skupnost
- Vsebuje
- Naročilo
- pogodbe
- piškotki
- bi
- Ustvarjanje
- kripto
- Trenutna
- DAO
- dan
- Decentralizirano
- Denial of Service
- Podatki
- Dex
- navzdol
- enostavno
- jesti
- ETH
- Eter
- ethereum
- ethereum blockchain
- Ethereum Classic
- Primer
- Izkoristite
- konec
- prva
- brezplačno
- funkcija
- igra
- Games
- GAS
- ustvarjajo
- GitHub
- dogaja
- dobro
- vodi
- kramp
- žaga
- hash
- Glava
- tukaj
- Kako
- HTTPS
- razišče
- IT
- Java
- pridružite
- skoči
- King
- jezik
- velika
- vrstica
- Long
- si
- loterija
- moški
- milijonov
- Mati
- številke
- Organizacija
- Papir
- Vzorec
- Plačajte
- ljudje
- kos
- platforma
- Predvajaj
- predvajalnik
- ponzi
- Ponzijeva shema
- moč
- Postopek
- Programerji
- Programiranje
- javnega
- nazaj
- pregleda
- Nagrade
- pravila
- Satoshi
- varnost
- nastavite
- pametna
- pametna pogodba
- Pametne pogodbe
- So
- trdnost
- Nekaj
- Spin
- po delih
- začel
- Izjava
- Strategija
- uspešno
- Uspešno
- tech
- testi
- skozi
- čas
- orodja
- transakcija
- nebančni
- univerza
- posodobitve
- vrednost
- Ranljivosti
- ranljivost
- Ranljivi
- denarnica
- Kaj
- Kolo
- WHO
- zmago
- delo
- pisanje