icarus-cmd 0.3.1

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.
@@ -0,0 +1,141 @@
1
+ // Serveur web local d'Icarus : sert l'UI, expose une API REST et streame la
2
+ // sortie des scans en direct (NDJSON sur la réponse POST). Aucune dépendance
3
+ // externe : http natif uniquement.
4
+
5
+ import { createServer } from 'node:http';
6
+ import { readFileSync, existsSync, createReadStream } from 'node:fs';
7
+ import { join, dirname, extname, basename } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ import { TOOLS, PROFILES, getTool, toolStatus } from '../core/registry.js';
11
+ import { runTool } from '../core/runner.js';
12
+ import { effectiveTarget } from '../core/target.js';
13
+ import { allFindings, findingsForTarget, allScans, clearAll, targets, DATA_DIR } from '../core/store.js';
14
+ import { generateReport } from '../report/html.js';
15
+
16
+ const HERE = dirname(fileURLToPath(import.meta.url));
17
+ const PUBLIC = join(HERE, 'public');
18
+ const MIME = { '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript', '.json': 'application/json', '.svg': 'image/svg+xml' };
19
+
20
+ function send(res, code, body, type = 'application/json') {
21
+ res.writeHead(code, { 'Content-Type': type, 'Cache-Control': 'no-store' });
22
+ res.end(typeof body === 'string' || Buffer.isBuffer(body) ? body : JSON.stringify(body));
23
+ }
24
+
25
+ function readBody(req) {
26
+ return new Promise((resolve) => {
27
+ let data = '';
28
+ req.on('data', (c) => { data += c; });
29
+ req.on('end', () => { try { resolve(JSON.parse(data || '{}')); } catch { resolve({}); } });
30
+ });
31
+ }
32
+
33
+ // Schéma "public" des outils (avec options) pour que l'UI génère ses contrôles.
34
+ function toolsState() {
35
+ return toolStatus({ fresh: true }).map(({ tool, bin, available }) => ({
36
+ id: tool.id,
37
+ name: tool.name,
38
+ category: tool.category,
39
+ description: tool.description,
40
+ needs: tool.needs,
41
+ available,
42
+ bin: bin || null,
43
+ install: tool.install,
44
+ options: tool.options || [],
45
+ }));
46
+ }
47
+
48
+ async function handleScan(req, res) {
49
+ const body = await readBody(req);
50
+ const target = String(body.target || '').trim();
51
+ const ids = Array.isArray(body.tools) ? body.tools : [];
52
+ const timeout = Number(body.timeout) || 0;
53
+ const toolOpts = body.toolOpts || {};
54
+
55
+ if (!target || !ids.length) { send(res, 400, { error: 'target et tools requis' }); return; }
56
+
57
+ res.writeHead(200, { 'Content-Type': 'application/x-ndjson', 'Cache-Control': 'no-store', 'X-Accel-Buffering': 'no' });
58
+ const emit = (ev) => res.write(JSON.stringify(ev) + '\n');
59
+
60
+ const avail = new Set(toolStatus().filter((s) => s.available).map((s) => s.tool.id));
61
+ const run = ids.filter((id) => getTool(id) && avail.has(id));
62
+ const skipped = ids.filter((id) => getTool(id) && !avail.has(id));
63
+ if (skipped.length) emit({ type: 'info', message: `Ignorés (non installés) : ${skipped.join(', ')}` });
64
+
65
+ let totalFindings = 0;
66
+ for (const id of run) {
67
+ const tool = getTool(id);
68
+ const et = effectiveTarget(tool, target);
69
+ emit({ type: 'tool-start', tool: id, name: tool.name, target: et });
70
+
71
+ const opts = { ...(toolOpts[id] || {}), timeout };
72
+ const result = await runTool(tool, et, {
73
+ opts,
74
+ onLog: (l) => emit({ type: 'log', tool: id, line: l }),
75
+ onData: (s) => emit({ type: 'out', tool: id, chunk: s }),
76
+ });
77
+
78
+ totalFindings += result.findings.length;
79
+ emit({ type: 'tool-done', tool: id, code: result.code, error: result.error || null, findings: result.findings });
80
+ }
81
+
82
+ emit({ type: 'done', totalFindings, tools: run.length });
83
+ res.end();
84
+ }
85
+
86
+ async function handleApi(req, res, url) {
87
+ const path = url.pathname;
88
+
89
+ if (path === '/api/state' && req.method === 'GET') {
90
+ return send(res, 200, {
91
+ tools: toolsState(),
92
+ profiles: PROFILES,
93
+ targets: targets(),
94
+ findingsCount: allFindings().length,
95
+ scansCount: allScans().length,
96
+ });
97
+ }
98
+ if (path === '/api/findings' && req.method === 'GET') {
99
+ const t = url.searchParams.get('target');
100
+ return send(res, 200, t ? findingsForTarget(t) : allFindings());
101
+ }
102
+ if (path === '/api/scans' && req.method === 'GET') return send(res, 200, allScans());
103
+ if (path === '/api/scan' && req.method === 'POST') return handleScan(req, res);
104
+ if (path === '/api/clear' && req.method === 'POST') { clearAll(); return send(res, 200, { ok: true }); }
105
+ if (path === '/api/report' && req.method === 'POST') {
106
+ const { htmlPath, jsonPath } = generateReport(allFindings(), { scans: allScans() });
107
+ return send(res, 200, { htmlUrl: `/report/${basename(htmlPath)}`, jsonUrl: `/report/${basename(jsonPath)}`, htmlPath });
108
+ }
109
+ return send(res, 404, { error: 'not found' });
110
+ }
111
+
112
+ function serveStatic(res, file) {
113
+ if (!existsSync(file)) { send(res, 404, 'Not found', 'text/plain'); return; }
114
+ const type = MIME[extname(file)] || 'application/octet-stream';
115
+ res.writeHead(200, { 'Content-Type': type, 'Cache-Control': 'no-store' });
116
+ createReadStream(file).pipe(res);
117
+ }
118
+
119
+ export function startWeb({ port = 7373 } = {}) {
120
+ const server = createServer(async (req, res) => {
121
+ const url = new URL(req.url, `http://${req.headers.host}`);
122
+ try {
123
+ if (url.pathname.startsWith('/api/')) return await handleApi(req, res, url);
124
+
125
+ if (url.pathname.startsWith('/report/')) {
126
+ const f = join(DATA_DIR, 'reports', basename(url.pathname));
127
+ return serveStatic(res, f);
128
+ }
129
+
130
+ // Fichiers statiques de l'UI.
131
+ const rel = url.pathname === '/' ? 'index.html' : url.pathname.replace(/^\//, '');
132
+ return serveStatic(res, join(PUBLIC, basename(rel)));
133
+ } catch (err) {
134
+ send(res, 500, { error: err.message });
135
+ }
136
+ });
137
+
138
+ return new Promise((resolve) => {
139
+ server.listen(port, () => resolve({ server, url: `http://localhost:${port}` }));
140
+ });
141
+ }
@@ -0,0 +1,7 @@
1
+ 10.64.0.1
2
+ 10.1.4.254
3
+ 1.1.1.1
4
+ 1.0.0.1
5
+ 8.8.8.8
6
+ 8.8.4.4
7
+ 9.9.9.9
@@ -0,0 +1,140 @@
1
+ admin
2
+ administrator
3
+ login
4
+ logout
5
+ register
6
+ signup
7
+ signin
8
+ dashboard
9
+ panel
10
+ cpanel
11
+ wp-admin
12
+ wp-login.php
13
+ wp-content
14
+ wp-includes
15
+ wp-json
16
+ api
17
+ api/v1
18
+ api/v2
19
+ graphql
20
+ rest
21
+ backup
22
+ backups
23
+ old
24
+ new
25
+ test
26
+ testing
27
+ dev
28
+ staging
29
+ prod
30
+ config
31
+ configuration
32
+ settings
33
+ setup
34
+ install
35
+ installer
36
+ phpinfo.php
37
+ info.php
38
+ server-status
39
+ server-info
40
+ .git
41
+ .git/config
42
+ .env
43
+ .env.local
44
+ .htaccess
45
+ .htpasswd
46
+ .svn
47
+ .ds_store
48
+ robots.txt
49
+ sitemap.xml
50
+ crossdomain.xml
51
+ security.txt
52
+ .well-known
53
+ uploads
54
+ upload
55
+ files
56
+ file
57
+ images
58
+ img
59
+ assets
60
+ static
61
+ public
62
+ private
63
+ tmp
64
+ temp
65
+ cache
66
+ logs
67
+ log
68
+ db
69
+ database
70
+ sql
71
+ dump
72
+ data
73
+ storage
74
+ media
75
+ includes
76
+ inc
77
+ lib
78
+ libs
79
+ vendor
80
+ node_modules
81
+ src
82
+ js
83
+ css
84
+ fonts
85
+ download
86
+ downloads
87
+ docs
88
+ doc
89
+ documentation
90
+ help
91
+ support
92
+ contact
93
+ about
94
+ user
95
+ users
96
+ account
97
+ accounts
98
+ profile
99
+ profiles
100
+ member
101
+ members
102
+ auth
103
+ oauth
104
+ token
105
+ session
106
+ sessions
107
+ cart
108
+ checkout
109
+ order
110
+ orders
111
+ payment
112
+ payments
113
+ invoice
114
+ invoices
115
+ report
116
+ reports
117
+ export
118
+ import
119
+ search
120
+ query
121
+ status
122
+ health
123
+ healthz
124
+ ping
125
+ metrics
126
+ debug
127
+ console
128
+ shell
129
+ cmd
130
+ phpmyadmin
131
+ adminer
132
+ pma
133
+ mysql
134
+ manager
135
+ management
136
+ portal
137
+ internal
138
+ intranet
139
+ secret
140
+ hidden