Ana içeriğe geç

Akıllı sözleşme hatalarını bulmak için Slither nasıl kullanılır

solidityakıllı kontratlargüvenliktest etmekstatik analiz
Gelişmiş
Trailofbits
Güvenli sözleşmeler oluşturmak(opens in a new tab)
9 Haziran 2020
6 dakikalık okuma minute read

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 giriş
  • API: Python API açıklaması

Kurulum

Slither, Python >= 3.6 gerektirir. Pip veya docker kullanılarak kurulabilir.

Pip aracılığıyla Slither:

pip3 install --user slither-analyzer

Docker aracılığıyla Slither:

docker pull trailofbits/eth-security-toolbox
docker run -it -v "$PWD":/home/trufflecon trailofbits/eth-security-toolbox

Son komut, geçerli dizininize erişimi olan bir docker'da eth-security-toolbox'ı çalıştırır. Dosyaları ana makinenizden değiştirebilir ve dosyalar üzerindeki araçları docker'dan çalıştırabilirsiniz

Docker'ın içinde şunu çalıştırın:

solc-select 0.5.11
cd /home/trufflecon/

Bir komut dosyası çalıştırma

Python 3 ile bir python komut dosyası çalıştırmak için:

python3 script.py

Komut 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_paths

Algılayıcılara ek olarak Slither, yazıcıları(opens in a new tab) ve araçları(opens in a new tab) aracılığıyla kod inceleme kabiliyetlerine sahiptir.

Özel algılayıcılara ve GitHub entegrasyonuna erişmek için crytic.io(opens in a new tab) kullanın.

Statik analiz

Slither statik analiz çerçevesinin kabiliyetleri ve dizaynı, blog gönderilerinde (1(opens in a new tab), 2(opens in a new tab)) ve bir akademik kağıtta(opens in a new tab) açıklanmıştır.

Statik analiz çeşit çeşittir. Büyük olasılıkla clang(opens in a new tab) ve gcc(opens in a new tab) gibi derleyicilerin bu araştırma tekniklerine bağlı olduğunun farkındasınızdır ancak bu, aynı zamanda Infer(opens in a new tab), CodeClimate(opens in a new tab), FindBugs(opens in a new tab) ve Frama-C(opens in a new tab) ve Polyspace(opens in a new tab) gibi resmî yöntemlere dayalı araçların da önemini vurgular.

Burada statik analiz tekniklerini ve araştırmacıyı etraflıca 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
  • Kod analizi
  • Ara temsil

Kod temsili

Tek bir yürütme yolu hakkında mantık oluşturan dinamik bir analizin aksine, statik analiz aynı anda tüm yollar hakkında mantık oluşturur. Bunu yapmak için farklı bir kod temsiline dayanır. Soyut söz dizimi ağacı (AST) ve kontrol akış grafiği (CFG) en yaygın iki statik analiz yöntemidir.

Soyut Söz Dizimi Ağaçları (AST)

AST, derleyici her kod ayrıştırdığında kullanılır. Muhtemelen statik analizin yapılabileceği en temel yapıdır.

Özetle bir AST, genellikle her yaprağın bir değişken veya sabit içerdiği ve dahili 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}
Kopyala

İlgili AST şurada gösterilir:

AST

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, bunun analiz edilmesi pek kolay olmayabilir. Örnek olarak, a + b <= a ifadesi tarafından kullanılan operasyonları tanımlamak için, öncelikle <= ve sonrasında + analiz etmelisiniz. Yaygın bir yaklaşım, ağaçta yinelemeli olarak gezinen sözde ziyaretçi desenini kullanmaktır. Slither, ExpressionVisitor(opens in a new tab) içinde genel bir ziyaretçi bulundurur.

Aşağıdaki kod, ifadenin bir ekleme içerip içermediğini algılamak için ExpressionVisitor kullanır:

1from slither.visitors.expression.expression import ExpressionVisitor
2from slither.core.expressions.binary_operation import BinaryOperationType
3
4class HasAddition(ExpressionVisitor):
5
6 def result(self):
7 return self._result
8
9 def _post_binary_operation(self, expression):
10 if expression.type == BinaryOperationType.ADDITION:
11 self._result = True
12
13visitor = HasAddition(expression) # expression is the expression to be tested
14print(f'The expression {expression} has a addition: {visitor.result()}')
Tümünü göster
Kopyala

Kontrol Akış Grafiği (CFG)

İkinci en yaygın kod temsili, kontrol akış grafiğidir (CFG). Adından da anlaşılacağı gibi, tüm yürütme yollarını ortaya çıkaran grafik tabanlı bir gösterimdir. Her düğüm bir veya birden fazla talimat içerir. Grafikteki kenarlar, kontrol akışı işlemlerini temsil eder (if/then/else, loop vb.). Önceki örneğimizin CFG'si:

CFG

CFG, analizlerin çoğunun üzerine inşa edildiği temsildir.

Diğer birçok kod temsili mevcuttur. Her temsilin yapmak istediğiniz analize göre avantajları ve dezavantajları vardır.

Analiz

Slither ile yapabileceğiniz en basit analiz türü söz dizimsel analizdir.

Söz Dizimi Analizi

Slither, desen eşleştirme benzeri bir yaklaşım kullanarak tutarsızlıkları ve kusurları bulmak için kodun farklı bileşenleri ve temsilleri arasında gezinebilir.

Örneğin, aşağıdaki algılayıcılar söz dizimi ile ilgili sorunları arar:

Semantik analiz

Söz dizimi analizinin aksine, semantik bir analiz daha derine inecek ve kodun "anlamını" analiz edecektir. Bu aile, bazı geniş analiz türlerini içerir. Daha güçlü ve kullanışlı sonuçlara yol açarlar, ancak aynı zamanda bunları yazmak daha karmaşıktır.

Semantik analiz, en gelişmiş güvenlik açığı tespitleri için kullanılır.

Veri bağımlılığı analizi

variable_a değerinin variable_b tarafından etkilendiği bir yol varsa, variable_a değişkeninin variable_b değişkenine veri bağımlı olduğu söylenir.

Sıradaki kodda, variable_a, variable_b'ye bağımlıdır:

1// ...
2variable_a = variable_b + 1;
Kopyala

Slither, ara temsil özelliği sayesinde (sonraki bir bölümde bahsedilecek) yerleşik veri bağımlılığı(opens in a new tab) kabiliyetleriyle gelir.

Veri bağımlılığı kullanımının bir örneği zararlı katı eşitlik algılayıcısında(opens in a new tab) bulunabilir. Burada Slither, tehlikeli bir değerle (incorrect_strict_equality.py#L86-L87(opens in a new tab)) katı bir eşitlik karşılaştırması arayacak ve bir saldırganın sözleşmeyi tuzağa düşürmesini önlemek için kullanıcıya == yerine >= veya <= kullanması gerektiğini bildirecektir. Diğerlerinin yanı sıra algılayıcı, balanceOf(address) (incorrect_strict_equality.py#L63-L64(opens in a new tab)) çağrısının dönüş değerini tehlikeli olarak değerlendirecektir ve kullanımını izlemek için veri bağımlılığı motorunu kullanır.

Sabit-nokta hesaplaması

Analiziniz CFG'de geziniyor ve kenarları takip ediyorsa, muhtemelen önceden ziyaret edilmiş düğümleri görmeniz olasıdır. Örneğin, aşağıda gösterildiği gibi bir döngü sunulursa:

1for(uint i; i < range; ++){
2 variable_a += 1
3}
Kopyala

Analizinizin ne zaman duracağını bilmesi gerekecek. Burada iki ana strateji vardır: (1) her bir düğümde sınırlı sayıda yineleme yapın, (2) düzeltme noktası olarak adlandırılan bir noktayı hesaplayın. Bir düzeltme noktası temel olarak, bu düğümü analiz etmenin herhangi bir anlamlı bilgi sağlamadığı anlamına gelir.

Kullanılan bir sabitleme noktası örneği yeniden giriş algılayıcılarında bulunabilir: Slither düğümleri araştırır ve harici çağrıları arar, belleğe yazar ve okur. Bir düzeltme noktasına ulaştığında (reentrancy.py#L125-L131(opens in a new tab)), keşfi durdurur ve farklı yeniden giriş modelleri aracılığıyla bir yeniden girişin olup olmadığını görmek için sonuçları analiz eder (reentrancy_benign.py(opens in a new tab), reentrancy_read_before_write.py(opens in a new tab), reentrancy_eth.py(opens in a new tab)).

Etkili sabit nokta hesaplama kullanarak analiz yazmak, analizin bilgilerini nasıl yaydığının iyi anlaşılmasını gerektirir.

Ara temsil

Bir ara temsil (IR), statik analize orijinalinden daha uygun olması amaçlanan bir dildir. Slither, Solidity'yi kendi IR'ına çevirir: SlithIR(opens in a new tab).

Yalnızca temel kontroller yazmak istiyorsanız SlithIR'ı anlamak gerekli değildir. Ancak, ileri düzey anlamsal analiz yazmayı planlıyorsanız kullanışlı olacaktır. SlithIR(opens in a new tab) ve SSA(opens in a new tab) yazıcıları, kodun nasıl çevirildiğini anlamanıza yardımcı olacaktır.

API Temelleri

Slither, sözleşmenin temel özelliklerini ve fonksiyonlarını keşfetmenizi sağlayan bir API'ye sahiptir.

Bir kod temelini yüklemek için:

1from slither import Slither
2slither = Slither('/path/to/project')
3
Kopyala

Sözleşmeleri ve fonksiyonları keşfetme

Bir Slither objesi şunlara sahiptir:

  • contracts (list(Contract): sözleşme listesi
  • contracts_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): İsminden bir sözleşmeyi döndürür

Bir Contract objesi şunlara sahiptir:

  • name (str): Sözleşmenin adı
  • functions (list(Function)): Fonksiyon listesi
  • modifiers (list(Modifier)): Fonksiyon listesi
  • all_functions_called (list(Function/Modifier)): Sözleşme tarafından erişilebilen tüm iç fonksiyonların listesi
  • inheritance (list(Contract)): Kalıtılan sözleşmelerin listesi
  • get_function_from_signature (str): İmzasından bir Function döndürür
  • get_modifier_from_signature (str): İmzasından bir Modifier döndürür
  • get_state_variable_from_name (str): İsminden bir StateVariable döndürür

Bir Function veya Modifier objesi şunlara sahiptir:

  • name (str): Fonksiyonun adı
  • contract (contract): Fonksiyonun duyurulduğu sözleşmenin adı
  • nodes (list(Node)): Fonksiyonun/niteleyicinin CFG'sini tutan düğümlerin listesi
  • entry_point (Node): CFG giriş noktası
  • variables_read (list(Variable)): Okunan değişkenlerin listesi
  • variables_written (list(Variable)): Yazılan değişkenlerin listesi
  • state_variables_read (list(StateVariable)): Okunan durum değişkenlerinin listesi (okunan değişkenlerin alt kümesi)
  • state_variables_written (list(StateVariable)): Yazılan durum değişkenlerinin listesi (yazılan değişkenlerin alt kümesi)

Son düzenleme: @nhsz(opens in a new tab), 15 Ağustos 2023

Bu rehber yararlı oldu mu?