Akıllı sözleşme hatalarını bulmak için Slither nasıl kullanılır?
Slither Nasıl Kullanılır?
Bu öğreticinin amacı, akıllı sözleşmelerdeki hataları otomatik olarak bulmak için Slither'ın nasıl kullanılacağını göstermektir.
- Kurulum
- Komut satırı kullanımı
- Statik analize giriş: Statik analize kısa bir giriş
- API: Python API'si açıklaması
Kurulum
Slither, Python >= 3.6 gerektirir. Pip veya docker kullanılarak kurulabilir.
Pip aracılığıyla Slither:
pip3 install --user slither-analyzerDocker aracılığıyla Slither:
docker pull trailofbits/eth-security-toolboxdocker run -it -v "$PWD":/home/trufflecon trailofbits/eth-security-toolboxSon komut, geçerli dizininize erişimi olan bir docker'da eth-security-toolbox'ı çalıştırır. Dosyaları ana makinenizden değiştirebilir ve docker'dan dosyalar üzerindeki araçları çalıştırabilirsiniz
Docker içinde şunu çalıştırın:
solc-select 0.5.11cd /home/trufflecon/Bir betik çalıştırma
Python 3 ile bir python betiği çalıştırmak için:
python3 script.pyKomut satırı
Komut satırı ve kullanıcı tanımlı komut dosyaları. Slither, birçok yaygın hatayı bulan bir dizi önceden tanımlanmış algılayıcıyla birlikte gelir. Slither'ı komut satırından çağırmak tüm algılayıcıları çalıştırır, ayrıntılı statik analiz bilgisi gerekmez:
slither project_pathsDedektörlere ek olarak Slither, yazıcılarıopens in a new tab ve araçlarıopens in a new tab aracılığıyla kod inceleme yeteneklerine sahiptir.
Özel dedektörlere ve GitHub entegrasyonuna erişmek için crytic.ioopens in a new tab kullanın.
Statik analiz
Slither statik analiz çatısının yetenekleri ve tasarımı, blog gönderilerinde (1opens in a new tab, 2opens in a new tab) ve bir akademik makaledeopens in a new tab açıklanmıştır.
Statik analizin farklı türleri mevcuttur. clangopens in a new tab ve gccopens in a new tab gibi derleyicilerin bu araştırma tekniklerine dayandığını büyük olasılıkla fark etmişsinizdir, ancak bu aynı zamanda Inferopens in a new tab, CodeClimateopens in a new tab, FindBugsopens in a new tab ve Frama-Copens in a new tab ile Polyspaceopens in a new tab gibi resmi yöntemlere dayalı araçların da temelini oluşturur.
Burada statik analiz tekniklerini ve araştırmalarını kapsamlı bir şekilde incelemeyeceğiz. Bunun yerine, hataları bulmak ve kodu anlamak amacıyla onu daha etkili bir şekilde kullanabilmeniz için Slither'ın nasıl çalıştığını anlamak için gerekenlere odaklanacağız.
Kod temsili
Tek bir yürütme yolunu değerlendiren dinamik analizin aksine, statik analiz aynı anda tüm yolları değerlendirir. Bunu yapmak için farklı bir kod temsiline dayanır. En yaygın iki tanesi soyut sözdizimi ağacı (AST) ve kontrol akış grafiğidir (CFG).
Soyut Sözdizimi Ağaçları (AST)
AST, derleyici kodu her ayrıştırdığında kullanılır. Bu, muhtemelen statik analizin gerçekleştirilebileceği en temel yapıdır.
Özetle bir AST, genellikle her yaprağın bir değişken veya bir sabit içerdiği ve iç düğümlerin işlenenler veya kontrol akışı işlemleri olduğu yapılandırılmış bir ağaçtır. Aşağıdaki kodu göz önünde bulundurun:
1function safeAdd(uint a, uint b) pure internal returns(uint){2 if(a + b <= a){3 revert();4 }5 return a + b;6}İlgili AST şurada gösterilir:
Slither, solc tarafından dışa aktarılan AST'yi kullanır.
Oluşturulması basit olsa da, AST iç içe geçmiş bir yapıdır. Bazen, bunu analiz etmek pek kolay olmayabilir. Örneğin, a + b <= a ifadesinin kullandığı işlemleri belirlemek için önce <= ve ardından +yı analiz etmelisiniz. Yaygın bir yaklaşım, ağaçta özyinelemeli olarak gezinen ziyaretçi desenini kullanmaktır. Slither, ExpressionVisitoropens in a new tab içinde jenerik bir ziyaretçi içerir.
Aşağıdaki kod, ifadenin bir toplama işlemi içerip içermediğini tespit etmek için ExpressionVisitor kullanır:
1from slither.visitors.expression.expression import ExpressionVisitor2from slither.core.expressions.binary_operation import BinaryOperationType34class HasAddition(ExpressionVisitor):56 def result(self):7 return self._result89 def _post_binary_operation(self, expression):10 if expression.type == BinaryOperationType.ADDITION:11 self._result = True1213visitor = HasAddition(expression) # expression, test edilecek ifadedir14print(f'{expression} ifadesi bir toplama içeriyor: {visitor.result()}')Tümünü gösterKontrol Akış Grafiği (CFG)
İkinci en yaygın kod temsili kontrol akış grafiğidir (CFG). Adından da anlaşılacağı gibi, bu, tüm yürütme yollarını ortaya çıkaran graf tabanlı bir gösterimdir. Her düğüm bir veya daha fazla talimat içerir. Grafikteki kenarlar kontrol akışı işlemlerini (if/then/else, döngü vb.) temsil eder. Önceki örneğimizin CFG'si şöyledir:
CFG, analizlerin çoğunun üzerine inşa edildiği temsildir.
Daha birçok kod gösterimi mevcuttur. Her bir gösterimin, gerçekleştirmek istediğiniz analize göre avantajları ve dezavantajları vardır.
Analiz
Slither ile gerçekleştirebileceğiniz en basit analiz türleri sözdizimsel analizlerdir.
Sözdizimi analizi
Slither, desen eşleştirme benzeri bir yaklaşım kullanarak tutarsızlıkları ve kusurları bulmak için kodun farklı bileşenleri ve onların gösterimleri arasında gezinebilir.
Örneğin, aşağıdaki dedektörler söz dizimiyle ilgili sorunları arar:
-
Durum değişkeni gölgelemeopens in a new tab: tüm durum değişkenleri üzerinde yinelenir ve herhangi birinin kalıtılmış bir sözleşmeden bir değişkeni gölgeleyip gölgelemediğini kontrol eder (state.py#L51-L62opens in a new tab)
-
Hatalı ERC20 arayüzüopens in a new tab: hatalı ERC20 fonksiyon imzalarını arar (incorrect_erc20_interface.py#L34-L55opens in a new tab)
Anlamsal analiz
Sözdizimi analizinin aksine, anlamsal bir analiz daha derine iner ve kodun "anlamını" analiz eder. Bu aile, bazı genel analiz türlerini içerir. Bunlar daha güçlü ve kullanışlı sonuçlara yol açar, ancak yazılmaları da daha karmaşıktır.
Anlamsal analizler, en gelişmiş güvenlik açığı tespitleri için kullanılır.
Veri bağımlılığı analizi
variable_a'nın değerinin variable_b'den etkilendiği bir yol varsa, variable_a değişkeninin variable_b'ye veri bağımlı olduğu söylenir.
Aşağıdaki kodda variable_a değişkeni variable_b'ye bağımlıdır:
1// ...2variable_a = variable_b + 1;Slither, ara gösterimi (ileriki bir bölümde ele alınacaktır) sayesinde yerleşik veri bağımlılığıopens in a new tab yetenekleriyle birlikte gelir.
Veri bağımlılığı kullanımına bir örnek, tehlikeli katı eşitlik dedektöründeopens in a new tab bulunabilir. Burada Slither, tehlikeli bir değere katı eşitlik karşılaştırması arar (incorrect_strict_equality.py#L86-L87opens in a new tab) ve bir saldırganın sözleşmeyi tuzağa düşürmesini önlemek için kullanıcıya == yerine >= veya <= kullanması gerektiğini bildirir. Diğer şeylerin yanı sıra dedektör, balanceOf(address) çağrısının dönüş değerini tehlikeli olarak kabul eder (incorrect_strict_equality.py#L63-L64opens in a new tab) ve kullanımını izlemek için veri bağımlılığı motorunu kullanır.
Sabit nokta hesaplaması
Analiziniz CFG içinde gezinir ve kenarları takip ederse, daha önce ziyaret edilmiş düğümleri görmeniz olasıdır. Örneğin, bir döngü aşağıda gösterildiği gibi sunulursa:
1for(uint i; i < range; ++){2 variable_a += 13}Analizinizin ne zaman duracağını bilmesi gerekir. Burada iki ana strateji vardır: (1) her düğümde sonlu sayıda yineleme yapmak, (2) sabit nokta adı verilen bir şeyi hesaplamak. Sabit nokta, temel olarak bu düğümü analiz etmenin artık anlamlı bir bilgi sağlamadığı anlamına gelir.
Kullanılan bir sabit nokta örneği, yeniden giriş dedektörlerinde bulunabilir: Slither düğümleri araştırır ve harici çağrıları, depolamaya yazma ve okuma işlemlerini arar. Bir sabit noktaya ulaştığında (reentrancy.py#L125-L131opens in a new tab), keşfi durdurur ve farklı yeniden giriş desenleri (reentrancy_benign.pyopens in a new tab, reentrancy_read_before_write.pyopens in a new tab, reentrancy_eth.pyopens in a new tab) aracılığıyla bir yeniden girişin mevcut olup olmadığını görmek için sonuçları analiz eder.
Verimli sabit nokta hesaplaması kullanarak analizler yazmak, analizin kendi bilgilerini nasıl yaydığını iyi anlamayı gerektirir.
Ara temsil
Bir ara temsil (IR), statik analize orijinalinden daha elverişli olması amaçlanan bir dildir. Slither, Solidity'yi kendi IR'si olan SlithIRopens in a new tab'ye çevirir.
Yalnızca temel kontroller yazmak istiyorsanız SlithIR'ı anlamanız gerekli değildir. Ancak, gelişmiş anlamsal analizler yazmayı planlıyorsanız kullanışlı olacaktır. SlithIRopens in a new tab ve SSAopens in a new tab yazıcıları, kodun nasıl çevrildiğini anlamanıza yardımcı olacaktır.
API Temelleri
Slither'ın, sözleşmenin ve fonksiyonlarının temel niteliklerini keşfetmenizi sağlayan bir API'si vardır.
Bir kod tabanını yüklemek için:
1from slither import Slither2slither = Slither('/path/to/project')3Sözleşmeleri ve fonksiyonları keşfetme
Bir Slither nesnesi şunlara sahiptir:
contracts (list(Contract): sözleşme listesicontracts_derived (list(Contract): başka bir sözleşme tarafından kalıtılmayan sözleşmelerin listesi (sözleşmelerin alt kümesi)get_contract_from_name (str): Adından bir sözleşme döndürür
Bir Contract nesnesi şunlara sahiptir:
name (str): Sözleşmenin adıfunctions (list(Function)): Fonksiyon listesimodifiers (list(Modifier)): Niteleyici listesiall_functions_called (list(Function/Modifier)): Sözleşme tarafından erişilebilen tüm dahili fonksiyonların listesiinheritance (list(Contract)): Kalıtılmış sözleşmelerin listesiget_function_from_signature (str): İmzasından bir Fonksiyon döndürürget_modifier_from_signature (str): İmzasından bir Niteleyici döndürürget_state_variable_from_name (str): Adından bir StateVariable (Durum Değişkeni) döndürür
Bir Function veya Modifier nesnesi şunlara sahiptir:
name (str): Fonksiyonun adıcontract (contract): fonksiyonun bildirildiği sözleşmenodes (list(Node)): Fonksiyonun/niteleyicinin CFG'sini oluşturan düğümlerin listesientry_point (Node): CFG'nin giriş noktasıvariables_read (list(Variable)): Okunan değişkenlerin listesivariables_written (list(Variable)): Yazılan değişkenlerin listesistate_variables_read (list(StateVariable)): Okunan durum değişkenlerinin listesi (okunandeğişkenlerinalt kümesi)state_variables_written (list(StateVariable)): Yazılan durum değişkenlerinin listesi (yazılandeğişkenlerinalt kümesi)
Sayfanın son güncellenmesi: 3 Şubat 2025

