@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
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VoidSec Scanner - Core Types
|
|
3
|
+
* Based on actual tool output fields
|
|
4
|
+
*/
|
|
5
|
+
export type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
6
|
+
export type ToolSource = 'nuclei' | 'testssl' | 'trivy' | 'katana' | 'nvd' | 'zap';
|
|
7
|
+
/**
|
|
8
|
+
* Unified finding from any scanning tool
|
|
9
|
+
*/
|
|
10
|
+
export interface Finding {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
description: string;
|
|
14
|
+
severity: Severity;
|
|
15
|
+
source: ToolSource;
|
|
16
|
+
target: string;
|
|
17
|
+
affectedUrls?: string[];
|
|
18
|
+
cveTable?: CveTableEntry[];
|
|
19
|
+
cve?: string;
|
|
20
|
+
cwe?: string;
|
|
21
|
+
cvss?: string;
|
|
22
|
+
templateId?: string;
|
|
23
|
+
tags?: string[];
|
|
24
|
+
matcher?: string;
|
|
25
|
+
extracted?: string[];
|
|
26
|
+
request?: string;
|
|
27
|
+
response?: string;
|
|
28
|
+
curl?: string;
|
|
29
|
+
packageName?: string;
|
|
30
|
+
installedVersion?: string;
|
|
31
|
+
fixedVersion?: string;
|
|
32
|
+
references?: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Technology detection entry
|
|
36
|
+
*/
|
|
37
|
+
export interface TechDetection {
|
|
38
|
+
host: string;
|
|
39
|
+
technologies: string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Severity counts for summary
|
|
43
|
+
*/
|
|
44
|
+
export interface SeverityCounts {
|
|
45
|
+
critical: number;
|
|
46
|
+
high: number;
|
|
47
|
+
medium: number;
|
|
48
|
+
low: number;
|
|
49
|
+
info: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Scan profile configuration
|
|
53
|
+
*/
|
|
54
|
+
export type ScanProfile = 'quick' | 'standard' | 'deep';
|
|
55
|
+
/**
|
|
56
|
+
* Test coverage result for a category
|
|
57
|
+
*/
|
|
58
|
+
export interface TestCoverageItem {
|
|
59
|
+
name: string;
|
|
60
|
+
description: string;
|
|
61
|
+
tested: boolean;
|
|
62
|
+
status: 'pass' | 'fail' | 'info' | 'untested';
|
|
63
|
+
count: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Passed security check item
|
|
67
|
+
*/
|
|
68
|
+
export interface PassedCheckItem {
|
|
69
|
+
name: string;
|
|
70
|
+
description: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* CVE table entry for consolidated version-based findings
|
|
74
|
+
*/
|
|
75
|
+
export interface CveTableEntry {
|
|
76
|
+
cve: string;
|
|
77
|
+
cvss?: string;
|
|
78
|
+
severity: Severity;
|
|
79
|
+
summary: string;
|
|
80
|
+
references?: string[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Complete scan report
|
|
84
|
+
*/
|
|
85
|
+
export interface Report {
|
|
86
|
+
target: string;
|
|
87
|
+
scanDate: string;
|
|
88
|
+
duration: string;
|
|
89
|
+
profile: ScanProfile;
|
|
90
|
+
summary: SeverityCounts;
|
|
91
|
+
totalFindings: number;
|
|
92
|
+
technologies: TechDetection[];
|
|
93
|
+
findings: Finding[];
|
|
94
|
+
coverage?: TestCoverageItem[];
|
|
95
|
+
passedChecks?: PassedCheckItem[];
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Nuclei JSONL output structure
|
|
99
|
+
*/
|
|
100
|
+
export interface NucleiOutput {
|
|
101
|
+
'template-id': string;
|
|
102
|
+
'template-path'?: string;
|
|
103
|
+
info: {
|
|
104
|
+
name: string;
|
|
105
|
+
description?: string;
|
|
106
|
+
severity: string;
|
|
107
|
+
tags?: string[];
|
|
108
|
+
reference?: string[];
|
|
109
|
+
classification?: {
|
|
110
|
+
'cve-id'?: string[];
|
|
111
|
+
'cwe-id'?: string[];
|
|
112
|
+
'cvss-metrics'?: string;
|
|
113
|
+
'cvss-score'?: number;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
'matcher-name'?: string;
|
|
117
|
+
'matched-at': string;
|
|
118
|
+
'extracted-results'?: string[];
|
|
119
|
+
host?: string;
|
|
120
|
+
request?: string;
|
|
121
|
+
response?: string;
|
|
122
|
+
'curl-command'?: string;
|
|
123
|
+
timestamp?: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* testssl.sh JSON output structure
|
|
127
|
+
*/
|
|
128
|
+
export interface TestsslOutput {
|
|
129
|
+
id: string;
|
|
130
|
+
ip: string;
|
|
131
|
+
port: string;
|
|
132
|
+
severity: string;
|
|
133
|
+
cve?: string;
|
|
134
|
+
cwe?: string;
|
|
135
|
+
finding: string;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Trivy JSON output structure (simplified)
|
|
139
|
+
*/
|
|
140
|
+
export interface TrivyVulnerability {
|
|
141
|
+
VulnerabilityID: string;
|
|
142
|
+
PkgName: string;
|
|
143
|
+
InstalledVersion: string;
|
|
144
|
+
FixedVersion?: string;
|
|
145
|
+
Severity: string;
|
|
146
|
+
Title?: string;
|
|
147
|
+
Description?: string;
|
|
148
|
+
References?: string[];
|
|
149
|
+
CVSS?: {
|
|
150
|
+
nvd?: {
|
|
151
|
+
V3Score?: number;
|
|
152
|
+
V3Vector?: string;
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
export interface TrivyOutput {
|
|
157
|
+
Results?: Array<{
|
|
158
|
+
Target: string;
|
|
159
|
+
Vulnerabilities?: TrivyVulnerability[];
|
|
160
|
+
}>;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Scan options passed to runners
|
|
164
|
+
*/
|
|
165
|
+
export interface ScanOptions {
|
|
166
|
+
target: string;
|
|
167
|
+
profile: ScanProfile;
|
|
168
|
+
outputDir?: string;
|
|
169
|
+
rateLimit?: number;
|
|
170
|
+
timeout?: number;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@voidagency/web-scanner",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Security scanning CLI orchestrating ZAP, Nuclei, and testssl.sh",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cli.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"voidsec": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"templates",
|
|
13
|
+
"zap.yaml",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsx src/cli.ts",
|
|
19
|
+
"start": "node dist/cli.js",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"security",
|
|
24
|
+
"scanner",
|
|
25
|
+
"vulnerability",
|
|
26
|
+
"pentest",
|
|
27
|
+
"zap",
|
|
28
|
+
"nuclei",
|
|
29
|
+
"testssl",
|
|
30
|
+
"cve",
|
|
31
|
+
"security-audit"
|
|
32
|
+
],
|
|
33
|
+
"author": "",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": ""
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"commander": "^12.1.0",
|
|
41
|
+
"execa": "^9.3.0",
|
|
42
|
+
"handlebars": "^4.7.8",
|
|
43
|
+
"glob": "^11.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"typescript": "^5.5.0",
|
|
47
|
+
"@types/node": "^22.0.0",
|
|
48
|
+
"tsx": "^4.16.0"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20.0.0"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
id: drupal-api-index-exposed
|
|
2
|
+
|
|
3
|
+
info:
|
|
4
|
+
name: Drupal JSON:API Index Exposed
|
|
5
|
+
author: voidsec
|
|
6
|
+
severity: high
|
|
7
|
+
description: |
|
|
8
|
+
The Drupal JSON:API index is publicly accessible without authentication.
|
|
9
|
+
This exposes the entire API structure including endpoints for users, nodes,
|
|
10
|
+
files, webform submissions, and other sensitive resources.
|
|
11
|
+
Attackers can use this to map the application and access sensitive data.
|
|
12
|
+
remediation: |
|
|
13
|
+
Restrict JSON:API access using authentication or disable public access.
|
|
14
|
+
In settings.php or via contrib module like 'jsonapi_extras'.
|
|
15
|
+
reference:
|
|
16
|
+
- https://www.drupal.org/project/drupal/issues/3240913
|
|
17
|
+
- https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/security-considerations
|
|
18
|
+
classification:
|
|
19
|
+
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
|
|
20
|
+
cvss-score: 7.5
|
|
21
|
+
cwe-id: CWE-200
|
|
22
|
+
metadata:
|
|
23
|
+
verified: true
|
|
24
|
+
max-request: 4
|
|
25
|
+
vendor: drupal
|
|
26
|
+
product: drupal
|
|
27
|
+
tags: drupal,exposure,api,jsonapi,misconfig,high
|
|
28
|
+
|
|
29
|
+
http:
|
|
30
|
+
- method: GET
|
|
31
|
+
path:
|
|
32
|
+
# With language prefix
|
|
33
|
+
- "{{BaseURL}}/fr/api"
|
|
34
|
+
- "{{BaseURL}}/en/api"
|
|
35
|
+
- "{{BaseURL}}/ar/api"
|
|
36
|
+
# Without language prefix
|
|
37
|
+
- "{{BaseURL}}/api"
|
|
38
|
+
# Standard jsonapi prefix
|
|
39
|
+
- "{{BaseURL}}/jsonapi"
|
|
40
|
+
- "{{BaseURL}}/fr/jsonapi"
|
|
41
|
+
|
|
42
|
+
stop-at-first-match: true
|
|
43
|
+
|
|
44
|
+
matchers-condition: and
|
|
45
|
+
matchers:
|
|
46
|
+
# Must be JSON:API response with links (index)
|
|
47
|
+
- type: word
|
|
48
|
+
part: body
|
|
49
|
+
words:
|
|
50
|
+
- '"jsonapi"'
|
|
51
|
+
- '"links"'
|
|
52
|
+
condition: and
|
|
53
|
+
|
|
54
|
+
# Must expose sensitive endpoints (not just 403)
|
|
55
|
+
- type: word
|
|
56
|
+
part: body
|
|
57
|
+
words:
|
|
58
|
+
- 'user--user'
|
|
59
|
+
- 'node--'
|
|
60
|
+
- 'file--'
|
|
61
|
+
condition: or
|
|
62
|
+
|
|
63
|
+
# Must NOT be an error response
|
|
64
|
+
- type: word
|
|
65
|
+
part: body
|
|
66
|
+
words:
|
|
67
|
+
- '"errors"'
|
|
68
|
+
negative: true
|
|
69
|
+
|
|
70
|
+
- type: status
|
|
71
|
+
status:
|
|
72
|
+
- 200
|
|
73
|
+
|
|
74
|
+
extractors:
|
|
75
|
+
# Extract exposed resource types
|
|
76
|
+
- type: regex
|
|
77
|
+
name: exposed_endpoints
|
|
78
|
+
group: 1
|
|
79
|
+
regex:
|
|
80
|
+
- '"([a-z_]+--[a-z_]+)":\{"href"'
|
|
81
|
+
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
id: drupal-api-user-detail-exposure
|
|
2
|
+
|
|
3
|
+
info:
|
|
4
|
+
name: Drupal JSON:API User Details Exposed
|
|
5
|
+
author: voidsec
|
|
6
|
+
severity: medium
|
|
7
|
+
description: |
|
|
8
|
+
Individual Drupal user records expose sensitive attributes via JSON:API.
|
|
9
|
+
This can leak usernames, email patterns, and account information.
|
|
10
|
+
remediation: |
|
|
11
|
+
Configure JSON:API permissions to restrict user field access.
|
|
12
|
+
Use jsonapi_extras module to hide sensitive fields.
|
|
13
|
+
reference:
|
|
14
|
+
- https://www.drupal.org/project/drupal/issues/3240913
|
|
15
|
+
- https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/security-considerations
|
|
16
|
+
classification:
|
|
17
|
+
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
|
|
18
|
+
cvss-score: 5.3
|
|
19
|
+
cwe-id: CWE-200
|
|
20
|
+
metadata:
|
|
21
|
+
verified: true
|
|
22
|
+
max-request: 1
|
|
23
|
+
vendor: drupal
|
|
24
|
+
product: drupal
|
|
25
|
+
tags: drupal,exposure,api,jsonapi,user,pii
|
|
26
|
+
|
|
27
|
+
# Usage: nuclei -t drupal-api-user-detail.yaml -u URL -var user_url=<full_user_url>
|
|
28
|
+
# The 'user_url' variable should be passed from the scanner after extracting from API response
|
|
29
|
+
|
|
30
|
+
http:
|
|
31
|
+
- method: GET
|
|
32
|
+
path:
|
|
33
|
+
- "{{user_url}}"
|
|
34
|
+
|
|
35
|
+
matchers-condition: and
|
|
36
|
+
matchers:
|
|
37
|
+
- type: status
|
|
38
|
+
status:
|
|
39
|
+
- 200
|
|
40
|
+
|
|
41
|
+
- type: word
|
|
42
|
+
part: body
|
|
43
|
+
words:
|
|
44
|
+
- '"jsonapi"'
|
|
45
|
+
- '"attributes"'
|
|
46
|
+
condition: and
|
|
47
|
+
|
|
48
|
+
# Check for sensitive attributes being exposed
|
|
49
|
+
- type: word
|
|
50
|
+
part: body
|
|
51
|
+
words:
|
|
52
|
+
- '"display_name"'
|
|
53
|
+
- '"mail"'
|
|
54
|
+
- '"name"'
|
|
55
|
+
- '"created"'
|
|
56
|
+
- '"changed"'
|
|
57
|
+
- '"access"'
|
|
58
|
+
- '"login"'
|
|
59
|
+
condition: or
|
|
60
|
+
|
|
61
|
+
extractors:
|
|
62
|
+
- type: json
|
|
63
|
+
name: display_name
|
|
64
|
+
json:
|
|
65
|
+
- '.data.attributes.display_name'
|
|
66
|
+
|
|
67
|
+
- type: json
|
|
68
|
+
name: username
|
|
69
|
+
json:
|
|
70
|
+
- '.data.attributes.name'
|
|
71
|
+
|
|
72
|
+
- type: json
|
|
73
|
+
name: email
|
|
74
|
+
json:
|
|
75
|
+
- '.data.attributes.mail'
|
|
76
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
id: drupal-api-user-listing
|
|
2
|
+
|
|
3
|
+
info:
|
|
4
|
+
name: Drupal API Username Listing - Detect
|
|
5
|
+
author: voidsec,lixts
|
|
6
|
+
severity: medium
|
|
7
|
+
description: |
|
|
8
|
+
Drupal API username listing was detected. This exposes user display names
|
|
9
|
+
which could be used for targeted attacks or enumeration.
|
|
10
|
+
reference:
|
|
11
|
+
- https://www.drupal.org/project/drupal/issues/3240913
|
|
12
|
+
- https://raw.githubusercontent.com/projectdiscovery/nuclei-templates/refs/heads/main/http/exposures/apis/drupal-jsonapi-user-listing.yaml
|
|
13
|
+
classification:
|
|
14
|
+
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
|
|
15
|
+
cvss-score: 5.3
|
|
16
|
+
cwe-id: CWE-200
|
|
17
|
+
metadata:
|
|
18
|
+
verified: true
|
|
19
|
+
max-request: 2
|
|
20
|
+
vendor: drupal
|
|
21
|
+
product: drupal
|
|
22
|
+
tags: drupal,exposure,discovery,api,user-enum
|
|
23
|
+
|
|
24
|
+
http:
|
|
25
|
+
- method: GET
|
|
26
|
+
path:
|
|
27
|
+
# Custom /api/ prefix (common in decoupled Drupal)
|
|
28
|
+
- "{{BaseURL}}/api/user/user"
|
|
29
|
+
# Standard JSON:API prefix
|
|
30
|
+
- "{{BaseURL}}/jsonapi/user/user"
|
|
31
|
+
|
|
32
|
+
stop-at-first-match: true
|
|
33
|
+
|
|
34
|
+
matchers-condition: and
|
|
35
|
+
matchers:
|
|
36
|
+
- type: regex
|
|
37
|
+
regex:
|
|
38
|
+
- '"display_name"\s*:\s*"[^"]+"'
|
|
39
|
+
- '"name"\s*:\s*"[^"]+"'
|
|
40
|
+
condition: or
|
|
41
|
+
|
|
42
|
+
- type: status
|
|
43
|
+
status:
|
|
44
|
+
- 200
|
|
45
|
+
|
|
46
|
+
- type: word
|
|
47
|
+
part: header
|
|
48
|
+
words:
|
|
49
|
+
- "application/json"
|
|
50
|
+
- "application/vnd.api+json"
|
|
51
|
+
condition: or
|
|
52
|
+
|
|
53
|
+
extractors:
|
|
54
|
+
- type: json
|
|
55
|
+
name: usernames
|
|
56
|
+
json:
|
|
57
|
+
- '.data[].attributes.display_name'
|
|
58
|
+
- '.data[].attributes.name'
|
|
59
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
id: drupal-dev-files-exposed
|
|
2
|
+
|
|
3
|
+
info:
|
|
4
|
+
name: Drupal Development Files Exposed
|
|
5
|
+
author: voidsec
|
|
6
|
+
severity: low
|
|
7
|
+
description: |
|
|
8
|
+
Development and configuration files are publicly accessible.
|
|
9
|
+
These files can reveal project structure, dependencies, and
|
|
10
|
+
configuration that aids attackers in reconnaissance.
|
|
11
|
+
remediation: |
|
|
12
|
+
Block access to development files in web server configuration.
|
|
13
|
+
Add to nginx: location ~* \.(lock|properties)$ { deny all; }
|
|
14
|
+
reference:
|
|
15
|
+
- https://www.drupal.org/docs/security-in-drupal
|
|
16
|
+
classification:
|
|
17
|
+
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
|
|
18
|
+
cvss-score: 5.3
|
|
19
|
+
cwe-id: CWE-538
|
|
20
|
+
metadata:
|
|
21
|
+
verified: true
|
|
22
|
+
max-request: 8
|
|
23
|
+
vendor: drupal
|
|
24
|
+
product: drupal
|
|
25
|
+
tags: drupal,exposure,config,devfiles,misconfig
|
|
26
|
+
|
|
27
|
+
http:
|
|
28
|
+
- method: GET
|
|
29
|
+
path:
|
|
30
|
+
- "{{BaseURL}}/cghooks.lock"
|
|
31
|
+
- "{{BaseURL}}/sonar-project.properties"
|
|
32
|
+
- "{{BaseURL}}/core/yarn.lock"
|
|
33
|
+
- "{{BaseURL}}/yarn.lock"
|
|
34
|
+
- "{{BaseURL}}/package-lock.json"
|
|
35
|
+
- "{{BaseURL}}/composer.lock"
|
|
36
|
+
- "{{BaseURL}}/.gitlab-ci.yml"
|
|
37
|
+
- "{{BaseURL}}/.github/workflows/main.yml"
|
|
38
|
+
|
|
39
|
+
stop-at-first-match: false
|
|
40
|
+
|
|
41
|
+
matchers-condition: and
|
|
42
|
+
matchers:
|
|
43
|
+
- type: status
|
|
44
|
+
status:
|
|
45
|
+
- 200
|
|
46
|
+
|
|
47
|
+
# Content indicators for each file type
|
|
48
|
+
- type: word
|
|
49
|
+
part: body
|
|
50
|
+
words:
|
|
51
|
+
- '"pre-commit"' # cghooks.lock
|
|
52
|
+
- 'sonar.projectKey' # sonar-project.properties
|
|
53
|
+
- '# yarn lockfile' # yarn.lock
|
|
54
|
+
- '"lockfileVersion"' # package-lock.json
|
|
55
|
+
- '"_readme"' # composer.lock
|
|
56
|
+
- 'stages:' # gitlab-ci
|
|
57
|
+
- 'runs-on:' # github actions
|
|
58
|
+
condition: or
|
|
59
|
+
|
|
60
|
+
extractors:
|
|
61
|
+
# Extract project identifiers (NOT all package names)
|
|
62
|
+
- type: regex
|
|
63
|
+
name: sonar_project
|
|
64
|
+
regex:
|
|
65
|
+
- 'sonar\.projectKey=([^\s]+)'
|
|
66
|
+
- 'sonar\.projectName=([^\s]+)'
|
|
67
|
+
|
|
68
|
+
# For composer.lock - just confirm it's a Drupal project
|
|
69
|
+
- type: regex
|
|
70
|
+
name: drupal_version
|
|
71
|
+
regex:
|
|
72
|
+
- '"drupal/core":\s*\{\s*"version":\s*"([^"]+)"'
|
|
73
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
id: drupal-file-path-disclosure
|
|
2
|
+
|
|
3
|
+
info:
|
|
4
|
+
name: Drupal File Path Disclosure in 403 Response
|
|
5
|
+
author: voidsec
|
|
6
|
+
severity: medium
|
|
7
|
+
description: |
|
|
8
|
+
The /file/{id}/download endpoint returns 403 Access Denied but leaks
|
|
9
|
+
the actual filename in the error message (e.g., "Access to file
|
|
10
|
+
public://2023-02/document.pdf denied"). An attacker can use this to
|
|
11
|
+
discover file paths and access them directly via /sites/default/files/.
|
|
12
|
+
remediation: |
|
|
13
|
+
Customize error messages to not include file paths.
|
|
14
|
+
Use hook_file_download() to return generic access denied messages.
|
|
15
|
+
reference:
|
|
16
|
+
- https://www.drupal.org/docs/security-in-drupal/writing-secure-code-for-drupal
|
|
17
|
+
classification:
|
|
18
|
+
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
|
|
19
|
+
cvss-score: 5.3
|
|
20
|
+
cwe-id: CWE-200
|
|
21
|
+
metadata:
|
|
22
|
+
verified: true
|
|
23
|
+
max-request: 6
|
|
24
|
+
vendor: drupal
|
|
25
|
+
product: drupal
|
|
26
|
+
tags: drupal,exposure,file,path-disclosure,info-leak
|
|
27
|
+
|
|
28
|
+
http:
|
|
29
|
+
- method: GET
|
|
30
|
+
path:
|
|
31
|
+
- "{{BaseURL}}/file/1/download"
|
|
32
|
+
- "{{BaseURL}}/fr/file/1/download"
|
|
33
|
+
- "{{BaseURL}}/en/file/1/download"
|
|
34
|
+
- "{{BaseURL}}/ar/file/1/download"
|
|
35
|
+
- "{{BaseURL}}/file/2/download"
|
|
36
|
+
- "{{BaseURL}}/fr/file/2/download"
|
|
37
|
+
|
|
38
|
+
stop-at-first-match: true
|
|
39
|
+
|
|
40
|
+
matchers-condition: and
|
|
41
|
+
matchers:
|
|
42
|
+
- type: status
|
|
43
|
+
status:
|
|
44
|
+
- 403
|
|
45
|
+
|
|
46
|
+
- type: word
|
|
47
|
+
part: body
|
|
48
|
+
words:
|
|
49
|
+
- "public://"
|
|
50
|
+
- "Access to file"
|
|
51
|
+
condition: and
|
|
52
|
+
|
|
53
|
+
extractors:
|
|
54
|
+
- type: regex
|
|
55
|
+
name: disclosed_path
|
|
56
|
+
group: 1
|
|
57
|
+
regex:
|
|
58
|
+
- 'public://([^\s"<>]+)'
|
|
59
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
id: drupal-files-listing
|
|
2
|
+
|
|
3
|
+
info:
|
|
4
|
+
name: Drupal Files Directory Listing
|
|
5
|
+
author: voidsec
|
|
6
|
+
severity: medium
|
|
7
|
+
description: |
|
|
8
|
+
The Drupal /sites/default/files/ directory has listing enabled or is
|
|
9
|
+
directly accessible. This can expose uploaded files, private documents,
|
|
10
|
+
and potentially sensitive information.
|
|
11
|
+
remediation: |
|
|
12
|
+
Disable directory listing in web server configuration.
|
|
13
|
+
For Nginx: autoindex off;
|
|
14
|
+
For Apache: Options -Indexes
|
|
15
|
+
reference:
|
|
16
|
+
- https://www.drupal.org/docs/security-in-drupal/writing-secure-code-for-drupal
|
|
17
|
+
classification:
|
|
18
|
+
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
|
|
19
|
+
cvss-score: 5.3
|
|
20
|
+
cwe-id: CWE-548
|
|
21
|
+
metadata:
|
|
22
|
+
verified: true
|
|
23
|
+
max-request: 6
|
|
24
|
+
vendor: drupal
|
|
25
|
+
product: drupal
|
|
26
|
+
tags: drupal,exposure,listing,files,misconfig
|
|
27
|
+
|
|
28
|
+
http:
|
|
29
|
+
- method: GET
|
|
30
|
+
path:
|
|
31
|
+
# Standard Drupal files path
|
|
32
|
+
- "{{BaseURL}}/sites/default/files/"
|
|
33
|
+
# With language prefix
|
|
34
|
+
- "{{BaseURL}}/fr/sites/default/files/"
|
|
35
|
+
- "{{BaseURL}}/en/sites/default/files/"
|
|
36
|
+
# Alternative paths
|
|
37
|
+
- "{{BaseURL}}/files/"
|
|
38
|
+
- "{{BaseURL}}/sites/files/"
|
|
39
|
+
|
|
40
|
+
stop-at-first-match: true
|
|
41
|
+
|
|
42
|
+
matchers-condition: and
|
|
43
|
+
matchers:
|
|
44
|
+
# Directory listing indicators
|
|
45
|
+
- type: word
|
|
46
|
+
part: body
|
|
47
|
+
words:
|
|
48
|
+
- "Index of"
|
|
49
|
+
- "Directory listing"
|
|
50
|
+
- "<title>Index of"
|
|
51
|
+
- "Parent Directory"
|
|
52
|
+
condition: or
|
|
53
|
+
|
|
54
|
+
- type: status
|
|
55
|
+
status:
|
|
56
|
+
- 200
|
|
57
|
+
|
|
58
|
+
extractors:
|
|
59
|
+
- type: regex
|
|
60
|
+
name: files_found
|
|
61
|
+
regex:
|
|
62
|
+
- 'href="([^"]+\.(pdf|doc|docx|xls|xlsx|zip|sql|bak|txt|log))"'
|
|
63
|
+
|