Üdvözöljük az intelligens szerződés-auditálás kezdőknek szóló útmutatójában! Az intelligens szerződés-auditálás megkezdésének egyik legjobb módja, ha belevágunk, és megnézzük az intelligens szerződések néhány gyakori sérülékenységét.
Hasznos lenne, ha már ismeri az Ethereum Solidity programozási nyelvét. Ahogy megnézzük a Noob solidity programozói által írt néhány kódot.
Újbóli belépési támadás
Valós forgatókönyv:
Képzeld el, hogy van 50 csokoládé. Van egy szemtelen kishúgod, akinek megengedted, hogy egyszerre csak 2 csokit vegyen el tőled. Ezenkívül ne akarjon 10 csokinál többet adni neki egy nap alatt, mert attól tart, hogy fogszuvasodást szenved. Ennek érdekében minden este megszámolja, hány csokoládé maradt nálatok. Szerinted ez működne? Vagy feltörne a húgodtól?
Sajnos nem fog menni! A húgod kitalálja, hogy estig nem tudod, hány csoki van nálad. Így már másnap este előtt hatszor meglátogat a húgod, és minden alkalommal vesz 6 csokit! Ezt nevezzük visszatérési támadásnak.
Itt frissíted az esti csokoládék számát, ahelyett, hogy minden alkalommal frissítenéd a számot, amikor a nővéred 2 csokoládét vesz el tőled. Ez történik az intelligens szerződésekkel is. Az intelligens szerződés bizonyos egyensúlyt feltételez, miközben a támadó ténylegesen azzal van elfoglalva, hogy többször is kivonjon bizonyos mennyiségű kriptot a szerződésből.
Példa valós kódra:
Ez a kód egy intelligens szerződéshez tartozik unbanked. Bárki visszavonhatja az étert a bank nélküli szerződéstől, amíg az üzenetküldő (azaz a hívó fél) egyenlege megvan. withdraw
függvény ) nagyobb vagy egyenlő, mint a felvenni kért összeg.
function withdraw(uint _amount) { require(balances[msg.sender] >= _amount); msg.sender.call.value(_amount)(); balances[msg.sender] -= _amount;
}
Figyelje meg, hogy van egy hívási kulcsszó, amely a szükséges mennyiségű étert elküldi a msg.sender
. A támadó ezt kihasználhatja egy Thief nevű szerződés létrehozásával, amelyben meghívja a visszavonási függvényt a fallback()
funkció. A fallback()
A Solidity funkció egy speciális funkció, amely akkor kerül végrehajtásra, amikor étert küldenek az intelligens szerződéshez.
Ez azt jelenti, hogy a támadó képes rekurzívan hívja meg a visszavonás függvényt. Így az intelligens szerződés frissítése előtt az egyenlegek msg.sender
az utolsó kódsorban a támadó már többször visszavonta az etert. Ez elkerülhető, ha a hívás kulcsszó használata előtt frissítik az egyenlegeket, így követve a ellenőrzések-hatások-kölcsönhatások mintát.
Hatás:
A az első Reentrancy Attack 2016-ban történt egy DAO-n (Decentralized Autonomous Organization), ami körülbelül 50 millió dolláros feltörést eredményezett. Ennek a feltörésnek a visszafordításához az Ethereum közösség felosztotta az Ethereum blokkláncot, ami az ETC (Ethereum Classic) és az ETH (Ethereum) létrejöttét eredményezte.
Aritmetikai túlcsordulás és alulcsordulás
Valós forgatókönyv:
Játsszunk egy gondolatjátékot. Ez egy Spin-the kerékből áll, és a győztes az alapján dől el, hogy mennyit tud a kerék megpörgetése során elérni. A kerék 256-tól -256-ig van jelölve.
A játék szabályai szerint az összes játékos mutatója a 0-n áll minden pörgetés elején. A játékos pedig csak a negatív számok irányába pöröghet. Hogyan fogod megnyerni ezt a játékot?
Egy jó stratégia a játék megnyeréséhez az lenne, ha olyan erővel forgatnád a kereket, hogy a kerék -256-ig forogjon, majd egy mozdulattal 256-ra forduljon. Ez azért lehetséges, mert a 256 csak a -256 után jön a keréken. Ezt nevezzük aritmetikai alulcsordulásnak. Az aritmetikai túlcsordulás pedig ennek éppen az ellenkezője.
Példa valós kódra:
An alul- vagy túlcsordulás akkor történik, amikor egy aritmetikai művelet eléri a minimumát vagy maximumát.
function withdraw(uint _amount) public { require(balances[msg.sender] - _amount > 0); address payable to = payable(msg.sender); to.transfer(_amount); balances[msg.sender] -= _amount;
}
A _amount
A visszavonási függvény paramétere egy előjel nélküli egész szám. Az egyenlegleképezés értéke (ami olyan, mint egy szótár pythonban vagy kulcs-érték pár C++-ban vagy Java nyelven) szintén előjel nélküli egész szám.
mapping(address => uint256) public balances
A szükséges kimutatás ellenőrzi, hogy az egyenlegek a msg.sender
pozitív vagy sem. De ez az állítás mindig igaz, még akkor is, ha az összeg nagyobb, mint az egyenlege msg.sender
. Ez azért van így, mert mind a balances
és a _amount
a változók előjel nélküli egész típusúak, és számtani eredménye (alulcsordulás után) is előjel nélküli egész szám lesz!
És mint emlékszik rá, az előjel nélküli egész szám mindig pozitív. Ez azt jelenti, hogy a támadó korlátlan mennyiségű Ethert vonhat ki az intelligens szerződésből! Részletes példát és megvalósítási kódot talál erre a biztonsági résre itt.
Egy másik fontos dolog, amit itt meg kell jegyezni, hogy mondjuk két előjel nélküli egész szám közötti aritmetikai művelet is előjel nélküli egész. Veszélyes lehet, ha ezt figyelmen kívül hagyják az okosszerződésekben, mert nem kívánt biztonsági résekhez vezethet!
function votes(uint postId, uint upvote, uint downvotes) { if (upvote - downvote < 0) { deletePost(postId) }
}
Amint azt a fenti példában észrevehette, az if utasítás teljesen értelmetlen, mint upvote - downvote
mindig pozitív lesz. És a bejegyzés akkor is törlődik downvotes
nagyobb, mint upvotes
. Az ilyen támadások elkerülése érdekében ajánlatos a Solidity fordítóprogramnál nagyobb verzióját használni 0.8.0.
Hatás:
Az úgynevezett érme PoWH érme 2017-ben indult. Noha ez egy Ponzi játék volt, magát egy aritmetikai túlcsordulási hiba miatt feltörték, ami akkoriban körülbelül 866 ETH-t vagy 950,000 XNUMX dollárt veszített. Erről részletesen olvashat itt.
Muszáj elolvasni: A Tinyman elleni támadás tanulságai, az Algorand legnagyobb DEX-je
Szolgáltatás megtagadása támadás
Valós forgatókönyv:
Képzeld el, hogy egy Bitcoin Tech Egyetemen vagy. Úgy tűnik, minden rendben van, kivéve, hogy mindenki számára van közös étkezőasztal. És sajnos egy másik osztályból kevesen vannak, akik mindig előbb ülnek le az étkezőasztalhoz, mint bárki az osztályodból.
A gyakorlati forgatókönyv szerint mindenkitől megtagadják az alapvető szolgáltatást, ami értékes időveszteséggel jár. Ezt hívjuk „szolgáltatásmegtagadási támadásnak”.
Példa valós kódra:
nevű játékban Ether királya, bárkiből király lehet. De a királlyá válás szabálya az, hogy egy személynek több étert kell elhelyeznie, mint a jelenlegi király. Ezt úgy lehet megtenni, hogy hívja a claimThrone()
Az éter királya szerződés funkciója, amelyben a személy közvetlenül az előző királynak küld étert, és ő lesz az új király.
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; }
Ahogy azt sejteni lehetett, ez a kód sebezhető a DoS Attack ellen, de hogyan? Ehhez meg kell értenie, hogy az Ethereumban kétféle cím létezik – az első a egy külső címet tulajdonában lévő fiók vagy egyszerűen egy pénztárca címe, a második pedig a szerződés címe. Most az étert el lehet küldeni ezen címtípusok bármelyikéről.
Ha ezt az étert a szerződéses cím küldi, akkor a szerződés lesz a király. De tegyük fel, hogy ez az új szerződés nem rendelkezik a fallback()
funkció, amely akkor szükséges, ha a szerződés étert akar fogadni. Aztán ha jön egy új személy és megpróbálja felhívni a claimThrone()
funkció, mindig kudarcot vallanak!
Figyeljük meg, hogy ez részben azért is történik, mert a claimThrone()
A függvény a második kötelező utasításban kifejezetten ellenőrzi, hogy az éter átvitele sikeres volt-e vagy sem. Megtalálhatja a teljes kódot, és DoS támadást hajthat végre rajta itt.
Az is előfordulhat, hogy egy kód sebezhető a DoS támadásokkal szemben, ha a kódban nagy méretű hurok található. Ez azért történik, mert a gáz-határérték ilyen esetekben túl lehet lépni. Olvashatsz róla itt.
Hatás:
Az úgynevezett játék Kormányzati, ami látszólag Ponzi-séma volt, elakadt az 1100 éterrel, mert nagy mennyiségű gázra volt szükség a kifizetés feldolgozásához.
Bizonytalan véletlenszerűség
Valós forgatókönyv:
Volt egyszer egy Hesky nevű ember, akit mindig a majmája, Pesky kísért. Hesky lottójátékokat bonyolított le, és jó nyereségre tett szert. Egy nap Alice észrevette, hogy Hesky figyelmesen bámulja a majmát, Peskyt. Aztán látta, hogy ír valamit egy papírra, és egy borítékba zárta. Kíváncsian úgy döntött, hogy tovább vizsgálja.
Később aznap este Alice látta, hogy a lottó nyertesét a lezárt boríték nyilvános felnyitásával döntötték el. Néhány napos figyelése után Alice rájött, hogy a Hesky a nyerő lottószámot Pesky mozdulataira nézve döntötte el (például ha a majom vakarta a fejét, Hesky 10-et írt le)! Most Alice-nek megvolt a képlete, amellyel minden lottót megnyerhetett, és csak meg kellett vennie a megfelelő sorszámú lottószelvényt!
Hesky azt feltételezte, hogy a lottó nyertesének „véletlenszerű” döntését soha nem lehet kitalálni, de valóban tévedett.
Példa valós kódra:
Ebben a példában egy véletlen számot generálunk a blokk számának és a blokk időbélyegének kombinációjának hash alapján. ezt a hash-t a rendszer a válaszváltozóhoz rendeli. Most, aki kitalálja ezt a (látszólag) véletlenszerű számot, 1 étert kap. Szerinted ez feltörhetetlen?
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"); } }
Dehogy! A támadó továbbra is kitalálhatja ezt a véletlen számot úgy, hogy egyszerűen bemásolja a kódot a válaszváltozóhoz rendelt érték létrehozásához, és ugyanazt a válaszváltozót továbbítja a guess()
funkció!
guessTheRandomNumber.guess(answer);
A teljes kódot megtalálod itt. Ennek a támadásnak a elkerülése érdekében ajánlott egy Verifiable Random Function, például a Láncszem VRF.
Hatás:
Körülbelül 400 ETH veszett el egy támadás miatt Smart Millions lottó szerződés. Meglepő módon még maga a szerződéses lottó is Ponzi-játék volt (jajj!).
Idő manipuláció
Valós forgatókönyv:
Satoshi szeret sütit enni. Imád mindenféle sütit, amit édesanyja készít. De az édesanyja nagyon szigorú, és úgy érzi, hogy nem tesz jót neki, ha túl sok sütit eszik. Édesanyja tehát olyan szabályt alkot, hogy csak este 8-kor kapja meg a sütit.
Ugyanazon a napon 7:45-kor Satoshi az anyjához fut, és sütit kér. Az anyja megkérdezi: "Hány óra van?"
– 8 óra van! – válaszolja.
"Oké. Akkor vedd ki a sütiket a szekrényemből."
Így Satoshi 15 perccel sikeresen manipulálta az időt, hogy megszerezze a sütijét! Micsoda sütire éhes fickó!
Példa valós kódra:
Egy blokk időbélyegét kb 15 másodperc egy bányász által. Ily módon egy bányász beállíthat egy kedvező időbélyeget, és belefoglalhatja a tranzakcióját ugyanabba a blokkba, amelyet bányásznak. A funkció play()
a G-Dot nevű játékszerződéshez tartozik.
function play() public { require(now > 1640392200 && neverPlayed == true); neverPlayed = false; msg.sender.transfer(1500 ether);
}
Ez a szerződés 1500 étert jutalmaz annak a játékosnak, aki elsőként hívja meg a játék funkciót. De amint láthatja, a lejátszás funkció csak akkor hívható meg, ha a most vagy block.timestamp-je annak a tranzakciónak, amely a play()
függvény, nagyobb, mint a korszak ideje 1640392200.
A bányász könnyen manipulálhatja ezt az időbélyeget, és belefoglalhatja a hívó tranzakcióját play()
funkció ugyanabban a blokkban úgy, hogy ő maga az első játékos. Így garantáltan a bányász nyeri meg a játékot!
Hatás:
A block.timestamp-et véletlen számok generálására használták a Kormányzati és így sebezhető volt az időmanipulációs támadásokkal szemben.
Forduljon a QuillAuditshoz
A QuillAudits egy biztonságos intelligens szerződés-ellenőrzési platform, amelyet az általa tervezett QuillHash
Technologies.
Ez egy auditálási platform, amely szigorúan elemzi és ellenőrzi az intelligens szerződéseket, hogy statikus és dinamikus elemző eszközökkel, gázelemzőkkel és szimulátorokkal hatékony kézi ellenőrzésen keresztül ellenőrizze a biztonsági réseket. Ezen túlmenően, az ellenőrzési folyamat kiterjedt egységtesztet és szerkezeti elemzést is magában foglal.
Intelligens szerződés-auditokat és penetrációs teszteket is végzünk, hogy megtaláljuk a lehetőségeket
biztonsági rések, amelyek sérthetik a platform integritását.
Ha segítségre van szüksége az intelligens szerződések auditálásához, forduljon bizalommal szakértőinkhez itt!
Hogy naprakész legyél munkánkkal, csatlakozz közösségünkhöz: -
Twitter | LinkedIn | Facebook | Telegram
A poszt Útmutató kezdőknek az intelligens szerződések auditálásához: 1. rész jelent meg először Quillhash blog.
Forrás: https://blog.quillhash.com/2022/01/19/beginners-guide-to-smart-contract-auditing-part-1/
- "
- &
- 000
- 2016
- 7
- Rólunk
- Fiók
- cím
- Minden termék
- már
- Bár
- elemzés
- könyvvizsgálat
- autonóm
- Kezdet
- BEST
- Bitcoin
- blockchain
- Bogár
- megvesz
- hívás
- esetek
- Ellenőrzések
- klasszikus
- kód
- Érme
- kombináció
- Közös
- közösség
- tartalmaz
- szerződés
- szerződések
- keksz
- tudott
- létrehozása
- crypto
- Jelenlegi
- DAO
- nap
- decentralizált
- Denial of Service
- részlet
- Dex
- le-
- könnyen
- eszik
- ETH
- Éter
- Ethereum
- Ethereum blokklánc
- Ethereum Classic
- példa
- Exploit
- végén
- vezetéknév
- Ingyenes
- funkció
- játék
- Games
- GAS
- generál
- GitHub
- megy
- jó
- útmutató
- csapkod
- hack
- hash
- fej
- itt
- Hogyan
- HTTPS
- vizsgálja
- IT
- Jáva
- csatlakozik
- ugrás
- király
- nyelv
- nagy
- vonal
- Hosszú
- keres
- lottó
- férfi
- millió
- anya
- számok
- szervezet
- Papír
- Mintás
- Fizet
- Emberek (People)
- darab
- emelvény
- játszani
- játékos
- ponzi
- Ponzi-rendszer
- hatalom
- folyamat
- programozók
- Programozás
- nyilvános
- fordított
- Kritika
- Jutalmak
- szabályok
- Satoshi
- biztonság
- készlet
- okos
- okos szerződés
- Intelligens szerződések
- So
- szilárdság
- valami
- Centrifugálás
- osztott
- kezdődött
- nyilatkozat
- Stratégia
- sikeres
- sikeresen
- tech
- tesztek
- Keresztül
- idő
- szerszámok
- tranzakció
- bank nélküli
- egyetemi
- Frissítés
- érték
- sérülékenységek
- sebezhetőség
- Sebezhető
- pénztárca
- Mit
- Kerék
- WHO
- nyer
- Munka
- írás