# Smart Contract Audit Contests कैसे जीतें
Public audit contests security में सबसे तेज़ और सबसे कठोर feedback loop देते हैं। आप वही codebase पढ़ते हैं जिसे पूरी दुनिया भी पढ़ रही है, आपके पास कुछ ही दिन होते हैं, और पैसा सिर्फ़ unique, valid और high-severity findings पर मिलता है। यह guide एक ऐसा workflow देती है जो बिखरी हुई मेहनत को लगातार अच्छे placements में बदलता है, आपके पहले contest से लेकर पहली leaderboard finish तक।
शुरू करने से पहले अपनी expectations तय करें
ज़्यादातर नए लोग एक या दो contests के बाद छोड़ देते हैं क्योंकि उन्होंने तुरंत पैसे जीतने की उम्मीद की थी। reward distribution बहुत asymmetric होती है: एक अकेला High दस Lows से भारी पड़ता है, और duplicates pot को बाँट देते हैं। पहले दस contests में आपका असली लक्ष्य calibration है: यह सीखना कि कौन से findings valid हैं, कौन से noise हैं, और judges severity को कैसे तौलते हैं। शुरुआती contests को paid practice मानें।
ज़्यादातर contest frameworks में severity, impact गुणा likelihood का एक function होती है:
- High: funds का सीधा नुकसान या lock हो जाना, या साफ़ तौर पर protocol तोड़ने वाला state, एक plausible path के साथ।
- Medium: नुकसान सिर्फ़ specific conditions में, या core functionality टूटना बिना सीधे चोरी के।
- Low / Informational: code quality, funds या logic पर कोई असली impact नहीं। यह शायद ही कभी pay करता है।
अगर कोई bug "और इसलिए funds खो जाते हैं, फँस जाते हैं या चोरी हो जाते हैं" पर खत्म नहीं हो सकता, तो वह शायद High नहीं है।
Phase 1: तेज़ी से scope करें (पहले दो घंटे)
सबसे बड़ी file की पहली line से शुरू मत कीजिए। पहले एक map बनाइए।
cloc या solidity-metrics जैसे tools दिखाते हैं कि complexity कहाँ है।# तेज़ complexity map
cloc src/ --by-file
# external और public functions गिनें, यानी attack surface
grep -rEn 'function .*\b(external|public)\b' src/ | wc -l
phase one के अंत तक आपको दो वाक्यों में बता पाना चाहिए कि protocol कैसे पैसा कमाता और घुमाता है। अगर नहीं बता पाते, तो mapping जारी रखें।
Phase 2: high-severity bugs की खोज करें
Generality, line-by-line पढ़ने से बेहतर है। codebase को बार-बार आने वाली bug classes के lens से देखें, क्योंकि एक ही गलतियाँ अलग-अलग protocols में दोहराई जाती हैं।
वे bug classes जो score करती हैं
- Accounting और rounding. multiplication से पहले division, गलत दिशा में round होने वाली fee math, vaults में share-price manipulation (ERC-4626 पर classic first-depositor inflation attack)।
- Access control gaps. किसी privileged function पर modifier न होना, दो बार call हो सकने वाला initializer, गलत address की तुलना करने वाला role check।
- Reentrancy, जिसमें read-only reentrancy भी शामिल है। callback के बीच में state पढ़ना उसके update होने से पहले। cross-function और cross-contract variants में ही असली पैसा होता है, textbook वाला single-function case नहीं।
- Oracle और price manipulation. एक ही AMM pool से spot price, कोई TWAP नहीं, price feed पर कोई staleness check नहीं।
- Unchecked external calls और return values. ऐसा token जो revert करने के बजाय
falseलौटाता है, ऐसा low-levelcallजिसका success flag ignore कर दिया जाता है।
- Slippage और deadline. बिना minimum-out या hardcoded zero वाले swaps, जो users को sandwiching के लिए खुला छोड़ देते हैं।
इस realistic vault pattern को देखें। bug subtle और high-severity है:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Vault {
mapping(address => uint256) public shares;
uint256 public totalShares;
IERC20 public immutable asset;
constructor(IERC20 _asset) {
asset = _asset;
}
function deposit(uint256 amount) external returns (uint256 minted) {
uint256 totalAssets = asset.balanceOf(address(this));
// जब totalShares == 0 हो, shares 1:1 mint होते हैं
minted = totalShares == 0
? amount
: (amount * totalShares) / totalAssets;
shares[msg.sender] += minted;
totalShares += minted;
asset.transferFrom(msg.sender, address(this), amount);
}
}
finding: एक attacker 1 wei deposit करता है, 1 share पाता है, फिर asset की बड़ी मात्रा सीधे vault को transfer कर देता है। अब totalAssets बहुत बड़ा है जबकि totalShares सिर्फ़ 1 है। अगला ईमानदार depositor minted = (amount * 1) / totalAssets निकालता है, जो एक असली deposit के लिए round down होकर zero shares बन जाता है, और उसके funds attacker को दान कर देता है। fix यह है कि construction पर dead shares mint करें, या balanceOf पढ़ने के बजाय totalAssets को internally track करें।
इन्हें असल में कैसे खोजें
- हर external function के लिए पूछें: अगर मैं इसे zero के साथ, max uint के साथ, एक ही transaction में दो बार, या तय order से बाहर call करूँ तो क्या होगा?
- हर
transferऔरcallको follow करें। पक्का करें कि return value check हो रहा है और external call से पहले state update हो रहा है।
- एक property लिखें और उसे fuzzer से तोड़ने की कोशिश करें। accounting bugs के लिए Foundry के invariant tests बहुत अच्छे हैं:
function invariant_totalSharesBackedByAssets() public view {
// कुल redeemable value कभी रखे हुए assets से ज़्यादा नहीं होनी चाहिए
assertLe(vault.totalShares(), asset.balanceOf(address(vault)) + 1);
}
एक pass होता हुआ proof-of-concept test "शायद" को High में बदल देता है। judges उन findings को reward करते हैं जिन्हें वे चला सकें।
Phase 3: ऐसे reports लिखें जिन्हें judges reward करें
सही bug भी कमज़ोर writeup के साथ downgrade हो जाता है या किसी बेहतर लिखे finding का duplicate मार दिया जाता है। हर finding को एक ही तरह structure करें:
एक थके हुए reader के लिए लिखें। impact पहली line में बताएँ, उसे कभी मत दबाएँ। speculation से बचें: अगर आप नुकसान दिखा नहीं सकते, तो ईमानदारी से कहें और खुद को downgrade करें, बजाय इसके कि "invalid" mark का जोखिम लें जो आपके accuracy score को नुकसान पहुँचाता है।
पूरे contest window में time management
एक हफ़्ते का contest एक marathon है जिसके अंत में एक sprint होता है।
- Day 1: सिर्फ़ scope और mapping। अभी कोई finding नहीं।
- Days 2 से 4: money paths के साथ गहरी dives, एक बार में एक subsystem। हर शक एक scratch file में लिखें, चाहे आधा-अधूरा ही क्यों न हो।
- Day 5: अपनी सबसे मज़बूत leads के लिए proof-of-concept tests बनाएँ। कमज़ोर leads छोड़ दें।
- Final day: writeups को polish करें, severities दोबारा check करें, submit करें। आख़िरी घंटों में किसी नई lead के पीछे मत भागें; जो साबित कर सकते हैं उसे पूरा करें।
अपना ध्यान बचाकर रखें। एक subsystem पर दो घंटे की focused review, सब कुछ सरसरी तौर पर देखने के पूरे दिन से बेहतर है।
beginner से आगे बढ़ना
- judged reports पढ़ें। हर contest के बाद उन Highs का अध्ययन करें जो place हुए। आपको वही patterns दोबारा दिखेंगे।
- एक personal bug-class checklist रखें और हर contract को उसमें से गुज़ारें। आपकी बढ़त pattern recognition है, और checklist इसे systematic बनाती है।
- Specialize करें। एक niche चुनें (vaults, lending, bridges, AMMs) और गहराई में जाएँ। specialists अपने domain में generalists से ज़्यादा findings निकालते हैं।
- proof-of-concept की muscle बनाएँ। Foundry tests लिखने की speed सीधे तौर पर यह multiply करती है कि deadline से पहले आप कितने findings confirm कर सकते हैं।
इसे hands-on practice करें
इन bug classes को आत्मसात करने का सबसे तेज़ तरीका है उन्हें एक सुरक्षित environment में जानबूझकर exploit करना, फिर उन्हें fix करना। app.solingo-blockchain.xyz पर आप audit-style exercises कर सकते हैं, proof-of-concept exploits लिख सकते हैं, और अपने severity reasoning को worked solutions से मिलाकर देख सकते हैं। accounting और access-control tracks से शुरू करें, फिर reentrancy और oracle manipulation पर जाएँ। code पढ़ें, उसे तोड़ें, report लिखें, दोहराएँ।