@voidagency/web-scanner 0.0.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.
- package/README.md +198 -0
- package/dist/aggregator.d.ts +65 -0
- package/dist/aggregator.d.ts.map +1 -0
- package/dist/aggregator.js +546 -0
- package/dist/aggregator.js.map +1 -0
- package/dist/categories.d.ts +59 -0
- package/dist/categories.d.ts.map +1 -0
- package/dist/categories.js +278 -0
- package/dist/categories.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +457 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +121 -0
- package/dist/config.js.map +1 -0
- package/dist/coverage.d.ts +49 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/coverage.js +165 -0
- package/dist/coverage.js.map +1 -0
- package/dist/enrichers/nvd.d.ts +55 -0
- package/dist/enrichers/nvd.d.ts.map +1 -0
- package/dist/enrichers/nvd.js +326 -0
- package/dist/enrichers/nvd.js.map +1 -0
- package/dist/report.d.ts +12 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +460 -0
- package/dist/report.js.map +1 -0
- package/dist/runners/nuclei.d.ts +59 -0
- package/dist/runners/nuclei.d.ts.map +1 -0
- package/dist/runners/nuclei.js +531 -0
- package/dist/runners/nuclei.js.map +1 -0
- package/dist/runners/testssl.d.ts +16 -0
- package/dist/runners/testssl.d.ts.map +1 -0
- package/dist/runners/testssl.js +179 -0
- package/dist/runners/testssl.js.map +1 -0
- package/dist/runners/zap.d.ts +30 -0
- package/dist/runners/zap.d.ts.map +1 -0
- package/dist/runners/zap.js +389 -0
- package/dist/runners/zap.js.map +1 -0
- package/dist/types.d.ts +172 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -0
- package/templates/drupal-api-index-exposed.yaml +81 -0
- package/templates/drupal-api-user-detail.yaml +76 -0
- package/templates/drupal-api-user-listing.yaml +59 -0
- package/templates/drupal-dev-files-exposed.yaml +73 -0
- package/templates/drupal-file-path-disclosure.yaml +59 -0
- package/templates/drupal-files-listing.yaml +63 -0
- package/templates/drupal-install-error-disclosure.yaml +62 -0
- package/templates/drupal-theme-lockfiles.yaml +79 -0
- package/templates/drupal-version-detect.yaml +89 -0
- package/templates/http-options-enabled.yaml +56 -0
- package/templates/nextjs-version-detect.yaml +35 -0
- package/templates/php-version-detect.yaml +37 -0
- package/zap.yaml +33 -0
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuclei Runner
|
|
3
|
+
* Execute nuclei scans and parse JSONL output
|
|
4
|
+
*
|
|
5
|
+
* DESIGN: Keep it simple - don't try to reformat Nuclei's output.
|
|
6
|
+
* Just parse and pass through. Let the template handle display.
|
|
7
|
+
*
|
|
8
|
+
* Note: Headless templates require accepting macOS keychain prompt once ("Always Allow")
|
|
9
|
+
*/
|
|
10
|
+
import { execa } from 'execa';
|
|
11
|
+
// Stack-specific tags (always includes generic stuff)
|
|
12
|
+
const STACK_TAGS = {
|
|
13
|
+
drupal: ['drupal', 'php', 'nginx', 'apache'],
|
|
14
|
+
wordpress: ['wordpress', 'wp-plugin', 'wp-theme', 'php', 'nginx', 'apache'],
|
|
15
|
+
nextjs: ['nextjs', 'react', 'javascript', 'nodejs', 'nginx'],
|
|
16
|
+
laravel: ['laravel', 'php', 'nginx', 'apache'],
|
|
17
|
+
symfony: ['symfony', 'php', 'nginx', 'apache'],
|
|
18
|
+
django: ['django', 'python', 'nginx', 'apache'],
|
|
19
|
+
rails: ['rails', 'ruby', 'nginx', 'apache'],
|
|
20
|
+
springboot: ['spring', 'java', 'tomcat', 'nginx'],
|
|
21
|
+
generic: [], // No stack-specific tags
|
|
22
|
+
};
|
|
23
|
+
// Universal tags - always included (common infrastructure + generic checks)
|
|
24
|
+
const UNIVERSAL_TAGS = ['generic', 'misconfig', 'exposure', 'cve', 'panel', 'config', 'tech', 'nginx', 'apache'];
|
|
25
|
+
// Profile determines depth, not templates
|
|
26
|
+
const PROFILE_CONFIG = {
|
|
27
|
+
quick: { timeout: 60 },
|
|
28
|
+
standard: { timeout: 300 },
|
|
29
|
+
deep: { timeout: 600, templates: ['http/fuzzing/'] },
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Map Nuclei severity to normalized severity
|
|
33
|
+
*/
|
|
34
|
+
function mapSeverity(severity) {
|
|
35
|
+
const s = severity.toLowerCase();
|
|
36
|
+
if (s === 'critical')
|
|
37
|
+
return 'critical';
|
|
38
|
+
if (s === 'high')
|
|
39
|
+
return 'high';
|
|
40
|
+
if (s === 'medium')
|
|
41
|
+
return 'medium';
|
|
42
|
+
if (s === 'low')
|
|
43
|
+
return 'low';
|
|
44
|
+
return 'info';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if this is a tech detection template
|
|
48
|
+
*/
|
|
49
|
+
function isTechTemplate(data) {
|
|
50
|
+
return data['template-id']?.includes('technologies/') ||
|
|
51
|
+
data.info.tags?.some(t => ['tech', 'detect'].includes(t)) ||
|
|
52
|
+
false;
|
|
53
|
+
}
|
|
54
|
+
// User-defined severity overrides (loaded from config)
|
|
55
|
+
let severityOverrides = {};
|
|
56
|
+
/**
|
|
57
|
+
* Set severity overrides from config
|
|
58
|
+
*/
|
|
59
|
+
export function setSeverityOverrides(overrides) {
|
|
60
|
+
severityOverrides = {};
|
|
61
|
+
for (const [pattern, severity] of Object.entries(overrides)) {
|
|
62
|
+
const s = severity.toLowerCase();
|
|
63
|
+
if (['critical', 'high', 'medium', 'low', 'info'].includes(s)) {
|
|
64
|
+
severityOverrides[pattern] = s;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get effective severity (with user overrides)
|
|
70
|
+
*/
|
|
71
|
+
function getEffectiveSeverity(data) {
|
|
72
|
+
const templateId = data['template-id'];
|
|
73
|
+
// Check for user override
|
|
74
|
+
for (const [pattern, severity] of Object.entries(severityOverrides)) {
|
|
75
|
+
if (templateId?.includes(pattern)) {
|
|
76
|
+
return severity;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Default to Nuclei's severity
|
|
80
|
+
return mapSeverity(data.info.severity);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Parse a single JSONL line into a Finding
|
|
84
|
+
* SIMPLE: Just map the fields, don't transform
|
|
85
|
+
*/
|
|
86
|
+
function parseNucleiLine(line, index) {
|
|
87
|
+
try {
|
|
88
|
+
const data = JSON.parse(line);
|
|
89
|
+
const severity = getEffectiveSeverity(data); // Use override if applicable
|
|
90
|
+
const isTech = isTechTemplate(data);
|
|
91
|
+
// Only show CVE/CWE/CVSS for actual vulnerabilities (not info-level tech detection)
|
|
92
|
+
const isVuln = severity !== 'info' && !isTech;
|
|
93
|
+
// Get extracted results (versions, etc.) - filter noise and limit
|
|
94
|
+
let extracted = data['extracted-results'];
|
|
95
|
+
if (extracted && extracted.length > 0) {
|
|
96
|
+
// Filter out noisy patterns (package names from lock files)
|
|
97
|
+
extracted = extracted.filter(e => !e.startsWith('"name":') &&
|
|
98
|
+
!e.startsWith('"author":') &&
|
|
99
|
+
e.length < 100 // Skip very long extractions
|
|
100
|
+
);
|
|
101
|
+
// Limit to 5 useful extractions
|
|
102
|
+
if (extracted.length > 5) {
|
|
103
|
+
extracted = extracted.slice(0, 5);
|
|
104
|
+
}
|
|
105
|
+
// If all filtered out, set to undefined
|
|
106
|
+
if (extracted.length === 0) {
|
|
107
|
+
extracted = undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
id: String(index + 1).padStart(3, '0'),
|
|
112
|
+
title: data.info.name,
|
|
113
|
+
description: data.info.description || '',
|
|
114
|
+
severity,
|
|
115
|
+
source: 'nuclei',
|
|
116
|
+
target: data['matched-at'],
|
|
117
|
+
// The KEY field - what actually matched
|
|
118
|
+
matcher: data['matcher-name'],
|
|
119
|
+
// Extracted values (versions, etc.)
|
|
120
|
+
extracted,
|
|
121
|
+
// Classification - only for vulnerabilities
|
|
122
|
+
cve: isVuln ? data.info.classification?.['cve-id']?.[0] : undefined,
|
|
123
|
+
cwe: isVuln ? data.info.classification?.['cwe-id']?.[0] : undefined,
|
|
124
|
+
cvss: isVuln ? data.info.classification?.['cvss-metrics'] : undefined,
|
|
125
|
+
// Metadata
|
|
126
|
+
templateId: data['template-id'],
|
|
127
|
+
tags: data.info.tags,
|
|
128
|
+
// Evidence - only for medium+ severity
|
|
129
|
+
response: (severity === 'medium' || severity === 'high' || severity === 'critical')
|
|
130
|
+
? data.response?.substring(0, 1000)
|
|
131
|
+
: undefined,
|
|
132
|
+
curl: isVuln ? data['curl-command'] : undefined,
|
|
133
|
+
// References
|
|
134
|
+
references: data.info.reference,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Check if a finding is a technology detection
|
|
143
|
+
*/
|
|
144
|
+
function isTechDetection(finding) {
|
|
145
|
+
// Official Nuclei tech templates
|
|
146
|
+
if (finding.templateId?.includes('technologies/'))
|
|
147
|
+
return true;
|
|
148
|
+
// Custom version detection templates (title pattern: "X Version - Detect")
|
|
149
|
+
if (/Version\s*-\s*Detect/i.test(finding.title))
|
|
150
|
+
return true;
|
|
151
|
+
// Tags indicating tech detection
|
|
152
|
+
if (finding.tags?.some(t => ['tech', 'detect', 'version'].includes(t)))
|
|
153
|
+
return true;
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Extract technology name and version from finding
|
|
158
|
+
*/
|
|
159
|
+
function extractTechInfo(finding) {
|
|
160
|
+
// Pattern: "Drupal Version - Detect" or "Next.js Version - Detect"
|
|
161
|
+
// Use [^\s]+ to capture tech names with dots (Next.js)
|
|
162
|
+
const match = /^([^\s]+)\s+Version\s*-\s*Detect/i.exec(finding.title);
|
|
163
|
+
if (match) {
|
|
164
|
+
const techName = match[1];
|
|
165
|
+
const version = finding.extracted?.[0] || finding.matcher;
|
|
166
|
+
return version ? `${techName}/${version}` : techName;
|
|
167
|
+
}
|
|
168
|
+
// Fallback: use matcher or title
|
|
169
|
+
return finding.matcher || finding.title;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Extract technology detections from findings
|
|
173
|
+
*/
|
|
174
|
+
export function extractTechnologies(findings) {
|
|
175
|
+
const techByHost = new Map();
|
|
176
|
+
for (const finding of findings) {
|
|
177
|
+
// Only tech detection findings
|
|
178
|
+
if (!isTechDetection(finding))
|
|
179
|
+
continue;
|
|
180
|
+
// Extract host from target URL
|
|
181
|
+
let host;
|
|
182
|
+
try {
|
|
183
|
+
host = new URL(finding.target).hostname;
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
host = finding.target;
|
|
187
|
+
}
|
|
188
|
+
if (!techByHost.has(host)) {
|
|
189
|
+
techByHost.set(host, new Set());
|
|
190
|
+
}
|
|
191
|
+
// Extract technology name with version
|
|
192
|
+
const techName = extractTechInfo(finding);
|
|
193
|
+
if (techName) {
|
|
194
|
+
techByHost.get(host).add(techName);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return Array.from(techByHost.entries()).map(([host, techs]) => ({
|
|
198
|
+
host,
|
|
199
|
+
technologies: Array.from(techs),
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get tags for a given stack
|
|
204
|
+
*/
|
|
205
|
+
export function getStackTags(stack) {
|
|
206
|
+
const stackTags = STACK_TAGS[stack] || [];
|
|
207
|
+
return [...UNIVERSAL_TAGS, ...stackTags];
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get available stacks
|
|
211
|
+
*/
|
|
212
|
+
export function getAvailableStacks() {
|
|
213
|
+
return Object.keys(STACK_TAGS);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Run Nuclei scan on target URL(s)
|
|
217
|
+
*/
|
|
218
|
+
export async function runNuclei(targets, profile = 'standard', options = {}) {
|
|
219
|
+
const targetList = Array.isArray(targets) ? targets : [targets];
|
|
220
|
+
const stack = options.stack || 'generic';
|
|
221
|
+
const tags = getStackTags(stack);
|
|
222
|
+
const profileConfig = PROFILE_CONFIG[profile];
|
|
223
|
+
// Build target args: -u url1 -u url2 ...
|
|
224
|
+
const targetArgs = targetList.flatMap(t => ['-u', t]);
|
|
225
|
+
// Build template args for deep profile
|
|
226
|
+
const extraTemplateArgs = profileConfig.templates?.flatMap(t => ['-t', t]) ?? [];
|
|
227
|
+
const args = [
|
|
228
|
+
'-jsonl',
|
|
229
|
+
'-silent',
|
|
230
|
+
'-nc', // no color
|
|
231
|
+
'-duc', // disable update check
|
|
232
|
+
'-headless', // enable headless browser for templates that need it
|
|
233
|
+
'-rl', String(options.rateLimit || 50),
|
|
234
|
+
'-timeout', String(options.timeout || profileConfig.timeout),
|
|
235
|
+
...targetArgs,
|
|
236
|
+
'-tags', tags.join(','),
|
|
237
|
+
'-t', './templates/', // Custom VoidSec templates
|
|
238
|
+
...extraTemplateArgs,
|
|
239
|
+
];
|
|
240
|
+
try {
|
|
241
|
+
const { stdout } = await execa('nuclei', args, { reject: false, stdin: 'ignore' });
|
|
242
|
+
const lines = stdout.trim().split('\n').filter(line => line.trim());
|
|
243
|
+
const allFindings = [];
|
|
244
|
+
for (const line of lines) {
|
|
245
|
+
const finding = parseNucleiLine(line, allFindings.length);
|
|
246
|
+
if (finding) {
|
|
247
|
+
allFindings.push(finding);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Extract technologies
|
|
251
|
+
const technologies = extractTechnologies(allFindings);
|
|
252
|
+
// Filter: Keep only non-tech findings OR tech findings with severity > info
|
|
253
|
+
const findings = allFindings.filter(f => !f.templateId?.includes('technologies/') || f.severity !== 'info');
|
|
254
|
+
return { findings, technologies };
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
throw new Error(`Nuclei scan failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Check if Nuclei is installed
|
|
262
|
+
*/
|
|
263
|
+
export async function isNucleiInstalled() {
|
|
264
|
+
try {
|
|
265
|
+
await execa('nuclei', ['--version']);
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Extract Drupal themes from HTML
|
|
274
|
+
* Looks for: /themes/xxx/ patterns in script/link tags
|
|
275
|
+
*/
|
|
276
|
+
export async function extractDrupalThemes(targetUrl) {
|
|
277
|
+
try {
|
|
278
|
+
const response = await fetch(targetUrl);
|
|
279
|
+
const html = await response.text();
|
|
280
|
+
// Match /themes/xxx/ but exclude /themes/contrib/
|
|
281
|
+
const themeMatches = html.matchAll(/\/themes\/([^/]+)\//g);
|
|
282
|
+
const themes = new Set();
|
|
283
|
+
for (const match of themeMatches) {
|
|
284
|
+
const theme = match[1];
|
|
285
|
+
// Skip contrib/custom - these are directories, not themes
|
|
286
|
+
if (theme && theme !== 'contrib' && theme !== 'custom') {
|
|
287
|
+
themes.add(theme);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return Array.from(themes);
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Run Nuclei template with dynamic variables
|
|
298
|
+
* Used for checks that need runtime-extracted values (like theme names)
|
|
299
|
+
*/
|
|
300
|
+
export async function runNucleiWithVars(target, templatePath, vars, options = {}) {
|
|
301
|
+
const args = [
|
|
302
|
+
'-jsonl',
|
|
303
|
+
'-silent',
|
|
304
|
+
'-nc',
|
|
305
|
+
'-duc',
|
|
306
|
+
'-headless',
|
|
307
|
+
'-rl', String(options.rateLimit || 150),
|
|
308
|
+
'-t', templatePath,
|
|
309
|
+
'-u', target,
|
|
310
|
+
];
|
|
311
|
+
// Add variables
|
|
312
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
313
|
+
args.push('-var', `${key}=${value}`);
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
const { stdout } = await execa('nuclei', args, { reject: false, stdin: 'ignore' });
|
|
317
|
+
const lines = stdout.trim().split('\n').filter(line => line.trim());
|
|
318
|
+
const findings = [];
|
|
319
|
+
for (const line of lines) {
|
|
320
|
+
const finding = parseNucleiLine(line, findings.length);
|
|
321
|
+
if (finding) {
|
|
322
|
+
findings.push(finding);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return findings;
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
return [];
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Try to fetch user list from a single API path
|
|
333
|
+
*/
|
|
334
|
+
async function tryFetchUserList(apiUrl) {
|
|
335
|
+
try {
|
|
336
|
+
const response = await fetch(apiUrl, {
|
|
337
|
+
headers: { 'Accept': 'application/vnd.api+json' }
|
|
338
|
+
});
|
|
339
|
+
if (!response.ok)
|
|
340
|
+
return [];
|
|
341
|
+
const json = await response.json();
|
|
342
|
+
if (!json.data || !Array.isArray(json.data))
|
|
343
|
+
return [];
|
|
344
|
+
// Extract self links from each user
|
|
345
|
+
return json.data
|
|
346
|
+
.map((user) => user.links?.self && (typeof user.links.self === 'string' ? user.links.self : user.links.self.href))
|
|
347
|
+
.filter((url) => !!url);
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return [];
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Extract user URLs from Drupal JSON:API response
|
|
355
|
+
* Tries multiple API paths with language prefixes
|
|
356
|
+
*/
|
|
357
|
+
async function extractDrupalApiUserUrls(targetUrl) {
|
|
358
|
+
const baseUrl = new URL(targetUrl);
|
|
359
|
+
const apiPaths = [
|
|
360
|
+
'/api/user/user',
|
|
361
|
+
'/jsonapi/user/user',
|
|
362
|
+
'/en/api/user/user',
|
|
363
|
+
'/fr/api/user/user',
|
|
364
|
+
'/ar/api/user/user',
|
|
365
|
+
];
|
|
366
|
+
for (const path of apiPaths) {
|
|
367
|
+
const urls = await tryFetchUserList(`${baseUrl.origin}${path}`);
|
|
368
|
+
if (urls.length > 0)
|
|
369
|
+
return urls;
|
|
370
|
+
}
|
|
371
|
+
return [];
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Check sensitive attributes to look for in user API responses
|
|
375
|
+
*/
|
|
376
|
+
const SENSITIVE_USER_ATTRIBUTES = [
|
|
377
|
+
'display_name',
|
|
378
|
+
'mail',
|
|
379
|
+
'name',
|
|
380
|
+
'created',
|
|
381
|
+
'changed',
|
|
382
|
+
'access',
|
|
383
|
+
'login',
|
|
384
|
+
];
|
|
385
|
+
/**
|
|
386
|
+
* Check if a user API response exposes sensitive attributes
|
|
387
|
+
*/
|
|
388
|
+
async function checkUserApiExposure(userUrl) {
|
|
389
|
+
try {
|
|
390
|
+
const response = await fetch(userUrl, {
|
|
391
|
+
headers: { 'Accept': 'application/vnd.api+json' }
|
|
392
|
+
});
|
|
393
|
+
if (!response.ok)
|
|
394
|
+
return null;
|
|
395
|
+
const json = await response.json();
|
|
396
|
+
const attributes = json.data?.attributes || {};
|
|
397
|
+
// Check which sensitive attributes are exposed
|
|
398
|
+
const exposedAttrs = [];
|
|
399
|
+
const extractedValues = [];
|
|
400
|
+
for (const attr of SENSITIVE_USER_ATTRIBUTES) {
|
|
401
|
+
if (attr in attributes && attributes[attr]) {
|
|
402
|
+
exposedAttrs.push(attr);
|
|
403
|
+
// Capture first few values as evidence
|
|
404
|
+
if (extractedValues.length < 3) {
|
|
405
|
+
const value = String(attributes[attr]).substring(0, 50);
|
|
406
|
+
extractedValues.push(`${attr}: ${value}`);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (exposedAttrs.length === 0)
|
|
411
|
+
return null;
|
|
412
|
+
return {
|
|
413
|
+
id: '',
|
|
414
|
+
title: 'Drupal JSON:API User Details Exposed',
|
|
415
|
+
description: `User API endpoint exposes sensitive attributes: ${exposedAttrs.join(', ')}. This can leak usernames, email patterns, and account activity.`,
|
|
416
|
+
severity: exposedAttrs.includes('mail') ? 'high' : 'medium',
|
|
417
|
+
source: 'nuclei',
|
|
418
|
+
target: userUrl,
|
|
419
|
+
templateId: 'drupal-api-user-detail-exposure',
|
|
420
|
+
tags: ['drupal', 'exposure', 'api', 'jsonapi', 'user', 'pii'],
|
|
421
|
+
extracted: extractedValues,
|
|
422
|
+
cwe: 'CWE-200',
|
|
423
|
+
cvss: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N',
|
|
424
|
+
references: [
|
|
425
|
+
'https://www.drupal.org/project/drupal/issues/3240913',
|
|
426
|
+
'https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/security-considerations',
|
|
427
|
+
],
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Scan themes for exposed lock files
|
|
436
|
+
*/
|
|
437
|
+
async function scanThemeLockFiles(target, themes, onProgress) {
|
|
438
|
+
const findings = [];
|
|
439
|
+
for (const theme of themes) {
|
|
440
|
+
onProgress?.(`Checking theme: ${theme}`);
|
|
441
|
+
const themeFindings = await runNucleiWithVars(target, './templates/drupal-theme-lockfiles.yaml', { theme }, { rateLimit: 150 });
|
|
442
|
+
findings.push(...themeFindings);
|
|
443
|
+
}
|
|
444
|
+
return findings;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Check user API endpoints for sensitive attribute exposure
|
|
448
|
+
*/
|
|
449
|
+
async function scanUserApiExposure(userUrls, onProgress) {
|
|
450
|
+
onProgress?.(`Found ${userUrls.length} user URLs, checking for exposed attributes...`);
|
|
451
|
+
// Check first 5 users (enough to confirm the issue)
|
|
452
|
+
for (const userUrl of userUrls.slice(0, 5)) {
|
|
453
|
+
const finding = await checkUserApiExposure(userUrl);
|
|
454
|
+
if (finding) {
|
|
455
|
+
// Add one finding with all affected URLs
|
|
456
|
+
finding.affectedUrls = userUrls.slice(0, 10);
|
|
457
|
+
if (userUrls.length > 10) {
|
|
458
|
+
finding.description += ` (${userUrls.length} total users exposed)`;
|
|
459
|
+
}
|
|
460
|
+
return [finding];
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
onProgress?.('User endpoints not exposing sensitive attributes');
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Run all static Drupal templates (non-dynamic ones)
|
|
468
|
+
*/
|
|
469
|
+
async function runStaticDrupalTemplates(target, onProgress) {
|
|
470
|
+
onProgress?.('Running static Drupal templates...');
|
|
471
|
+
const args = [
|
|
472
|
+
'-jsonl',
|
|
473
|
+
'-silent',
|
|
474
|
+
'-nc',
|
|
475
|
+
'-duc',
|
|
476
|
+
'-headless',
|
|
477
|
+
'-rl', '150',
|
|
478
|
+
'-t', './templates/',
|
|
479
|
+
'-tags', 'drupal',
|
|
480
|
+
'-u', target,
|
|
481
|
+
];
|
|
482
|
+
try {
|
|
483
|
+
const { stdout } = await execa('nuclei', args, { reject: false, stdin: 'ignore' });
|
|
484
|
+
const lines = stdout.trim().split('\n').filter(line => line.trim());
|
|
485
|
+
const findings = [];
|
|
486
|
+
for (const line of lines) {
|
|
487
|
+
const finding = parseNucleiLine(line, findings.length);
|
|
488
|
+
if (finding) {
|
|
489
|
+
findings.push(finding);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
onProgress?.(`Found ${findings.length} issues from static templates`);
|
|
493
|
+
return findings;
|
|
494
|
+
}
|
|
495
|
+
catch {
|
|
496
|
+
return [];
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Run Drupal-specific scans (all templates + dynamic checks)
|
|
501
|
+
* Includes: static templates, theme lock files, API user exposure
|
|
502
|
+
*/
|
|
503
|
+
export async function runDrupalDynamicScans(target, onProgress) {
|
|
504
|
+
const findings = [];
|
|
505
|
+
// 1. Run all static Drupal templates
|
|
506
|
+
const staticFindings = await runStaticDrupalTemplates(target, onProgress);
|
|
507
|
+
findings.push(...staticFindings);
|
|
508
|
+
// 2. Extract themes from HTML and check lock files (dynamic)
|
|
509
|
+
onProgress?.('Extracting Drupal themes from HTML...');
|
|
510
|
+
const themes = await extractDrupalThemes(target);
|
|
511
|
+
if (themes.length > 0) {
|
|
512
|
+
onProgress?.(`Found themes: ${themes.join(', ')}`);
|
|
513
|
+
const themeFindings = await scanThemeLockFiles(target, themes, onProgress);
|
|
514
|
+
findings.push(...themeFindings);
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
onProgress?.('No custom themes found');
|
|
518
|
+
}
|
|
519
|
+
// 3. Check JSON:API user exposure (follow links - dynamic)
|
|
520
|
+
onProgress?.('Checking JSON:API user endpoints...');
|
|
521
|
+
const userUrls = await extractDrupalApiUserUrls(target);
|
|
522
|
+
if (userUrls.length > 0) {
|
|
523
|
+
const userFindings = await scanUserApiExposure(userUrls, onProgress);
|
|
524
|
+
findings.push(...userFindings);
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
onProgress?.('No accessible JSON:API user endpoints found');
|
|
528
|
+
}
|
|
529
|
+
return findings;
|
|
530
|
+
}
|
|
531
|
+
//# sourceMappingURL=nuclei.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nuclei.js","sourceRoot":"","sources":["../../src/runners/nuclei.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* testssl.sh Runner
|
|
3
|
+
* Execute SSL/TLS analysis and parse JSON output
|
|
4
|
+
*/
|
|
5
|
+
import { Finding, ScanProfile } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Run testssl.sh scan on target
|
|
8
|
+
*/
|
|
9
|
+
export declare function runTestssl(target: string, profile?: ScanProfile, options?: {
|
|
10
|
+
startIndex?: number;
|
|
11
|
+
}): Promise<Finding[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Check if testssl.sh is installed
|
|
14
|
+
*/
|
|
15
|
+
export declare function isTestsslInstalled(): Promise<boolean>;
|
|
16
|
+
//# sourceMappingURL=testssl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testssl.d.ts","sourceRoot":"","sources":["../../src/runners/testssl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,OAAO,EAAE,WAAW,EAA2B,MAAM,aAAa,CAAC;AA8H5E;;GAEG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,WAAwB,EACjC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACpC,OAAO,CAAC,OAAO,EAAE,CAAC,CAgDpB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO3D"}
|