cybersentinel-cli 1.0.2 → 1.0.4
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/bin/index.js +197 -2
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -72,7 +72,21 @@ $ s*" .u@*"" '""\\dP"
|
|
|
72
72
|
""""* RL d>
|
|
73
73
|
"$u. .$
|
|
74
74
|
^"*bo@" tony
|
|
75
|
-
`) + "\n" +
|
|
75
|
+
`) + "\n" +
|
|
76
|
+
chalk.green.bold('================================================================================\n') +
|
|
77
|
+
chalk.green.bold(' CYBERSENTINEL - Audit Platform CLI\n') +
|
|
78
|
+
chalk.green.bold('================================================================================\n') +
|
|
79
|
+
chalk.green('INTRODUCTION & PURPOSE:\n') +
|
|
80
|
+
chalk.white(' CyberSentinel CLI is a secure, interactive terminal-based auditing gateway\n') +
|
|
81
|
+
chalk.white(' designed for white-hat penetration testers and compliance officers. It executes\n') +
|
|
82
|
+
chalk.white(' automated vulnerability assessments, facilitates manual control checkpoints, and\n') +
|
|
83
|
+
chalk.white(' synchronizes verified ratings and uploads directly to the management database.\n\n') +
|
|
84
|
+
chalk.green('CREATOR & LEAD DEVELOPER:\n') +
|
|
85
|
+
chalk.white(' Engr. Brian Perez\n\n') +
|
|
86
|
+
chalk.green('PROPRIETARY LICENSE & COPYRIGHT:\n') +
|
|
87
|
+
chalk.white(' This software package and its distribution binaries are exclusively owned by\n') +
|
|
88
|
+
chalk.white(' the Inspire Alliance Fund Group Incorporated. All rights reserved.\n') +
|
|
89
|
+
chalk.green.bold('================================================================================\n');
|
|
76
90
|
|
|
77
91
|
const SNAKE_SPINNER = {
|
|
78
92
|
interval: 100,
|
|
@@ -122,6 +136,36 @@ function getMtlsClient(config) {
|
|
|
122
136
|
});
|
|
123
137
|
}
|
|
124
138
|
|
|
139
|
+
// Wait for user to decide to quit by pressing Ctrl + C or /exit command
|
|
140
|
+
async function waitToExit() {
|
|
141
|
+
console.log(chalk.gray('\n=================================================='));
|
|
142
|
+
console.log(chalk.green('Task execution complete. Session remains active.'));
|
|
143
|
+
console.log(chalk.green('Type "/exit" or press Ctrl+C to close the connection and exit.'));
|
|
144
|
+
console.log(chalk.gray('==================================================\n'));
|
|
145
|
+
|
|
146
|
+
const readline = require('readline');
|
|
147
|
+
const rl = readline.createInterface({
|
|
148
|
+
input: process.stdin,
|
|
149
|
+
output: process.stdout
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return new Promise((resolve) => {
|
|
153
|
+
const ask = () => {
|
|
154
|
+
rl.question(chalk.green('cybersentinel> '), (answer) => {
|
|
155
|
+
if (answer.trim() === '/exit') {
|
|
156
|
+
console.log(chalk.yellow('Closing session...'));
|
|
157
|
+
rl.close();
|
|
158
|
+
process.exit(0);
|
|
159
|
+
} else {
|
|
160
|
+
console.log(chalk.gray(`Unknown command "${answer.trim()}". Type "/exit" to quit.`));
|
|
161
|
+
ask();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
ask();
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
125
169
|
// Print startup banner
|
|
126
170
|
console.log(VIPER_BANNER);
|
|
127
171
|
|
|
@@ -253,6 +297,7 @@ program
|
|
|
253
297
|
console.log(chalk.green(`Files saved to: ${CONFIG_DIR}`));
|
|
254
298
|
console.log(chalk.green(`PKCS12 Container: client.p12 (encrypted)\n`));
|
|
255
299
|
|
|
300
|
+
await waitToExit();
|
|
256
301
|
} catch (error) {
|
|
257
302
|
spinner.fail(chalk.red('Registration failed!'));
|
|
258
303
|
if (error.response) {
|
|
@@ -270,6 +315,7 @@ program
|
|
|
270
315
|
} else {
|
|
271
316
|
console.error(chalk.red(`Error: ${error.message}`));
|
|
272
317
|
}
|
|
318
|
+
await waitToExit();
|
|
273
319
|
}
|
|
274
320
|
});
|
|
275
321
|
|
|
@@ -277,7 +323,7 @@ program
|
|
|
277
323
|
program
|
|
278
324
|
.command('init')
|
|
279
325
|
.description('Verify credential certificate files status')
|
|
280
|
-
.action(() => {
|
|
326
|
+
.action(async () => {
|
|
281
327
|
if (hasCertificates()) {
|
|
282
328
|
try {
|
|
283
329
|
const config = loadConfig();
|
|
@@ -292,6 +338,7 @@ program
|
|
|
292
338
|
console.log(chalk.yellow('⚠ No active client certificate found. Please run:'));
|
|
293
339
|
console.log(chalk.cyan(' cybersentinel register'));
|
|
294
340
|
}
|
|
341
|
+
await waitToExit();
|
|
295
342
|
});
|
|
296
343
|
|
|
297
344
|
// Command: audit
|
|
@@ -303,6 +350,7 @@ program
|
|
|
303
350
|
.action(async (options) => {
|
|
304
351
|
if (!hasCertificates()) {
|
|
305
352
|
console.error(chalk.red('Error: Local certificate files not found. Run "cybersentinel register" first.'));
|
|
353
|
+
await waitToExit();
|
|
306
354
|
process.exit(1);
|
|
307
355
|
}
|
|
308
356
|
|
|
@@ -311,6 +359,7 @@ program
|
|
|
311
359
|
config = loadConfig();
|
|
312
360
|
} catch (err) {
|
|
313
361
|
console.error(chalk.red(err.message));
|
|
362
|
+
await waitToExit();
|
|
314
363
|
process.exit(1);
|
|
315
364
|
}
|
|
316
365
|
|
|
@@ -335,6 +384,7 @@ program
|
|
|
335
384
|
} else {
|
|
336
385
|
console.error(chalk.red(`Connection error: ${err.message}`));
|
|
337
386
|
}
|
|
387
|
+
await waitToExit();
|
|
338
388
|
process.exit(1);
|
|
339
389
|
}
|
|
340
390
|
|
|
@@ -483,6 +533,29 @@ program
|
|
|
483
533
|
console.log(chalk.gray(`Current: Rating: ${currentVal.rating} | Notes: ${currentVal.notes}`));
|
|
484
534
|
}
|
|
485
535
|
|
|
536
|
+
const actionPrompt = await inquirer.prompt([
|
|
537
|
+
{
|
|
538
|
+
type: 'list',
|
|
539
|
+
name: 'action',
|
|
540
|
+
message: 'Choose action for this checkpoint:',
|
|
541
|
+
choices: [
|
|
542
|
+
{ name: 'Audit / Rate this item', value: 'audit' },
|
|
543
|
+
{ name: 'Skip this item', value: 'skip' },
|
|
544
|
+
{ name: chalk.yellow('Exit & Save Session'), value: 'exit' }
|
|
545
|
+
]
|
|
546
|
+
}
|
|
547
|
+
]);
|
|
548
|
+
|
|
549
|
+
if (actionPrompt.action === 'exit') {
|
|
550
|
+
console.log(chalk.yellow('\n✔ Session progress saved. Exiting audit session. Goodbye!'));
|
|
551
|
+
process.exit(0);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (actionPrompt.action === 'skip') {
|
|
555
|
+
console.log(chalk.gray(`Skipping item ${item.id}.`));
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
|
|
486
559
|
const itemAnswers = await inquirer.prompt([
|
|
487
560
|
{
|
|
488
561
|
type: 'list',
|
|
@@ -564,6 +637,128 @@ program
|
|
|
564
637
|
}
|
|
565
638
|
|
|
566
639
|
console.log(chalk.green.bold(`\n✔ Completed Category ${selectedCategory.id} Audit!\n`));
|
|
640
|
+
await waitToExit();
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
function startProxyServer(port, targetFilter) {
|
|
644
|
+
const http = require('http');
|
|
645
|
+
const net = require('net');
|
|
646
|
+
const url = require('url');
|
|
647
|
+
|
|
648
|
+
const server = http.createServer((req, res) => {
|
|
649
|
+
try {
|
|
650
|
+
const parsedUrl = url.parse(req.url);
|
|
651
|
+
const host = req.headers.host || '';
|
|
652
|
+
|
|
653
|
+
const shouldLog = !targetFilter || host.includes(targetFilter);
|
|
654
|
+
if (shouldLog) {
|
|
655
|
+
console.log(chalk.green(`[HTTP Request] ${req.method} ${req.url}`));
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const options = {
|
|
659
|
+
hostname: parsedUrl.hostname || host.split(':')[0],
|
|
660
|
+
port: parsedUrl.port || 80,
|
|
661
|
+
path: parsedUrl.path,
|
|
662
|
+
method: req.method,
|
|
663
|
+
headers: req.headers
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
const proxyReq = http.request(options, (proxyRes) => {
|
|
667
|
+
if (shouldLog) {
|
|
668
|
+
console.log(chalk.cyan(`[HTTP Response] ${req.method} ${req.url} -> Status: ${proxyRes.statusCode}`));
|
|
669
|
+
}
|
|
670
|
+
res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
|
671
|
+
proxyRes.pipe(res);
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
proxyReq.on('error', (err) => {
|
|
675
|
+
if (shouldLog) {
|
|
676
|
+
console.error(chalk.red(`[HTTP Error] ${req.method} ${req.url} -> Error: ${err.message}`));
|
|
677
|
+
}
|
|
678
|
+
res.writeHead(502);
|
|
679
|
+
res.end(`Proxy Gateway Error: ${err.message}`);
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
req.pipe(proxyReq);
|
|
683
|
+
} catch (err) {
|
|
684
|
+
console.error(chalk.red(`Proxy Request Handler Error: ${err.message}`));
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
server.on('connect', (req, clientSocket, head) => {
|
|
689
|
+
try {
|
|
690
|
+
const parts = req.url.split(':');
|
|
691
|
+
const targetHost = parts[0];
|
|
692
|
+
const targetPort = parseInt(parts[1] || '443', 10);
|
|
693
|
+
|
|
694
|
+
const shouldLog = !targetFilter || targetHost.includes(targetFilter);
|
|
695
|
+
if (shouldLog) {
|
|
696
|
+
console.log(chalk.yellow(`[HTTPS CONNECT Tunnel] ${targetHost}:${targetPort}`));
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
const serverSocket = net.connect(targetPort, targetHost, () => {
|
|
700
|
+
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
|
|
701
|
+
serverSocket.write(head);
|
|
702
|
+
serverSocket.pipe(clientSocket);
|
|
703
|
+
clientSocket.pipe(serverSocket);
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
serverSocket.on('error', (err) => {
|
|
707
|
+
if (shouldLog) {
|
|
708
|
+
console.error(chalk.red(`[HTTPS Tunnel Error] Tunnel to ${targetHost}:${targetPort} failed: ${err.message}`));
|
|
709
|
+
}
|
|
710
|
+
clientSocket.end('HTTP/1.1 502 Bad Gateway\r\n\r\n');
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
clientSocket.on('error', () => {
|
|
714
|
+
serverSocket.end();
|
|
715
|
+
});
|
|
716
|
+
} catch (err) {
|
|
717
|
+
console.error(chalk.red(`Proxy CONNECT Handler Error: ${err.message}`));
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
server.listen(port, () => {
|
|
722
|
+
console.log(chalk.green.bold(`\n⚡ CyberSentinel Interception Proxy Active!`));
|
|
723
|
+
console.log(chalk.green(`Listening on local port: ${port}`));
|
|
724
|
+
if (targetFilter) {
|
|
725
|
+
console.log(chalk.green(`Filtering target host: ${targetFilter}`));
|
|
726
|
+
}
|
|
727
|
+
console.log(chalk.gray(`Configure your browser (e.g. Chrome) to use HTTP/HTTPS proxy 127.0.0.1:${port}`));
|
|
728
|
+
console.log(chalk.gray(`Type "/exit" or press Ctrl+C to stop the proxy server.\n`));
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
const readline = require('readline');
|
|
732
|
+
const rl = readline.createInterface({
|
|
733
|
+
input: process.stdin,
|
|
734
|
+
output: process.stdout
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
const ask = () => {
|
|
738
|
+
rl.question('', (answer) => {
|
|
739
|
+
if (answer.trim() === '/exit') {
|
|
740
|
+
console.log(chalk.yellow('Stopping proxy server and closing session...'));
|
|
741
|
+
server.close();
|
|
742
|
+
rl.close();
|
|
743
|
+
process.exit(0);
|
|
744
|
+
} else {
|
|
745
|
+
ask();
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
};
|
|
749
|
+
ask();
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// Command: proxy
|
|
753
|
+
program
|
|
754
|
+
.command('proxy')
|
|
755
|
+
.description('Start a local interception proxy server (like Burp Suite CLI)')
|
|
756
|
+
.option('-p, --port <port>', 'Port to listen on', '8088')
|
|
757
|
+
.option('-t, --target <host>', 'Filter logs by target host domain')
|
|
758
|
+
.action((options) => {
|
|
759
|
+
const port = parseInt(options.port, 10);
|
|
760
|
+
startProxyServer(port, options.target);
|
|
567
761
|
});
|
|
568
762
|
|
|
569
763
|
program.parse(process.argv);
|
|
764
|
+
|