اہم مواد پر جائیں

اسمارٹ کنٹریکٹ بگز کو تلاش کرنے کے لیے Slither کا استعمال کیسے کریں

solidity
اسمارٹ معاہدات
سیکورٹی
testing
ترقی
Trailofbits
9 جون، 2020
9 منٹ کی پڑھائی

Slither کا استعمال کیسے کریں

اس ٹیوٹوریل کا مقصد یہ دکھانا ہے کہ اسمارٹ کنٹریکٹس میں بگز کو خود بخود تلاش کرنے کے لیے Slither کا استعمال کیسے کیا جائے۔

انسٹالیشن

Slither کے لیے Python >= 3.6 درکار ہے۔ اسے pip کے ذریعے یا docker کا استعمال کرکے انسٹال کیا جاسکتا ہے۔

pip کے ذریعے Slither:

pip3 install --user slither-analyzer

docker کے ذریعے Slither:

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

آخری کمانڈ eth-security-toolbox کو ایک docker میں چلاتا ہے جس کی آپ کی موجودہ ڈائریکٹری تک رسائی ہے۔ آپ اپنے ہوسٹ سے فائلیں تبدیل کر سکتے ہیں، اور docker سے فائلوں پر ٹولز چلا سکتے ہیں

docker کے اندر، چلائیں:

solc-select 0.5.11
cd /home/trufflecon/

ایک اسکرپٹ چلانا

python 3 کے ساتھ ایک python اسکرپٹ چلانے کے لیے:

python3 script.py

کمانڈ لائن

کمانڈ لائن بمقابلہ صارف کے ذریعے متعین کردہ اسکرپٹس۔ Slither پہلے سے متعین ڈیٹیکٹرز کے ایک سیٹ کے ساتھ آتا ہے جو بہت سے عام بگز کو تلاش کرتے ہیں۔ کمانڈ لائن سے Slither کو کال کرنے پر تمام ڈیٹیکٹرز چل جائیں گے، اسٹیٹک تجزیہ کے تفصیلی علم کی ضرورت نہیں:

slither project_paths

ڈیٹیکٹرز کے علاوہ، Slither میں اس کے پرنٹرزopens in a new tab اور ٹولزopens in a new tab کے ذریعے کوڈ ریویو کی صلاحیتیں ہیں۔

پرائیویٹ ڈیٹیکٹرز اور GitHub انٹیگریشن تک رسائی حاصل کرنے کے لیے crytic.ioopens in a new tab کا استعمال کریں۔

اسٹیٹک تجزیہ

Slither اسٹیٹک تجزیہ فریم ورک کی صلاحیتوں اور ڈیزائن کو بلاگ پوسٹس (1opens in a new tab, 2opens in a new tab) اور ایک تعلیمی مقالےopens in a new tab میں بیان کیا گیا ہے۔

اسٹیٹک تجزیہ مختلف اقسام میں موجود ہے۔ آپ کو شاید اس بات کا احساس ہوگا کہ clangopens in a new tab اور gccopens in a new tab جیسے کمپائلرز ان تحقیقی تکنیکوں پر انحصار کرتے ہیں، لیکن یہ (Inferopens in a new tab, CodeClimateopens in a new tab, FindBugsopens in a new tab اور Frama-Copens in a new tab اور Polyspaceopens in a new tab جیسے رسمی طریقوں پر مبنی ٹولز) کی بھی بنیاد ہے۔

ہم یہاں اسٹیٹک تجزیہ کی تکنیکوں اور محققین کا جامع طور پر جائزہ نہیں لیں گے۔ اس کے بجائے، ہم اس بات پر توجہ مرکوز کریں گے کہ Slither کے کام کرنے کے طریقے کو سمجھنے کے لیے کیا ضروری ہے تاکہ آپ بگز کو تلاش کرنے اور کوڈ کو سمجھنے کے لیے اس کا زیادہ مؤثر طریقے سے استعمال کر سکیں۔

کوڈ کی نمائندگی

ڈائنامک تجزیہ کے برعکس، جو ایک ہی ایگزیکیوشن پاتھ کے بارے میں استدلال کرتا ہے، اسٹیٹک تجزیہ ایک ہی وقت میں تمام پاتھس کے بارے میں استدلال کرتا ہے۔ ایسا کرنے کے لیے، یہ ایک مختلف کوڈ کی نمائندگی پر انحصار کرتا ہے۔ دو سب سے عام ہیں ایبسٹریکٹ سنٹیکس ٹری (AST) اور کنٹرول فلو گراف (CFG)۔

ایبسٹریکٹ سنٹیکس ٹریز (AST)

AST کا استعمال ہر بار کیا جاتا ہے جب کمپائلر کوڈ کو پارس کرتا ہے۔ یہ شاید سب سے بنیادی ڈھانچہ ہے جس پر اسٹیٹک تجزیہ کیا جا سکتا ہے۔

مختصراً، ایک AST ایک سٹرکچرڈ ٹری ہے جہاں، عام طور پر، ہر لیف میں ایک ویری ایبل یا ایک کانسٹنٹ ہوتا ہے اور انٹرنل نوڈز آپرینڈز یا کنٹرول فلو آپریشنز ہوتے ہیں۔ درج ذیل کوڈ پر غور کریں:

1function safeAdd(uint a, uint b) pure internal returns(uint){
2 if(a + b <= a){
3 revert();
4 }
5 return a + b;
6}

متعلقہ AST کو اس میں دکھایا گیا ہے:

AST

Slither, solc کے ذریعے ایکسپورٹ کردہ AST کا استعمال کرتا ہے۔

بنانے میں آسان ہونے کے باوجود، AST ایک نیسٹڈ سٹرکچر ہے۔ بعض اوقات، اس کا تجزیہ کرنا سب سے سیدھا نہیں ہوتا ہے۔ مثال کے طور پر، ایکسپریشن a + b <= a کے ذریعے استعمال ہونے والے آپریشنز کی شناخت کے لیے، آپ کو پہلے <= اور پھر + کا تجزیہ کرنا ہوگا۔ ایک عام طریقہ نام نہاد وزیٹر پیٹرن کا استعمال کرنا ہے، جو ٹری کے ذریعے ریکرسیولی نیویگیٹ کرتا ہے۔ Slither میں ExpressionVisitoropens in a new tab میں ایک عام وزیٹر موجود ہے۔

درج ذیل کوڈ ExpressionVisitor کا استعمال کرتا ہے یہ پتہ لگانے کے لیے کہ آیا ایکسپریشن میں کوئی ایڈیشن ہے:

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()}')
سب دکھائیں

کنٹرول فلو گراف (CFG)

دوسری سب سے عام کوڈ کی نمائندگی کنٹرول فلو گراف (CFG) ہے۔ جیسا کہ اس کے نام سے ظاہر ہے، یہ ایک گراف پر مبنی نمائندگی ہے جو تمام ایگزیکیوشن پاتھس کو ظاہر کرتی ہے۔ ہر نوڈ میں ایک یا ایک سے زیادہ ہدایات ہوتی ہیں۔ گراف میں ایجز کنٹرول فلو آپریشنز (if/then/else, loop, وغیرہ) کی نمائندگی کرتے ہیں۔ ہماری پچھلی مثال کا CFG یہ ہے:

CFG

CFG وہ نمائندگی ہے جس کے اوپر زیادہ تر تجزیے بنائے جاتے ہیں۔

بہت سی دوسری کوڈ کی نمائندگیاں موجود ہیں۔ ہر نمائندگی کے اپنے فائدے اور نقصانات ہیں اس تجزیہ کے مطابق جو آپ کرنا چاہتے ہیں۔

تجزیہ

سب سے آسان قسم کے تجزیے جو آپ Slither کے ساتھ کر سکتے ہیں وہ سنٹیکٹک تجزیے ہیں۔

سنٹیکس کا تجزیہ

Slither پیٹرن میچنگ جیسے طریقے کا استعمال کرتے ہوئے تضادات اور خامیوں کو تلاش کرنے کے لیے کوڈ کے مختلف اجزاء اور ان کی نمائندگی کے ذریعے نیویگیٹ کر سکتا ہے۔

مثال کے طور پر درج ذیل ڈیٹیکٹرز سنٹیکس سے متعلقہ مسائل کو تلاش کرتے ہیں:

سیمنٹک تجزیہ

سنٹیکس تجزیہ کے برعکس، ایک سیمنٹک تجزیہ زیادہ گہرائی میں جائے گا اور کوڈ کے "معنی" کا تجزیہ کرے گا۔ اس فیملی میں کچھ وسیع اقسام کے تجزیے شامل ہیں۔ یہ زیادہ طاقتور اور مفید نتائج کی طرف لے جاتے ہیں، لیکن لکھنے میں بھی زیادہ پیچیدہ ہیں۔

سیمنٹک تجزیے سب سے جدید کمزوریوں کا پتہ لگانے کے لیے استعمال کیے جاتے ہیں۔

ڈیٹا کا انحصاری تجزیہ

ایک ویری ایبل variable_a کو variable_b پر ڈیٹا-ڈیپینڈینٹ کہا جاتا ہے اگر کوئی ایسا پاتھ ہے جس کے لیے variable_a کی قدر variable_b سے متاثر ہوتی ہے۔

درج ذیل کوڈ میں، variable_a، variable_b پر منحصر ہے:

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

Slither بلٹ ان ڈیٹا ڈیپینڈینسیopens in a new tab کی صلاحیتوں کے ساتھ آتا ہے، اس کی درمیانی نمائندگی کی بدولت (جس پر بعد کے سیکشن میں بحث کی گئی ہے)۔

ڈیٹا ڈیپینڈینسی کے استعمال کی ایک مثال خطرناک سخت مساوات ڈیٹیکٹرopens in a new tab میں مل سکتی ہے۔ یہاں Slither ایک خطرناک قدر کے ساتھ سخت مساوات کے موازنہ کو تلاش کرے گا (incorrect_strict_equality.py#L86-L87opens in a new tab)، اور صارف کو مطلع کرے گا کہ اسے کسی حملہ آور کو کنٹریکٹ میں پھنسانے سے روکنے کے لیے == کے بجائے >= یا <= کا استعمال کرنا چاہیے۔ دیگر چیزوں کے علاوہ، ڈیٹیکٹر balanceOf(address) (incorrect_strict_equality.py#L63-L64opens in a new tab) پر کال کی واپسی کی قدر کو خطرناک سمجھے گا، اور اس کے استعمال کو ٹریک کرنے کے لیے ڈیٹا ڈیپینڈینسی انجن کا استعمال کرے گا۔

فکسڈ پوائنٹ کمپیوٹیشن

اگر آپ کا تجزیہ CFG کے ذریعے نیویگیٹ کرتا ہے اور ایجز کی پیروی کرتا ہے، تو آپ کو پہلے سے دیکھے گئے نوڈس نظر آنے کا امکان ہے۔ مثال کے طور پر، اگر ایک لوپ کو نیچے دکھایا گیا ہے:

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

آپ کے تجزیہ کو یہ جاننے کی ضرورت ہوگی کہ کب رکنا ہے۔ یہاں دو اہم حکمت عملیاں ہیں: (1) ہر نوڈ پر ایک محدود تعداد میں ایٹریٹ کریں، (2) ایک نام نہاد فکس پوائنٹ کا حساب لگائیں۔ ایک فکس پوائنٹ کا بنیادی طور پر مطلب ہے کہ اس نوڈ کا تجزیہ کوئی بامعنی معلومات فراہم نہیں کرتا ہے۔

فکس پوائنٹ کے استعمال کی ایک مثال ری اینٹرینسی ڈیٹیکٹرز میں مل سکتی ہے: Slither نوڈس کو ایکسپلور کرتا ہے، اور ایکسٹرنل کالز، اسٹوریج میں لکھنے اور پڑھنے کی تلاش کرتا ہے۔ ایک بار جب یہ فکس پوائنٹ (reentrancy.py#L125-L131opens in a new tab) تک پہنچ جاتا ہے، تو یہ ایکسپلوریشن کو روک دیتا ہے، اور نتائج کا تجزیہ کرتا ہے یہ دیکھنے کے لیے کہ آیا ری اینٹرینسی موجود ہے، مختلف ری اینٹرینسی پیٹرنز (reentrancy_benign.pyopens in a new tab, reentrancy_read_before_write.pyopens in a new tab, reentrancy_eth.pyopens in a new tab) کے ذریعے۔

موثر فکسڈ پوائنٹ کمپیوٹیشن کا استعمال کرتے ہوئے تجزیے لکھنے کے لیے اس بات کی اچھی سمجھ کی ضرورت ہوتی ہے کہ تجزیہ اپنی معلومات کو کیسے پھیلاتا ہے۔

درمیانی نمائندگی

ایک درمیانی نمائندگی (IR) ایک ایسی زبان ہے جو اصل زبان کے مقابلے میں اسٹیٹک تجزیہ کے لیے زیادہ موزوں ہو۔ Slither, Solidity کو اپنے IR: SlithIRopens in a new tab میں ترجمہ کرتا ہے۔

اگر آپ صرف بنیادی چیکس لکھنا چاہتے ہیں تو SlithIR کو سمجھنا ضروری نہیں ہے۔ تاہم، اگر آپ جدید سیمنٹک تجزیے لکھنے کا ارادہ رکھتے ہیں تو یہ کام آئے گا۔ SlithIRopens in a new tab اور SSAopens in a new tab پرنٹرز آپ کو یہ سمجھنے میں مدد کریں گے کہ کوڈ کا ترجمہ کیسے ہوتا ہے۔

API کی بنیادی باتیں

Slither میں ایک API ہے جو آپ کو کنٹریکٹ اور اس کے فنکشنز کی بنیادی خصوصیات کو ایکسپلور کرنے دیتا ہے۔

کوڈبیس کو لوڈ کرنے کے لیے:

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

کنٹریکٹس اور فنکشنز کو ایکسپلور کرنا

ایک Slither آبجیکٹ میں ہوتا ہے:

  • contracts (list(Contract): کنٹریکٹس کی فہرست
  • contracts_derived (list(Contract): ان کنٹریکٹس کی فہرست جو کسی دوسرے کنٹریکٹ سے موروثی نہیں ہیں (کنٹریکٹس کا سب سیٹ)
  • get_contract_from_name (str): اس کے نام سے ایک کنٹریکٹ واپس کریں

ایک Contract آبجیکٹ میں ہوتا ہے:

  • name (str): کنٹریکٹ کا نام
  • functions (list(Function)): فنکشنز کی فہرست
  • modifiers (list(Modifier)): فنکشنز کی فہرست
  • all_functions_called (list(Function/Modifier)): کنٹریکٹ کے ذریعے پہنچنے کے قابل تمام اندرونی فنکشنز کی فہرست
  • inheritance (list(Contract)): موروثی کنٹریکٹس کی فہرست
  • get_function_from_signature (str): اس کے سگنیچر سے ایک فنکشن واپس کریں
  • get_modifier_from_signature (str): اس کے سگنیچر سے ایک موڈیفائر واپس کریں
  • get_state_variable_from_name (str): اس کے نام سے ایک اسٹیٹ ویری ایبل واپس کریں

ایک Function یا Modifier آبجیکٹ میں ہوتا ہے:

  • name (str): فنکشن کا نام
  • contract (contract): وہ کنٹریکٹ جہاں فنکشن کا اعلان کیا گیا ہے
  • nodes (list(Node)): فنکشن/موڈیفائر کے CFG کو بنانے والے نوڈس کی فہرست
  • entry_point (Node): CFG کا انٹری پوائنٹ
  • variables_read (list(Variable)): پڑھے گئے ویری ایبلز کی فہرست
  • variables_written (list(Variable)): لکھے گئے ویری ایبلز کی فہرست
  • state_variables_read (list(StateVariable)): پڑھے گئے اسٹیٹ ویری ایبلز کی فہرست (ویری ایبلز`ریڈ کا سب سیٹ)
  • state_variables_written (list(StateVariable)): لکھے گئے اسٹیٹ ویری ایبلز کی فہرست (ویری ایبلز`رٹن کا سب سیٹ)

صفحہ کی آخری تازہ کاری: 3 فروری، 2025

کیا یہ ٹیوٹوریل کارآمد تھا؟