Tervetuloa älykkään sopimusten auditoinnin aloittelijoille! Yksi parhaista tavoista päästä alkuun älykkäiden sopimusten auditoinnissa on hypätä mukaan ja tarkastella muutamia yleisiä älykkäiden sopimusten haavoittuvuuksia.
Olisi hyödyllistä, jos sinulla on jo perustiedot Ethereumin Solidity-ohjelmointikielestä. Tarkastellaan joitain Noob solidity -ohjelmoijien kirjoittamia koodeja.
Re-Entrance Attack
Tosimaailman skenaario:
Kuvittele, että sinulla on 50 suklaata. Sinulla on tuhma pikkusisko, jonka olet sallinut ottaa sinulta vain 2 suklaata kerrallaan. Et myöskään halua antaa hänelle enempää kuin 10 suklaata päivässä, koska pelkäät, että hän saa hampaiden reikiintymisen. Tämän varmistamiseksi lasket joka ilta kuinka monta suklaata on jäljellä. Luuletko tämän toimivan? Vai joutuisitko pikkusiskosi hakkerointiin?
Valitettavasti se ei onnistu! Siskosi tajuaa, että et tiedä kuinka monta suklaata sinulla on ennen iltaa. Joten heti seuraavana päivänä pikkusiskosi vierailee luonasi 6 kertaa ennen iltaa ja ottaa joka kerta 2 suklaata! Tätä kutsumme paluuhyökkäykseksi.
Täällä päivität illalla saamiesi suklaamäärien sen sijaan, että päivität määrää joka kerta, kun siskosi ottaa sinulta 2 suklaata. Näin tapahtuu myös älykkäiden sopimusten kanssa. Älykäs sopimus olettaa tietyn tasapainon, kun taas hyökkääjä on itse asiassa kiireinen nostamalla jonkin verran kryptoa sopimuksesta useita kertoja.
Esimerkki tosimaailman koodista:
Tämä koodi kuuluu älykkääseen sopimukseen nimeltä pankittomien mahdollisuuksia avata. Kuka tahansa voi nostaa eetterin Unbanked-sopimuksesta niin kauan kuin viestin lähettäjän (eli soittajan) saldot ovat withdraw
funktio ) on suurempi tai yhtä suuri kuin nostettava summa.
function withdraw(uint _amount) { require(balances[msg.sender] >= _amount); msg.sender.call.value(_amount)(); balances[msg.sender] -= _amount;
}
Huomaa, että on olemassa kutsuavainsana, jota käytetään lähettämään tarvittava määrä eetteriä msg.sender
. Hyökkääjä voi hyödyntää tätä luomalla Thief-nimisen sopimuksen, jossa hän kutsuu poistotoimintoa kohdassa a fallback()
toiminto. A fallback()
Solidity-toiminto on erityinen toiminto, joka suoritetaan, kun eetteri lähetetään älysopimukseen.
Tämä tarkoittaa, että hyökkääjä pystyy kutsua rekursiivisesti peruutusfunktiota. Näin ollen ennen älykkään sopimuksen päivityksiä saldot msg.sender
viimeisellä koodirivillä hyökkääjä on jo poistanut eetterin useita kertoja. Tämä voidaan välttää, jos saldot päivitetään ennen kutsuavainsanan käyttöä, jolloin seuraa a tarkastukset-vaikutukset-vuorovaikutukset kuvio.
Vaikutus:
- ensimmäinen Reentrancy Attack tapahtui vuonna 2016 DAO:ssa (Decentralized Autonomous Organisation), joka johti noin 50 miljoonan dollarin hakkerointiin. Kääntääkseen tämän hakkeroinnin Ethereum-yhteisö jakoi Ethereumin lohkoketjun, josta syntyivät ETC (Ethereum Classic) ja ETH (Ethereum).
Aritmeettinen ylivuoto ja alivuoto
Tosimaailman skenaario:
Pelataan ajatusleikkiä. Se koostuu Spin-the-pyörästä, ja voittaja ratkeaa suurimman määrän perusteella, jonka hän pystyy pyörittämään pyörää. Pyörä on merkitty kauttaaltaan 256 - -256.
Pelin säännöt ovat, että kaikkien pelaajien osoitin lepää 0:ssa jokaisen pyöräytyksen alussa. Ja pelaaja saa pyöriä vain negatiivisten numeroiden suuntaan. Kuinka voitat tämän pelin?
Hyvä strategia voittaa tämä peli joka kerta olisi pyörittää pyörää sellaisella voimalla, että pyörä pyörii -256:een ja sitten kääntyy 256:een kerralla. Tämä on mahdollista, koska 256 tulee heti -256:n jälkeen ratissa. Tätä kutsumme aritmeettiseksi alivuotoksi. Ja aritmeettinen ylivuoto on juuri päinvastoin.
Esimerkki tosimaailman koodista:
An ali- tai ylivuoto tapahtuu, kun aritmeettinen operaatio saavuttaa minimi- tai maksiminsa.
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
poistofunktion parametri on etumerkitön kokonaisluku. Saldokartoituksen arvo (joka on kuin sanakirja pythonissa tai avainarvo-pari C++:ssa tai Javassa) on myös etumerkitön kokonaisluku.
mapping(address => uint256) public balances
Vaadittavalla lausunnolla tarkistetaan, onko saldot msg.sender
onko positiivinen vai ei. Mutta tämä väite on aina totta, vaikka summa olisi suurempi kuin saldot msg.sender
. Tämä johtuu siitä, että molemmat balances
ja _amount
muuttujat ovat tyyppiä etumerkitön kokonaisluku ja niiden aritmeettinen tulos (alivuodon jälkeen) on myös etumerkitön kokonaisluku!
Ja kuten muistat, etumerkitön kokonaisluku on aina positiivinen. Tämä tarkoittaa, että hyökkääjä voi nostaa rajattoman määrän eetteriä älysopimuksesta! Löydät yksityiskohtaisen esimerkin ja toteutuskoodin tälle haavoittuvuudelle tätä.
Toinen tärkeä huomioitava asia tässä on, että aritmeettinen operaatio esimerkiksi kahden etumerkittömän kokonaisluvun välillä on myös etumerkitön kokonaisluku. Se voi olla vaarallista, jos tämä jätetään huomiotta älykkäissä sopimuksissa, koska se voi johtaa ei-toivottuihin tietoturvaloukkauksiin!
function votes(uint postId, uint upvote, uint downvotes) { if (upvote - downvote < 0) { deletePost(postId) }
}
Kuten olet ehkä huomannut yllä olevassa esimerkissä, if-lause on melko turha upvote - downvote
tulee aina olemaan positiivista. Ja viesti poistetaan vaikka downvotes
on suurempi kuin upvotes
. Tällaisten hyökkäysten välttämiseksi on suositeltavaa käyttää Solidity-kääntäjäversiota, joka on suurempi kuin 0.8.0.
Vaikutus:
Kolikko nimeltä PoWH kolikko lanseerattiin vuonna 2017. Vaikka se oli Ponzi-peli, se itse hakkeroitiin aritmeettisen ylivuotovirheen vuoksi, joka johti noin 866 ETH:n eli 950,000 XNUMX dollarin tappioon tuolloin. Voit lukea tästä yksityiskohtaisesti tätä.
Täytyy lukea: Oppitunnit hyökkäyksestä Tinymania vastaan, Algorandin suurin DEX
Palvelunestohyökkäys
Tosimaailman skenaario:
Kuvittele, että olet Bitcoin Tech Universityssä. Kaikki näyttää hyvältä paitsi että kaikille on yhteinen ruokapöytä. Ja valitettavasti toiselta luokalta on vain vähän ihmisiä, jotka onnistuvat aina istumaan ruokapöytään ennen kuin kukaan omasta luokastasi.
Käytännössä he kieltävät olennaisen palvelun kaikilta, mikä johtaa arvokkaan ajan hukkaan. Tätä kutsumme "palvelunestohyökkäykseksi".
Esimerkki tosimaailman koodista:
Pelissä nimeltä Eetterin kuningas, kuka tahansa voi tulla kuninkaaksi. Mutta kuninkaaksi tulemisen sääntö on, että henkilön tulee tallettaa enemmän eetteriä kuin nykyinen kuningas. Tämän voi tehdä soittamalla claimThrone()
King of Ether -sopimuksen tehtävä, jossa henkilö lähettää eetterin suoraan edelliselle kuninkaalle ja hänestä tulee uusi 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; }
Kuten saatat arvata, tämä koodi on alttiina DoS-hyökkäykselle, mutta miten? Tätä varten sinun on ymmärrettävä, että Ethereumissa on kahdenlaisia osoitteita - ensimmäinen on ulkoisen osoitteen omistama tili tai yksinkertaisesti lompakon osoite, ja toinen on sopimuksen osoite. Nyt eetteri voidaan lähettää kummasta tahansa näistä osoitetyypeistä.
Jos tämä eetteri lähetetään sopimusosoitteen kautta, sopimuksesta tulee kuningas. Mutta oletetaan, että tässä uudessa sopimuksessa ei ole a fallback()
toiminto, joka on välttämätön, jos sopimus haluaa hyväksyä eetterin. Sitten jos uusi henkilö tulee paikalle ja yrittää soittaa claimThrone()
toiminto, se epäonnistuu aina!
Huomaa, että tämä tapahtuu myös osittain siksi claimThrone()
toiminto tarkastaa nimenomaisesti, onnistuiko eetterin siirto toisessa vaaditussa käskyssä. Löydät täydellisen koodin ja voit tehdä DoS-hyökkäyksen sitä vastaan tätä.
On myös mahdollista, että koodi on alttiina DoS-hyökkäykselle, jos koodissa on silmukka suurikokoisen joukon yli. Tämä tapahtuu, koska kaasun raja voidaan tällaisissa tapauksissa ylittää. Voit lukea siitä tätä.
Vaikutus:
Peli nimeltään GovernMental, joka oli ilmeisesti Ponzi-suunnitelma, juuttui 1100 eetteriin, koska maksun käsittelyyn tarvittiin suuri määrä kaasua.
Epävarma satunnaisuus
Tosimaailman skenaario:
Olipa kerran mies nimeltä Hesky, jonka mukana oli aina apinansa Pesky. Hesky johti arpajaisia ja teki hyviä voittoja. Eräänä päivänä Alice huomasi Heskyn tuijottavan kiihkeästi apinaansa Peskyä. Sitten hän näki hänen kirjoittavan jotain paperille ja sulki sen kirjekuoreen. Uteliaana hän päätti tutkia asiaa tarkemmin.
Myöhemmin samana iltana Alice näki, että lottovoittaja päätettiin avaamalla julkisesti suljettu kirjekuori. Katsottuaan häntä muutaman päivän ajan Alice tajusi, että Hesky päätti lottovoiton katsomalla Peskyn eleitä (esimerkiksi jos apina raapi hänen päätään, Hesky kirjoitti muistiin 10)! Nyt Alicella oli kaava voittaa jokainen lotto ja täytyi vain ostaa lottokuponki oikealla numerolla!
Hesky oli olettanut, että hänen "satunnaista" tapaansa päättää lottovoittaja ei voida koskaan selvittää, mutta hän oli todellakin väärässä.
Esimerkki tosimaailman koodista:
Tässä esimerkissä satunnaisluku generoidaan lohkon numeron ja sen lohkon aikaleiman yhdistelmän hajautusarvon perusteella. tämä hash määritetään sitten vastausmuuttujalle. Nyt jokainen, joka arvaa tämän (näennäisen) satunnaisen luvun, palkitaan 1 eetterillä. Onko tämä mielestäsi hakkeroimaton?
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! Hyökkääjä voi silti arvata tämän satunnaisluvun yksinkertaisesti kopioimalla liittämällä koodin vastausmuuttujalle määritetyn arvon luomiseksi ja välittämällä saman vastausmuuttujan guess()
toiminto!
guessTheRandomNumber.guess(answer);
Löydät täydellisen koodin tätä. Tämän hyökkäyksen välttämiseksi on suositeltavaa käyttää verifioitavaa satunnaisfunktiota, kuten Ketjulinkki VRF.
Vaikutus:
Noin 400 ETH:ta katosi hyökkäyksen seurauksena Smart Billions -lotto sopimus. Yllättäen jopa itse sopimusarpajaiset olivat Ponzi-järjestelmä (auts!).
Ajan manipulointi
Tosimaailman skenaario:
Satoshi tykkää syödä keksejä. Hän rakastaa kaikenlaisia keksejä, joita hänen äitinsä tekee. Mutta hänen äitinsä on erittäin tiukka, ja hänen mielestään liian monien kekseiden syöminen ei ole hänelle hyväksi. Joten hänen äitinsä tekee säännön, että hän saa keksejä vasta klo 8.
Samana päivänä klo 7 Satoshi juoksee äitinsä luo ja pyytää keksejä. Hänen äitinsä kysyy: "Paljonko kello on?"
"Kello on kahdeksan!" – hän vastaa.
"Okei. Ota sitten keksit kaapistani."
Ja näin Satoshi pystyi manipuloimaan aikaa onnistuneesti 15 minuutilla saadakseen keksinsä! Mikä keksinälkäinen jätkä!
Esimerkki tosimaailman koodista:
Lohkon aikaleimaa voidaan käsitellä noin 15 sekuntia kaivosmiehen toimesta. Tällä tavalla kaivosmies voi asettaa edullisen aikaleiman ja sisällyttää tapahtumansa samaan louhimaansa lohkoon. Toiminto play()
kuuluu pelisopimukseen nimeltä G-Dot.
function play() public { require(now > 1640392200 && neverPlayed == true); neverPlayed = false; msg.sender.transfer(1500 ether);
}
Tämä sopimus palkitsee 1500 eetteriä pelaajalle, joka soittaa ensimmäisenä pelitoiminnon. Mutta kuten näet, toistotoimintoa voidaan kutsua vain, jos tapahtuman nyt tai block.timestamp, joka sisältää kutsun play()
toiminto, on suurempi kuin aikakauden aika 1640392200.
Kaivostyöntekijä voi helposti muokata tätä aikaleimaa ja sisällyttää siihen puhelutapahtumansa play()
toimii samassa lohkossa siten, että hän itse on ensimmäinen pelaaja. Tällä tavalla on taattu, että kaivosmies voittaa pelin!
Vaikutus:
Block.timestamp-funktiota käytettiin satunnaislukujen luomiseen Valtiolliset ja oli siten alttiina ajan manipulointihyökkäyksiä vastaan.
Ota yhteyttä QuillAuditsiin
QuillAudits on turvallinen älykkäiden sopimusten auditointialusta, jonka on suunnitellut QuillHash
Teknologiat.
Se on auditointialusta, joka analysoi ja varmentaa tarkasti älykkäitä sopimuksia ja tarkistaa tietoturva-aukkoja tehokkaan manuaalisen tarkistuksen avulla staattisten ja dynaamisten analyysityökalujen, kaasuanalysaattoreiden ja simulaattoreiden avulla. Lisäksi auditointiprosessiin kuuluu myös laaja yksikkötestaus sekä rakenneanalyysi.
Teemme sekä älykkäitä sopimusauditointeja että penetraatiotestejä löytääksemme potentiaalia
tietoturva-aukkoja, jotka voivat vahingoittaa alustan eheyttä.
Jos tarvitset apua älykkäiden sopimusten auditoinnissa, ota rohkeasti yhteyttä asiantuntijoihimme täällä!
Liity yhteisöömme pysyäksesi ajan tasalla työstämme: -
Twitter | LinkedIn | Facebook | Telegram
Viesti Aloittelijan opas älykkääseen sopimusten auditointiin: Osa 1 ilmestyi ensin Quillhash-blogi.
Lähde: https://blog.quillhash.com/2022/01/19/beginners-guide-to-smart-contract-auditing-part-1/
- "
- &
- 000
- 2016
- 7
- Meistä
- Tili
- osoite
- Kaikki
- jo
- Vaikka
- analyysi
- tilintarkastus
- autonominen
- Alku
- PARAS
- Bitcoin
- blockchain
- Vika
- Ostetaan
- soittaa
- tapauksissa
- Tarkastukset
- klassinen
- koodi
- Kolikko
- yhdistelmä
- Yhteinen
- yhteisö
- sisältää
- sopimus
- sopimukset
- keksit
- voisi
- Luominen
- Crypto
- Nykyinen
- DAO
- päivä
- hajautettu
- Palvelunesto
- yksityiskohta
- Dex
- alas
- helposti
- syödä
- ETH
- Eetteri
- ethereum
- Ethereum blockchain
- Ethereum Classic
- esimerkki
- Käyttää hyväkseen
- loppu
- Etunimi
- Ilmainen
- toiminto
- peli
- Games
- GAS
- tuottaa
- GitHub
- menee
- hyvä
- ohjaavat
- hakata
- hakata
- hasis
- pää
- tätä
- Miten
- HTTPS
- tutkia
- IT
- Jaava
- yhdistää
- hypätä
- kuningas
- Kieli
- suuri
- linja
- Pitkät
- näköinen
- arpajaiset
- mies
- miljoona
- äiti
- numerot
- organisaatio
- Paperi
- Kuvio
- Maksaa
- Ihmiset
- kappale
- foorumi
- Pelaa
- soitin
- Ponzi
- Ponzi-huijaus
- teho
- prosessi
- Ohjelmoijat
- Ohjelmointi
- julkinen
- käänteinen
- arviot
- Palkkiot
- säännöt
- Satoshi
- turvallisuus
- setti
- fiksu
- älykäs sopimus
- Smart-sopimukset
- So
- kiinteys
- jotain
- Kierre
- jakaa
- alkoi
- Lausunto
- Strategia
- onnistunut
- Onnistuneesti
- teknologia
- testit
- Kautta
- aika
- työkalut
- kauppa
- pankittomien mahdollisuuksia avata
- yliopisto
- Päivitykset
- arvo
- haavoittuvuuksia
- alttius
- Haavoittuva
- Lompakko
- Mitä
- Pyörä
- KUKA
- voittaa
- Referenssit
- kirjoittaminen