@trailofbits/vsix-audit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +281 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +703 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/batch.d.ts +12 -0
- package/dist/scanner/batch.d.ts.map +1 -0
- package/dist/scanner/batch.js +104 -0
- package/dist/scanner/batch.js.map +1 -0
- package/dist/scanner/bundler.d.ts +35 -0
- package/dist/scanner/bundler.d.ts.map +1 -0
- package/dist/scanner/bundler.js +120 -0
- package/dist/scanner/bundler.js.map +1 -0
- package/dist/scanner/cache.d.ts +45 -0
- package/dist/scanner/cache.d.ts.map +1 -0
- package/dist/scanner/cache.js +153 -0
- package/dist/scanner/cache.js.map +1 -0
- package/dist/scanner/cache.test.d.ts +2 -0
- package/dist/scanner/cache.test.d.ts.map +1 -0
- package/dist/scanner/cache.test.js +149 -0
- package/dist/scanner/cache.test.js.map +1 -0
- package/dist/scanner/capabilities.d.ts +29 -0
- package/dist/scanner/capabilities.d.ts.map +1 -0
- package/dist/scanner/capabilities.js +217 -0
- package/dist/scanner/capabilities.js.map +1 -0
- package/dist/scanner/checks/ast.d.ts +3 -0
- package/dist/scanner/checks/ast.d.ts.map +1 -0
- package/dist/scanner/checks/ast.js +469 -0
- package/dist/scanner/checks/ast.js.map +1 -0
- package/dist/scanner/checks/ast.test.d.ts +2 -0
- package/dist/scanner/checks/ast.test.d.ts.map +1 -0
- package/dist/scanner/checks/ast.test.js +389 -0
- package/dist/scanner/checks/ast.test.js.map +1 -0
- package/dist/scanner/checks/behavioral.d.ts +3 -0
- package/dist/scanner/checks/behavioral.d.ts.map +1 -0
- package/dist/scanner/checks/behavioral.js +367 -0
- package/dist/scanner/checks/behavioral.js.map +1 -0
- package/dist/scanner/checks/blocklist.d.ts +3 -0
- package/dist/scanner/checks/blocklist.d.ts.map +1 -0
- package/dist/scanner/checks/blocklist.js +32 -0
- package/dist/scanner/checks/blocklist.js.map +1 -0
- package/dist/scanner/checks/blocklist.test.d.ts +2 -0
- package/dist/scanner/checks/blocklist.test.d.ts.map +1 -0
- package/dist/scanner/checks/blocklist.test.js +74 -0
- package/dist/scanner/checks/blocklist.test.js.map +1 -0
- package/dist/scanner/checks/chains.d.ts +35 -0
- package/dist/scanner/checks/chains.d.ts.map +1 -0
- package/dist/scanner/checks/chains.js +505 -0
- package/dist/scanner/checks/chains.js.map +1 -0
- package/dist/scanner/checks/chains.test.d.ts +2 -0
- package/dist/scanner/checks/chains.test.d.ts.map +1 -0
- package/dist/scanner/checks/chains.test.js +250 -0
- package/dist/scanner/checks/chains.test.js.map +1 -0
- package/dist/scanner/checks/dataflow.d.ts +3 -0
- package/dist/scanner/checks/dataflow.d.ts.map +1 -0
- package/dist/scanner/checks/dataflow.js +316 -0
- package/dist/scanner/checks/dataflow.js.map +1 -0
- package/dist/scanner/checks/dependencies.d.ts +13 -0
- package/dist/scanner/checks/dependencies.d.ts.map +1 -0
- package/dist/scanner/checks/dependencies.js +225 -0
- package/dist/scanner/checks/dependencies.js.map +1 -0
- package/dist/scanner/checks/dependencies.test.d.ts +2 -0
- package/dist/scanner/checks/dependencies.test.d.ts.map +1 -0
- package/dist/scanner/checks/dependencies.test.js +248 -0
- package/dist/scanner/checks/dependencies.test.js.map +1 -0
- package/dist/scanner/checks/finding-quality.test.d.ts +8 -0
- package/dist/scanner/checks/finding-quality.test.d.ts.map +1 -0
- package/dist/scanner/checks/finding-quality.test.js +164 -0
- package/dist/scanner/checks/finding-quality.test.js.map +1 -0
- package/dist/scanner/checks/ioc.d.ts +20 -0
- package/dist/scanner/checks/ioc.d.ts.map +1 -0
- package/dist/scanner/checks/ioc.js +234 -0
- package/dist/scanner/checks/ioc.js.map +1 -0
- package/dist/scanner/checks/ioc.test.d.ts +2 -0
- package/dist/scanner/checks/ioc.test.d.ts.map +1 -0
- package/dist/scanner/checks/ioc.test.js +298 -0
- package/dist/scanner/checks/ioc.test.js.map +1 -0
- package/dist/scanner/checks/manifest.d.ts +6 -0
- package/dist/scanner/checks/manifest.d.ts.map +1 -0
- package/dist/scanner/checks/manifest.js +123 -0
- package/dist/scanner/checks/manifest.js.map +1 -0
- package/dist/scanner/checks/manifest.test.d.ts +2 -0
- package/dist/scanner/checks/manifest.test.d.ts.map +1 -0
- package/dist/scanner/checks/manifest.test.js +108 -0
- package/dist/scanner/checks/manifest.test.js.map +1 -0
- package/dist/scanner/checks/obfuscation.d.ts +3 -0
- package/dist/scanner/checks/obfuscation.d.ts.map +1 -0
- package/dist/scanner/checks/obfuscation.js +432 -0
- package/dist/scanner/checks/obfuscation.js.map +1 -0
- package/dist/scanner/checks/obfuscation.test.d.ts +2 -0
- package/dist/scanner/checks/obfuscation.test.d.ts.map +1 -0
- package/dist/scanner/checks/obfuscation.test.js +399 -0
- package/dist/scanner/checks/obfuscation.test.js.map +1 -0
- package/dist/scanner/checks/package.d.ts +17 -0
- package/dist/scanner/checks/package.d.ts.map +1 -0
- package/dist/scanner/checks/package.js +422 -0
- package/dist/scanner/checks/package.js.map +1 -0
- package/dist/scanner/checks/package.test.d.ts +2 -0
- package/dist/scanner/checks/package.test.d.ts.map +1 -0
- package/dist/scanner/checks/package.test.js +518 -0
- package/dist/scanner/checks/package.test.js.map +1 -0
- package/dist/scanner/checks/patterns.d.ts +5 -0
- package/dist/scanner/checks/patterns.d.ts.map +1 -0
- package/dist/scanner/checks/patterns.js +251 -0
- package/dist/scanner/checks/patterns.js.map +1 -0
- package/dist/scanner/checks/patterns.test.d.ts +2 -0
- package/dist/scanner/checks/patterns.test.d.ts.map +1 -0
- package/dist/scanner/checks/patterns.test.js +147 -0
- package/dist/scanner/checks/patterns.test.js.map +1 -0
- package/dist/scanner/checks/unicode.d.ts +3 -0
- package/dist/scanner/checks/unicode.d.ts.map +1 -0
- package/dist/scanner/checks/unicode.js +247 -0
- package/dist/scanner/checks/unicode.js.map +1 -0
- package/dist/scanner/checks/unicode.test.d.ts +2 -0
- package/dist/scanner/checks/unicode.test.d.ts.map +1 -0
- package/dist/scanner/checks/unicode.test.js +202 -0
- package/dist/scanner/checks/unicode.test.js.map +1 -0
- package/dist/scanner/checks/yara.d.ts +23 -0
- package/dist/scanner/checks/yara.d.ts.map +1 -0
- package/dist/scanner/checks/yara.js +349 -0
- package/dist/scanner/checks/yara.js.map +1 -0
- package/dist/scanner/checks/yara.test.d.ts +2 -0
- package/dist/scanner/checks/yara.test.d.ts.map +1 -0
- package/dist/scanner/checks/yara.test.js +126 -0
- package/dist/scanner/checks/yara.test.js.map +1 -0
- package/dist/scanner/constants.d.ts +18 -0
- package/dist/scanner/constants.d.ts.map +1 -0
- package/dist/scanner/constants.js +37 -0
- package/dist/scanner/constants.js.map +1 -0
- package/dist/scanner/detection-coverage.test.d.ts +2 -0
- package/dist/scanner/detection-coverage.test.d.ts.map +1 -0
- package/dist/scanner/detection-coverage.test.js +216 -0
- package/dist/scanner/detection-coverage.test.js.map +1 -0
- package/dist/scanner/download.d.ts +76 -0
- package/dist/scanner/download.d.ts.map +1 -0
- package/dist/scanner/download.js +339 -0
- package/dist/scanner/download.js.map +1 -0
- package/dist/scanner/download.test.d.ts +2 -0
- package/dist/scanner/download.test.d.ts.map +1 -0
- package/dist/scanner/download.test.js +149 -0
- package/dist/scanner/download.test.js.map +1 -0
- package/dist/scanner/index.d.ts +8 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +167 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/index.test.d.ts +2 -0
- package/dist/scanner/index.test.d.ts.map +1 -0
- package/dist/scanner/index.test.js +71 -0
- package/dist/scanner/index.test.js.map +1 -0
- package/dist/scanner/loaders/zoo.d.ts +3 -0
- package/dist/scanner/loaders/zoo.d.ts.map +1 -0
- package/dist/scanner/loaders/zoo.js +112 -0
- package/dist/scanner/loaders/zoo.js.map +1 -0
- package/dist/scanner/types.d.ts +118 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +2 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/scanner/utils.d.ts +14 -0
- package/dist/scanner/utils.d.ts.map +1 -0
- package/dist/scanner/utils.js +25 -0
- package/dist/scanner/utils.js.map +1 -0
- package/dist/scanner/vsix.d.ts +6 -0
- package/dist/scanner/vsix.d.ts.map +1 -0
- package/dist/scanner/vsix.js +213 -0
- package/dist/scanner/vsix.js.map +1 -0
- package/dist/scanner/vsix.test.d.ts +2 -0
- package/dist/scanner/vsix.test.d.ts.map +1 -0
- package/dist/scanner/vsix.test.js +355 -0
- package/dist/scanner/vsix.test.js.map +1 -0
- package/package.json +60 -0
- package/zoo/blocklist/extensions.json +201 -0
- package/zoo/iocs/blockchain-extensions.txt +21 -0
- package/zoo/iocs/c2-domains.txt +50 -0
- package/zoo/iocs/c2-ips.txt +24 -0
- package/zoo/iocs/hashes.txt +47 -0
- package/zoo/iocs/malicious-npm.txt +85 -0
- package/zoo/iocs/wallets.txt +18 -0
- package/zoo/signatures/yara/README.md +46 -0
- package/zoo/signatures/yara/blockchain_c2.yar +48 -0
- package/zoo/signatures/yara/code_execution.yar +165 -0
- package/zoo/signatures/yara/credential_harvesting.yar +116 -0
- package/zoo/signatures/yara/crypto_wallet_targeting.yar +92 -0
- package/zoo/signatures/yara/data_exfiltration.yar +207 -0
- package/zoo/signatures/yara/google_calendar_c2.yar +187 -0
- package/zoo/signatures/yara/messaging_c2.yar +103 -0
- package/zoo/signatures/yara/multi_stage_attacks.yar +331 -0
- package/zoo/signatures/yara/obfuscation_patterns.yar +208 -0
- package/zoo/signatures/yara/powershell_attacks.yar +116 -0
- package/zoo/signatures/yara/rat_capabilities.yar +243 -0
- package/zoo/signatures/yara/self_propagation.yar +239 -0
- package/zoo/signatures/yara/unicode_stealth.yar +48 -0
- package/zoo/signatures/yara/websocket_c2.yar +83 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/*
|
|
2
|
+
GlassWorm Cryptocurrency Wallet Targeting Detection
|
|
3
|
+
Detects patterns for targeting cryptocurrency wallet extensions
|
|
4
|
+
|
|
5
|
+
IMPORTANT: These rules require CLEAR malicious intent indicators.
|
|
6
|
+
Many legitimate tools interact with crypto wallets.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
rule MAL_JS_GlassWorm_Wallet_Seed_Extraction_Jan25 {
|
|
10
|
+
meta:
|
|
11
|
+
description = "Detects GlassWorm-style wallet seed phrase extraction from storage combined with network exfil"
|
|
12
|
+
severity = "critical"
|
|
13
|
+
score = "95"
|
|
14
|
+
author = "vsix-audit"
|
|
15
|
+
date = "2025-01-29"
|
|
16
|
+
reference = "https://www.koi.security/blog/glassworm-first-self-propagating-worm-using-invisible-code-hits-openvsx-marketplace"
|
|
17
|
+
|
|
18
|
+
strings:
|
|
19
|
+
// Seed phrase patterns (very specific)
|
|
20
|
+
$seed1 = "seedPhrase" ascii wide
|
|
21
|
+
$seed2 = "mnemonic" ascii wide
|
|
22
|
+
$seed3 = "recoveryPhrase" ascii wide
|
|
23
|
+
|
|
24
|
+
// Private key extraction
|
|
25
|
+
$privkey = "privateKey" ascii wide
|
|
26
|
+
|
|
27
|
+
// Storage access
|
|
28
|
+
$storage1 = "localStorage.getItem" ascii wide
|
|
29
|
+
$storage2 = "chrome.storage" ascii wide
|
|
30
|
+
|
|
31
|
+
// Exfiltration - must send somewhere
|
|
32
|
+
$exfil1 = "discord.com/api/webhooks" ascii wide
|
|
33
|
+
$exfil2 = "discordapp.com/api/webhooks" ascii wide
|
|
34
|
+
$exfil3 = /fetch\s*\(\s*["'][^"']*["']\s*,\s*\{[^}]*body/ ascii wide
|
|
35
|
+
$exfil4 = "axios.post" ascii wide
|
|
36
|
+
|
|
37
|
+
condition:
|
|
38
|
+
any of ($seed*, $privkey) and any of ($storage*) and any of ($exfil*)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
rule MAL_JS_GlassWorm_Multi_Wallet_Enum_Jan25 {
|
|
42
|
+
meta:
|
|
43
|
+
description = "Detects GlassWorm-style enumeration of 3+ crypto wallet browser extension IDs for targeting"
|
|
44
|
+
severity = "high"
|
|
45
|
+
score = "85"
|
|
46
|
+
author = "vsix-audit"
|
|
47
|
+
date = "2025-01-29"
|
|
48
|
+
reference = "https://www.koi.security/blog/glassworm-first-self-propagating-worm-using-invisible-code-hits-openvsx-marketplace"
|
|
49
|
+
|
|
50
|
+
strings:
|
|
51
|
+
// MetaMask extension ID
|
|
52
|
+
$metamask_id = "nkbihfbeogaeaoehlefnkodbefgpgknn" ascii wide
|
|
53
|
+
|
|
54
|
+
// Phantom extension ID
|
|
55
|
+
$phantom_id = "bfnaelmomeimhlpmgjnjophhpkkoljpa" ascii wide
|
|
56
|
+
|
|
57
|
+
// Coinbase Wallet extension ID
|
|
58
|
+
$coinbase_id = "hnfanknocfeofbddgcijnmhnfnkdnaad" ascii wide
|
|
59
|
+
|
|
60
|
+
// Other wallet extension IDs
|
|
61
|
+
$trust_id = "egjidjbpglichdcondbcbdnbeeppgdph" ascii wide
|
|
62
|
+
$exodus_id = "aholpfdialjgjfhomihkjbmgjidlcdno" ascii wide
|
|
63
|
+
|
|
64
|
+
// Additional wallet extension IDs
|
|
65
|
+
$rabby_id = "acmacodkjbdgmoleebolmdjonilkdbch" ascii wide
|
|
66
|
+
$keplr_id = "dmkamcknogkgcdfhhbddcghachkejeap" ascii wide
|
|
67
|
+
$okx_id = "mcohilncbfahbmgdjkbpemcciiolgcge" ascii wide
|
|
68
|
+
$bitget_id = "jiidiaalihmmhddjgbnbgdfflelocpak" ascii wide
|
|
69
|
+
$rainbow_id = "opfgelmcmbiajamepnmloijbpoleiama" ascii wide
|
|
70
|
+
$zerion_id = "klghhnkeealcohjjanjjdaeeggmfmlpl" ascii wide
|
|
71
|
+
$backpack_id = "aflkmfhebedbjioipglgcbcmnbpgliof" ascii wide
|
|
72
|
+
$solflare_id = "bhhhlbepdkbapadjdnnojkbgioiodbic" ascii wide
|
|
73
|
+
|
|
74
|
+
// Must be checking for multiple
|
|
75
|
+
$check = /chrome\.runtime\.sendMessage|chrome\.management\.get/ ascii wide
|
|
76
|
+
|
|
77
|
+
condition:
|
|
78
|
+
3 of ($metamask_id, $phantom_id, $coinbase_id, $trust_id, $exodus_id,
|
|
79
|
+
$rabby_id, $keplr_id, $okx_id, $bitget_id, $rainbow_id,
|
|
80
|
+
$zerion_id, $backpack_id, $solflare_id) and $check
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// REMOVED: GlassWorm_Crypto_Wallet_Targeting
|
|
84
|
+
// Too broad - matched "metamask" + "phantom" + "address"
|
|
85
|
+
// which appears in many legitimate dApp extensions.
|
|
86
|
+
|
|
87
|
+
// REMOVED: GlassWorm_Wallet_Transaction_Interception
|
|
88
|
+
// Too broad - "transaction" + "hook" + "to/from/value" matches
|
|
89
|
+
// virtually all web3 applications.
|
|
90
|
+
|
|
91
|
+
// REMOVED: GlassWorm_Wallet_Extension_Enumeration
|
|
92
|
+
// Too broad - wallet detection is legitimate for dApps.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Data Exfiltration Detection
|
|
3
|
+
Detects patterns for stealing and transmitting sensitive data
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
rule C2_JS_Discord_Webhook_Jan25 {
|
|
7
|
+
meta:
|
|
8
|
+
description = "Detects Discord webhook URL patterns commonly used for data exfiltration and C2 communication"
|
|
9
|
+
severity = "high"
|
|
10
|
+
score = 75
|
|
11
|
+
author = "vsix-audit"
|
|
12
|
+
date = "2025-01-29"
|
|
13
|
+
|
|
14
|
+
strings:
|
|
15
|
+
$webhook1 = /discord\.com\/api\/webhooks\/\d+\/[a-zA-Z0-9_-]+/ ascii wide
|
|
16
|
+
$webhook2 = /discordapp\.com\/api\/webhooks\/\d+\/[a-zA-Z0-9_-]+/ ascii wide
|
|
17
|
+
$webhook3 = "discord.com/api/webhooks" ascii wide
|
|
18
|
+
$webhook4 = "discordapp.com/api/webhooks" ascii wide
|
|
19
|
+
|
|
20
|
+
condition:
|
|
21
|
+
any of them
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
rule C2_JS_Free_Hosting_Jan25 {
|
|
25
|
+
meta:
|
|
26
|
+
description = "Detects free hosting service domains commonly abused for C2 infrastructure and data exfiltration"
|
|
27
|
+
severity = "medium"
|
|
28
|
+
score = 60
|
|
29
|
+
author = "vsix-audit"
|
|
30
|
+
date = "2025-01-29"
|
|
31
|
+
|
|
32
|
+
strings:
|
|
33
|
+
// Vercel - commonly abused
|
|
34
|
+
$vercel = /[a-z0-9-]+\.vercel\.app/ ascii wide
|
|
35
|
+
|
|
36
|
+
// PythonAnywhere - commonly abused for exfil
|
|
37
|
+
$pythonanywhere = /[a-z0-9-]+\.pythonanywhere\.com/ ascii wide
|
|
38
|
+
|
|
39
|
+
// Netlify
|
|
40
|
+
$netlify = /[a-z0-9-]+\.netlify\.app/ ascii wide
|
|
41
|
+
|
|
42
|
+
// Glitch
|
|
43
|
+
$glitch = /[a-z0-9-]+\.glitch\.me/ ascii wide
|
|
44
|
+
|
|
45
|
+
// Replit
|
|
46
|
+
$replit = /[a-z0-9-]+\.repl\.co/ ascii wide
|
|
47
|
+
|
|
48
|
+
// Railway
|
|
49
|
+
$railway = /[a-z0-9-]+\.railway\.app/ ascii wide
|
|
50
|
+
|
|
51
|
+
// Render
|
|
52
|
+
$render = /[a-z0-9-]+\.onrender\.com/ ascii wide
|
|
53
|
+
|
|
54
|
+
// Cloudflare Pages
|
|
55
|
+
$cf_pages = /[a-z0-9-]+\.pages\.dev/ ascii wide
|
|
56
|
+
|
|
57
|
+
// Cloudflare Workers
|
|
58
|
+
$cf_workers = /[a-z0-9-]+\.workers\.dev/ ascii wide
|
|
59
|
+
|
|
60
|
+
// Firebase Hosting
|
|
61
|
+
$firebase1 = /[a-z0-9-]+\.web\.app/ ascii wide
|
|
62
|
+
$firebase2 = /[a-z0-9-]+\.firebaseapp\.com/ ascii wide
|
|
63
|
+
|
|
64
|
+
// AWS Amplify
|
|
65
|
+
$amplify = /[a-z0-9-]+\.amplifyapp\.com/ ascii wide
|
|
66
|
+
|
|
67
|
+
// Heroku
|
|
68
|
+
$heroku = /[a-z0-9-]+\.herokuapp\.com/ ascii wide
|
|
69
|
+
|
|
70
|
+
// Deno Deploy
|
|
71
|
+
$deno = /[a-z0-9-]+\.deno\.dev/ ascii wide
|
|
72
|
+
|
|
73
|
+
// Fly.io
|
|
74
|
+
$fly = /[a-z0-9-]+\.fly\.dev/ ascii wide
|
|
75
|
+
|
|
76
|
+
// Ngrok tunnels
|
|
77
|
+
$ngrok1 = /[a-z0-9-]+\.ngrok\.io/ ascii wide
|
|
78
|
+
$ngrok2 = /[a-z0-9-]+\.ngrok-free\.app/ ascii wide
|
|
79
|
+
|
|
80
|
+
condition:
|
|
81
|
+
any of them
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
rule STEALER_JS_SSH_Key_Exfil_Jan25 {
|
|
85
|
+
meta:
|
|
86
|
+
description = "Detects SSH private key file access combined with network transmission for credential theft"
|
|
87
|
+
severity = "critical"
|
|
88
|
+
score = 90
|
|
89
|
+
author = "vsix-audit"
|
|
90
|
+
date = "2025-01-29"
|
|
91
|
+
|
|
92
|
+
strings:
|
|
93
|
+
// SSH key paths
|
|
94
|
+
$ssh1 = ".ssh/id_rsa" ascii wide
|
|
95
|
+
$ssh2 = ".ssh/id_ed25519" ascii wide
|
|
96
|
+
$ssh3 = ".ssh/id_ecdsa" ascii wide
|
|
97
|
+
$ssh4 = ".ssh/id_dsa" ascii wide
|
|
98
|
+
|
|
99
|
+
// File reading
|
|
100
|
+
$read1 = "readFileSync" ascii wide
|
|
101
|
+
$read2 = "readFile" ascii wide
|
|
102
|
+
$read3 = "createReadStream" ascii wide
|
|
103
|
+
|
|
104
|
+
// Network transmission
|
|
105
|
+
$net1 = "fetch(" ascii wide
|
|
106
|
+
$net2 = "axios" ascii wide
|
|
107
|
+
$net3 = "request(" ascii wide
|
|
108
|
+
$net4 = "https.request" ascii wide
|
|
109
|
+
$net5 = "http.request" ascii wide
|
|
110
|
+
$net6 = ".post(" ascii wide
|
|
111
|
+
$net7 = ".put(" ascii wide
|
|
112
|
+
|
|
113
|
+
condition:
|
|
114
|
+
any of ($ssh*) and any of ($read*) and any of ($net*)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
rule STEALER_JS_Credential_File_Exfil_Jan25 {
|
|
118
|
+
meta:
|
|
119
|
+
description = "Detects credential file access (.npmrc, .env, .aws/credentials) combined with network exfiltration"
|
|
120
|
+
severity = "critical"
|
|
121
|
+
score = 90
|
|
122
|
+
author = "vsix-audit"
|
|
123
|
+
date = "2025-01-29"
|
|
124
|
+
|
|
125
|
+
strings:
|
|
126
|
+
// Credential files
|
|
127
|
+
$cred1 = ".npmrc" ascii wide
|
|
128
|
+
$cred2 = ".netrc" ascii wide
|
|
129
|
+
$cred3 = ".git-credentials" ascii wide
|
|
130
|
+
$cred4 = ".env" ascii wide
|
|
131
|
+
$cred5 = "credentials.json" ascii wide
|
|
132
|
+
$cred6 = ".aws/credentials" ascii wide
|
|
133
|
+
|
|
134
|
+
// File reading
|
|
135
|
+
$read1 = "readFileSync" ascii wide
|
|
136
|
+
$read2 = "readFile" ascii wide
|
|
137
|
+
|
|
138
|
+
// Network transmission
|
|
139
|
+
$net1 = "fetch(" ascii wide
|
|
140
|
+
$net2 = "axios" ascii wide
|
|
141
|
+
$net3 = ".post(" ascii wide
|
|
142
|
+
$net4 = "discord.com/api/webhooks" ascii wide
|
|
143
|
+
|
|
144
|
+
condition:
|
|
145
|
+
any of ($cred*) and any of ($read*) and any of ($net*)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
rule STEALER_JS_Browser_Data_Theft_Jan25 {
|
|
149
|
+
meta:
|
|
150
|
+
description = "Detects browser credential and cookie theft pattern targeting Chrome/Firefox/Edge storage files"
|
|
151
|
+
severity = "critical"
|
|
152
|
+
score = 95
|
|
153
|
+
author = "vsix-audit"
|
|
154
|
+
date = "2025-01-29"
|
|
155
|
+
|
|
156
|
+
strings:
|
|
157
|
+
// Browser data paths
|
|
158
|
+
$chrome1 = "Chrome" ascii wide nocase
|
|
159
|
+
$chrome2 = "User Data" ascii wide nocase
|
|
160
|
+
$chrome3 = "Login Data" ascii wide nocase
|
|
161
|
+
$chrome4 = "Cookies" ascii wide nocase
|
|
162
|
+
$firefox1 = "Firefox" ascii wide nocase
|
|
163
|
+
$firefox2 = "logins.json" ascii wide nocase
|
|
164
|
+
$edge1 = "Edge" ascii wide nocase
|
|
165
|
+
$brave1 = "BraveSoftware" ascii wide nocase
|
|
166
|
+
|
|
167
|
+
// Storage paths
|
|
168
|
+
$storage1 = "Local Storage" ascii wide nocase
|
|
169
|
+
$storage2 = "leveldb" ascii wide nocase
|
|
170
|
+
$storage3 = "IndexedDB" ascii wide nocase
|
|
171
|
+
|
|
172
|
+
// File operations
|
|
173
|
+
$read1 = "readFileSync" ascii wide
|
|
174
|
+
$read2 = "copyFileSync" ascii wide
|
|
175
|
+
$read3 = "createReadStream" ascii wide
|
|
176
|
+
|
|
177
|
+
condition:
|
|
178
|
+
(2 of ($chrome*) or any of ($firefox*) or ($edge1 and $chrome3) or $brave1) and
|
|
179
|
+
any of ($storage*) and any of ($read*)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
rule STEALER_JS_Env_Token_Exfil_Jan25 {
|
|
183
|
+
meta:
|
|
184
|
+
description = "Detects API token access from process.env variables combined with network transmission"
|
|
185
|
+
severity = "high"
|
|
186
|
+
score = 80
|
|
187
|
+
author = "vsix-audit"
|
|
188
|
+
date = "2025-01-29"
|
|
189
|
+
|
|
190
|
+
strings:
|
|
191
|
+
// Token environment variables
|
|
192
|
+
$env1 = "process.env.GITHUB_TOKEN" ascii wide
|
|
193
|
+
$env2 = "process.env.NPM_TOKEN" ascii wide
|
|
194
|
+
$env3 = "process.env.OPENAI_API_KEY" ascii wide
|
|
195
|
+
$env4 = "process.env.ANTHROPIC_API_KEY" ascii wide
|
|
196
|
+
$env5 = "process.env.AWS_SECRET" ascii wide
|
|
197
|
+
$env6 = "process.env.AZURE" ascii wide
|
|
198
|
+
$env7 = /process\.env\.[A-Z_]*(TOKEN|KEY|SECRET|PASSWORD)/ ascii wide
|
|
199
|
+
|
|
200
|
+
// Network transmission
|
|
201
|
+
$net1 = "fetch(" ascii wide
|
|
202
|
+
$net2 = "axios" ascii wide
|
|
203
|
+
$net3 = ".post(" ascii wide
|
|
204
|
+
|
|
205
|
+
condition:
|
|
206
|
+
any of ($env*) and any of ($net*)
|
|
207
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/*
|
|
2
|
+
GlassWorm Google Calendar C2 Detection
|
|
3
|
+
Detects Google Calendar API usage for command and control fallback
|
|
4
|
+
Based on GlassWorm using Google Calendar as backup C2 channel
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
rule C2_JS_GlassWorm_Google_Calendar_Jan25 {
|
|
8
|
+
meta:
|
|
9
|
+
description = "Detects GlassWorm-style Google Calendar API usage for command and control fallback channel"
|
|
10
|
+
severity = "high"
|
|
11
|
+
score = "80"
|
|
12
|
+
author = "vsix-audit"
|
|
13
|
+
date = "2025-01-29"
|
|
14
|
+
reference = "https://www.koi.security/blog/glassworm-first-self-propagating-worm-using-invisible-code-hits-openvsx-marketplace"
|
|
15
|
+
|
|
16
|
+
strings:
|
|
17
|
+
// Google Calendar API
|
|
18
|
+
$google_calendar = "google-calendar" ascii wide
|
|
19
|
+
$calendar_api = "calendarApi" ascii wide
|
|
20
|
+
$gcal_api = "gcalApi" ascii wide
|
|
21
|
+
$calendar_google = "calendar.google" ascii wide
|
|
22
|
+
|
|
23
|
+
// Calendar API endpoints
|
|
24
|
+
$calendar_app = "calendar.app.google" ascii wide
|
|
25
|
+
$googleapis_calendar = "googleapis.com/calendar" ascii wide
|
|
26
|
+
$calendar_v3 = "calendar/v3" ascii wide
|
|
27
|
+
$calendar_events = "calendar/events" ascii wide
|
|
28
|
+
|
|
29
|
+
// Calendar authentication
|
|
30
|
+
$calendar_auth = "calendarAuth" ascii wide
|
|
31
|
+
$gcal_auth = "gcalAuth" ascii wide
|
|
32
|
+
$calendar_token = "calendarToken" ascii wide
|
|
33
|
+
$calendar_oauth = "calendarOAuth" ascii wide
|
|
34
|
+
|
|
35
|
+
// Calendar event access
|
|
36
|
+
$calendar_events_list = "calendarEvents" ascii wide
|
|
37
|
+
$event_list = "eventList" ascii wide
|
|
38
|
+
$get_events = "getEvents" ascii wide
|
|
39
|
+
$list_events = "listEvents" ascii wide
|
|
40
|
+
|
|
41
|
+
// Event parsing
|
|
42
|
+
$parse_events = "parseEvents" ascii wide
|
|
43
|
+
$event_parser = "eventParser" ascii wide
|
|
44
|
+
$calendar_parser = "calendarParser" ascii wide
|
|
45
|
+
$event_data = "eventData" ascii wide
|
|
46
|
+
|
|
47
|
+
condition:
|
|
48
|
+
// High confidence: Google Calendar API + event access + parsing
|
|
49
|
+
(any of ($google_calendar, $calendar_api, $gcal_api, $calendar_google, $calendar_app, $googleapis_calendar, $calendar_v3, $calendar_events)) and
|
|
50
|
+
(any of ($calendar_auth, $gcal_auth, $calendar_token, $calendar_oauth)) and
|
|
51
|
+
(any of ($calendar_events_list, $event_list, $get_events, $list_events, $parse_events, $event_parser, $calendar_parser, $event_data))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
rule C2_JS_GlassWorm_Calendar_Commands_Jan25 {
|
|
55
|
+
meta:
|
|
56
|
+
description = "Detects GlassWorm-style calendar event parsing used to receive and execute C2 commands"
|
|
57
|
+
severity = "high"
|
|
58
|
+
score = "85"
|
|
59
|
+
author = "vsix-audit"
|
|
60
|
+
date = "2025-01-29"
|
|
61
|
+
reference = "https://www.koi.security/blog/glassworm-first-self-propagating-worm-using-invisible-code-hits-openvsx-marketplace"
|
|
62
|
+
|
|
63
|
+
strings:
|
|
64
|
+
// Event command parsing
|
|
65
|
+
$event_commands = "eventCommands" ascii wide
|
|
66
|
+
$calendar_commands = "calendarCommands" ascii wide
|
|
67
|
+
$parse_commands = "parseCommands" ascii wide
|
|
68
|
+
$command_parser = "commandParser" ascii wide
|
|
69
|
+
|
|
70
|
+
// Event data extraction
|
|
71
|
+
$event_summary = "eventSummary" ascii wide
|
|
72
|
+
$event_description = "eventDescription" ascii wide
|
|
73
|
+
$event_title = "eventTitle" ascii wide
|
|
74
|
+
$event_content = "eventContent" ascii wide
|
|
75
|
+
|
|
76
|
+
// Command execution from events
|
|
77
|
+
$execute_command = "executeCommand" ascii wide
|
|
78
|
+
$run_command = "runCommand" ascii wide
|
|
79
|
+
$command_exec = "commandExec" ascii wide
|
|
80
|
+
$exec_from_event = "execFromEvent" ascii wide
|
|
81
|
+
|
|
82
|
+
// Event monitoring
|
|
83
|
+
$monitor_events = "monitorEvents" ascii wide
|
|
84
|
+
$watch_events = "watchEvents" ascii wide
|
|
85
|
+
$event_watcher = "eventWatcher" ascii wide
|
|
86
|
+
$calendar_monitor = "calendarMonitor" ascii wide
|
|
87
|
+
|
|
88
|
+
// Event filtering
|
|
89
|
+
$filter_events = "filterEvents" ascii wide
|
|
90
|
+
$event_filter = "eventFilter" ascii wide
|
|
91
|
+
$command_filter = "commandFilter" ascii wide
|
|
92
|
+
$c2_filter = "c2Filter" ascii wide
|
|
93
|
+
|
|
94
|
+
condition:
|
|
95
|
+
// Detect event command parsing with execution capabilities
|
|
96
|
+
(any of ($event_commands, $calendar_commands, $parse_commands, $command_parser)) and
|
|
97
|
+
(any of ($event_summary, $event_description, $event_title, $event_content)) and
|
|
98
|
+
(any of ($execute_command, $run_command, $command_exec, $exec_from_event, $monitor_events, $watch_events, $event_watcher, $calendar_monitor, $filter_events, $event_filter, $command_filter, $c2_filter))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
rule C2_JS_GlassWorm_Calendar_Backup_Jan25 {
|
|
102
|
+
meta:
|
|
103
|
+
description = "Detects GlassWorm-style calendar-based backup C2 mechanism with redundancy and failover patterns"
|
|
104
|
+
severity = "medium"
|
|
105
|
+
score = "70"
|
|
106
|
+
author = "vsix-audit"
|
|
107
|
+
date = "2025-01-29"
|
|
108
|
+
reference = "https://www.koi.security/blog/glassworm-first-self-propagating-worm-using-invisible-code-hits-openvsx-marketplace"
|
|
109
|
+
|
|
110
|
+
strings:
|
|
111
|
+
// Backup C2 patterns
|
|
112
|
+
$backup_c2 = "backupC2" ascii wide
|
|
113
|
+
$fallback_c2 = "fallbackC2" ascii wide
|
|
114
|
+
$secondary_c2 = "secondaryC2" ascii wide
|
|
115
|
+
$alternate_c2 = "alternateC2" ascii wide
|
|
116
|
+
|
|
117
|
+
// C2 redundancy
|
|
118
|
+
$c2_redundancy = "c2Redundancy" ascii wide
|
|
119
|
+
$c2_backup = "c2Backup" ascii wide
|
|
120
|
+
$c2_failover = "c2Failover" ascii wide
|
|
121
|
+
$c2_resilience = "c2Resilience" ascii wide
|
|
122
|
+
|
|
123
|
+
// Calendar C2
|
|
124
|
+
$calendar_c2 = "calendarC2" ascii wide
|
|
125
|
+
$gcal_c2 = "gcalC2" ascii wide
|
|
126
|
+
$calendar_channel = "calendarChannel" ascii wide
|
|
127
|
+
$event_c2 = "eventC2" ascii wide
|
|
128
|
+
|
|
129
|
+
// C2 rotation
|
|
130
|
+
$c2_rotation = "c2Rotation" ascii wide
|
|
131
|
+
$c2_switch = "c2Switch" ascii wide
|
|
132
|
+
$c2_alternate = "c2Alternate" ascii wide
|
|
133
|
+
$c2_cycle = "c2Cycle" ascii wide
|
|
134
|
+
|
|
135
|
+
// C2 resilience
|
|
136
|
+
$c2_persistence = "c2Persistence" ascii wide
|
|
137
|
+
$c2_survival = "c2Survival" ascii wide
|
|
138
|
+
$c2_durability = "c2Durability" ascii wide
|
|
139
|
+
$c2_reliability = "c2Reliability" ascii wide
|
|
140
|
+
|
|
141
|
+
condition:
|
|
142
|
+
// Detect backup C2 with calendar integration
|
|
143
|
+
(any of ($backup_c2, $fallback_c2, $secondary_c2, $alternate_c2, $c2_redundancy, $c2_backup, $c2_failover, $c2_resilience)) and
|
|
144
|
+
(any of ($calendar_c2, $gcal_c2, $calendar_channel, $event_c2)) and
|
|
145
|
+
(any of ($c2_rotation, $c2_switch, $c2_alternate, $c2_cycle, $c2_persistence, $c2_survival, $c2_durability, $c2_reliability))
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
rule C2_JS_GlassWorm_Calendar_Exfil_Jan25 {
|
|
149
|
+
meta:
|
|
150
|
+
description = "Detects GlassWorm-style data exfiltration using calendar events with encoded payloads"
|
|
151
|
+
severity = "medium"
|
|
152
|
+
score = "75"
|
|
153
|
+
author = "vsix-audit"
|
|
154
|
+
date = "2025-01-29"
|
|
155
|
+
reference = "https://www.koi.security/blog/glassworm-first-self-propagating-worm-using-invisible-code-hits-openvsx-marketplace"
|
|
156
|
+
|
|
157
|
+
strings:
|
|
158
|
+
// Event exfiltration
|
|
159
|
+
$event_exfil = "eventExfil" ascii wide
|
|
160
|
+
$calendar_exfil = "calendarExfil" ascii wide
|
|
161
|
+
$event_data_exfil = "eventDataExfil" ascii wide
|
|
162
|
+
$calendar_data_exfil = "calendarDataExfil" ascii wide
|
|
163
|
+
|
|
164
|
+
// Event creation for exfiltration
|
|
165
|
+
$create_event = "createEvent" ascii wide
|
|
166
|
+
$add_event = "addEvent" ascii wide
|
|
167
|
+
$insert_event = "insertEvent" ascii wide
|
|
168
|
+
$post_event = "postEvent" ascii wide
|
|
169
|
+
|
|
170
|
+
// Data encoding in events
|
|
171
|
+
$encode_in_event = "encodeInEvent" ascii wide
|
|
172
|
+
$event_encoding = "eventEncoding" ascii wide
|
|
173
|
+
$calendar_encoding = "calendarEncoding" ascii wide
|
|
174
|
+
$event_base64 = "eventBase64" ascii wide
|
|
175
|
+
|
|
176
|
+
// Event data patterns
|
|
177
|
+
$event_payload = "eventPayload" ascii wide
|
|
178
|
+
$event_data = "eventData" ascii wide
|
|
179
|
+
$calendar_payload = "calendarPayload" ascii wide
|
|
180
|
+
$event_content = "eventContent" ascii wide
|
|
181
|
+
|
|
182
|
+
condition:
|
|
183
|
+
// Detect event-based exfiltration with data encoding
|
|
184
|
+
(any of ($event_exfil, $calendar_exfil, $event_data_exfil, $calendar_data_exfil)) and
|
|
185
|
+
(any of ($create_event, $add_event, $insert_event, $post_event)) and
|
|
186
|
+
(any of ($encode_in_event, $event_encoding, $calendar_encoding, $event_base64, $event_payload, $event_data, $calendar_payload, $event_content))
|
|
187
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Messaging Platform C2 Detection
|
|
3
|
+
Detects use of messaging platforms (Telegram, Slack) for C2 and exfiltration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
rule C2_JS_Telegram_Bot_Jan25 {
|
|
7
|
+
meta:
|
|
8
|
+
description = "Detects Telegram bot API used for C2 communication with command execution or system info gathering"
|
|
9
|
+
severity = "high"
|
|
10
|
+
score = 85
|
|
11
|
+
author = "vsix-audit"
|
|
12
|
+
date = "2025-01-30"
|
|
13
|
+
|
|
14
|
+
strings:
|
|
15
|
+
// Telegram API
|
|
16
|
+
$tg1 = "api.telegram.org" ascii wide
|
|
17
|
+
$tg2 = "/bot" ascii wide
|
|
18
|
+
$tg3 = "telegram" ascii wide nocase
|
|
19
|
+
|
|
20
|
+
// Bot methods
|
|
21
|
+
$method1 = "sendMessage" ascii wide
|
|
22
|
+
$method2 = "getUpdates" ascii wide
|
|
23
|
+
$method3 = "sendDocument" ascii wide
|
|
24
|
+
$method4 = "sendPhoto" ascii wide
|
|
25
|
+
|
|
26
|
+
// Command execution or system info (C2 indicators)
|
|
27
|
+
$exec1 = "child_process" ascii wide
|
|
28
|
+
$exec2 = ".exec(" ascii wide
|
|
29
|
+
$exec3 = ".spawn(" ascii wide
|
|
30
|
+
$exec4 = "execSync" ascii wide
|
|
31
|
+
$sys1 = "os.hostname" ascii wide
|
|
32
|
+
$sys2 = "os.userInfo" ascii wide
|
|
33
|
+
$sys3 = "os.platform" ascii wide
|
|
34
|
+
$sys4 = "process.env" ascii wide
|
|
35
|
+
|
|
36
|
+
condition:
|
|
37
|
+
any of ($tg*) and any of ($method*) and any of ($exec*, $sys*)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
rule STEALER_JS_Telegram_Exfil_Jan25 {
|
|
41
|
+
meta:
|
|
42
|
+
description = "Detects Telegram API used for file exfiltration targeting sensitive credential paths like .ssh"
|
|
43
|
+
severity = "high"
|
|
44
|
+
score = 80
|
|
45
|
+
author = "vsix-audit"
|
|
46
|
+
date = "2025-01-30"
|
|
47
|
+
|
|
48
|
+
strings:
|
|
49
|
+
// Telegram API
|
|
50
|
+
$tg1 = "api.telegram.org" ascii wide
|
|
51
|
+
$tg2 = "/bot" ascii wide
|
|
52
|
+
|
|
53
|
+
// Document sending
|
|
54
|
+
$send1 = "sendDocument" ascii wide
|
|
55
|
+
$send2 = "sendFile" ascii wide
|
|
56
|
+
$send3 = "multipart/form-data" ascii wide
|
|
57
|
+
|
|
58
|
+
// File reading
|
|
59
|
+
$read1 = "readFileSync" ascii wide
|
|
60
|
+
$read2 = "readFile" ascii wide
|
|
61
|
+
$read3 = "createReadStream" ascii wide
|
|
62
|
+
|
|
63
|
+
// Sensitive paths
|
|
64
|
+
$path1 = ".ssh" ascii wide
|
|
65
|
+
$path2 = ".npmrc" ascii wide
|
|
66
|
+
$path3 = ".env" ascii wide
|
|
67
|
+
$path4 = "credentials" ascii wide
|
|
68
|
+
$path5 = ".aws" ascii wide
|
|
69
|
+
$path6 = ".git-credentials" ascii wide
|
|
70
|
+
|
|
71
|
+
condition:
|
|
72
|
+
any of ($tg*) and any of ($send*) and any of ($read*) and any of ($path*)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
rule C2_JS_Slack_Webhook_Jan25 {
|
|
76
|
+
meta:
|
|
77
|
+
description = "Detects Slack webhook URL used for data exfiltration with system info or file access patterns"
|
|
78
|
+
severity = "high"
|
|
79
|
+
score = 75
|
|
80
|
+
author = "vsix-audit"
|
|
81
|
+
date = "2025-01-30"
|
|
82
|
+
|
|
83
|
+
strings:
|
|
84
|
+
// Slack webhook URL pattern
|
|
85
|
+
$slack1 = "hooks.slack.com/services" ascii wide
|
|
86
|
+
$slack2 = "hooks.slack.com" ascii wide
|
|
87
|
+
$slack3 = /T[A-Z0-9]{8,}\/B[A-Z0-9]{8,}\/[a-zA-Z0-9]{20,}/ ascii wide
|
|
88
|
+
|
|
89
|
+
// Data transmission
|
|
90
|
+
$send1 = "fetch(" ascii wide
|
|
91
|
+
$send2 = "axios" ascii wide
|
|
92
|
+
$send3 = ".post(" ascii wide
|
|
93
|
+
$send4 = "request(" ascii wide
|
|
94
|
+
|
|
95
|
+
// Data collection indicators
|
|
96
|
+
$data1 = "JSON.stringify" ascii wide
|
|
97
|
+
$data2 = "process.env" ascii wide
|
|
98
|
+
$data3 = "os.hostname" ascii wide
|
|
99
|
+
$data4 = "readFileSync" ascii wide
|
|
100
|
+
|
|
101
|
+
condition:
|
|
102
|
+
any of ($slack*) and any of ($send*) and any of ($data*)
|
|
103
|
+
}
|