Skip to content

Commit b360c52

Browse files
authored
Merge pull request #442 from ricekot/active-scripts-metadata
Implement `getMetadata` for active JS scripts
2 parents f83f3f5 + 0b19eaa commit b360c52

File tree

6 files changed

+176
-203
lines changed

6 files changed

+176
-203
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1313

1414
### Changed
1515
- Use Prettier to format all JavaScript scripts.
16+
- Update the following scripts to implement the `getMetadata()` function:
17+
- active/Cross Site WebSocket Hijacking.js
18+
- active/cve-2019-5418.js
19+
- active/gof_lite.js
20+
- active/JWT None Exploit.js
21+
- active/SSTI.js
1622

1723
## [18] - 2024-01-29
1824
### Added

active/Cross Site WebSocket Hijacking.js

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,45 @@ var Base64 = Java.type("java.util.Base64");
4141
var Random = Java.type("java.util.Random");
4242
var String = Java.type("java.lang.String");
4343
var ByteArray = Java.type("byte[]");
44+
var ScanRuleMetadata = Java.type(
45+
"org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadata"
46+
);
47+
var CommonAlertTag = Java.type("org.zaproxy.addon.commonlib.CommonAlertTag");
4448

4549
var LOG_DEBUG_MESSAGES = false; // change to true for more logs
4650

47-
var RISK = 3;
48-
var CONFIDENCE = 2;
49-
var TITLE = "Cross-Site WebSocket Hijacking";
50-
var DESCRIPTION =
51-
"Server accepted WebSocket connection through HTTP Upgrade request with modified Origin header.";
52-
var SOLUTION =
53-
"Validate Origin header on WebSocket connection handshake, to ensure only specified origins are allowed to connect.\
54-
Also, WebSocket handshake should use random tokens, similar to anti CSRF tokens.";
55-
var REFERENCE = "https://tools.ietf.org/html/rfc6455#section-10.2";
56-
var OTHER =
57-
"See also https://portswigger.net/web-security/websockets/cross-site-websocket-hijacking\
58-
or https://christian-schneider.net/CrossSiteWebSocketHijacking.html";
59-
var CWEID = 346; // CWE-346: Origin Validation Error, http://cwe.mitre.org/data/definitions/346.html
60-
var WASCID = 9; // WASC-9 Cross Site Request Forgery, http://projects.webappsec.org/w/page/13246919/Cross%20Site%20Request%20Forgery
51+
function getMetadata() {
52+
return ScanRuleMetadata.fromYaml(`
53+
id: 100025
54+
name: Cross-Site WebSocket Hijacking
55+
description: Server accepted WebSocket connection through HTTP Upgrade request with modified Origin header.
56+
solution: >
57+
Validate Origin header on WebSocket connection handshake, to ensure only specified origins are allowed to connect.
58+
Also, WebSocket handshake should use random tokens, similar to anti CSRF tokens.
59+
references:
60+
- https://tools.ietf.org/html/rfc6455#section-10.2
61+
category: server
62+
risk: high
63+
confidence: medium
64+
cweId: 346 # CWE-346: Origin Validation Error, http://cwe.mitre.org/data/definitions/346.html
65+
wascId: 9 # WASC-9 Cross Site Request Forgery, http://projects.webappsec.org/w/page/13246919/Cross%20Site%20Request%20Forgery
66+
alertTags:
67+
${CommonAlertTag.OWASP_2021_A01_BROKEN_AC.getTag()}: ${CommonAlertTag.OWASP_2021_A01_BROKEN_AC.getValue()}
68+
${CommonAlertTag.OWASP_2017_A05_BROKEN_AC.getTag()}: ${CommonAlertTag.OWASP_2017_A05_BROKEN_AC.getValue()}
69+
${CommonAlertTag.WSTG_V42_CLNT_10_WEBSOCKETS.getTag()}: ${CommonAlertTag.WSTG_V42_CLNT_10_WEBSOCKETS.getValue()}
70+
otherInfo: >
71+
See also https://portswigger.net/web-security/websockets/cross-site-websocket-hijacking
72+
or https://christian-schneider.net/CrossSiteWebSocketHijacking.html
73+
status: alpha
74+
codeLink: https://github.com/zaproxy/community-scripts/blob/main/active/Cross%20Site%20WebSocket%20Hijacking.js
75+
helpLink: https://www.zaproxy.org/docs/desktop/addons/community-scripts/
76+
`);
77+
}
6178

6279
function scanNode(as, msg) {
6380
var target = msg.getRequestHeader().getURI().toString();
64-
65-
// check if this is a WebSocket HTTP Upgrade request (the message should include also "Connection: Upgrade" header if we wanted to check it strictly)
66-
// TODO: in ZAP 2.11 we might use msg.isWebSocketUpgrade() check instead
67-
var upgradeHeader = msg.getRequestHeader().getHeader("Upgrade");
68-
if (!upgradeHeader || upgradeHeader.toLowerCase() !== "websocket") {
81+
// check if this is a WebSocket HTTP Upgrade request
82+
if (msg.isWebSocketUpgrade()) {
6983
if (LOG_DEBUG_MESSAGES) {
7084
print(
7185
"Cross-Site WebSocket Hijacking rule skipped for url=" +
@@ -102,17 +116,8 @@ function scanNode(as, msg) {
102116
);
103117
}
104118
as.newAlert()
105-
.setRisk(RISK)
106-
.setConfidence(CONFIDENCE)
107-
.setName(TITLE)
108-
.setDescription(DESCRIPTION)
109119
.setParam(target)
110120
.setEvidence(msg.getResponseHeader().getPrimeHeader())
111-
.setOtherInfo(OTHER)
112-
.setSolution(SOLUTION)
113-
.setReference(REFERENCE)
114-
.setCweId(CWEID)
115-
.setWascId(WASCID)
116121
.setMessage(msg)
117122
.raise();
118123
}

active/JWT None Exploit.js

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,36 @@ var Cookie = Java.type("java.net.HttpCookie");
44
var Base64 = Java.type("java.util.Base64");
55
var String = Java.type("java.lang.String");
66

7-
// Exploit information, used for raising alerts
8-
var RISK = 3;
9-
var CONFIDENCE = 2;
10-
var TITLE = "JWT None Exploit";
11-
var DESCRIPTION =
12-
"The application's JWT implementation allows for the usage of the 'none' algorithm, which bypasses the JWT hash verification.";
13-
var SOLUTION =
14-
"Use a secure JWT library, and (if your library supports it) restrict the allowed hash algorithms.";
15-
var REFERENCE =
16-
"https://www.sjoerdlangkemper.nl/2016/09/28/attacking-jwt-authentication/";
17-
var CWEID = 347; // CWE-347: Improper Verification of Cryptographic Signature
18-
var WASCID = 15; // WASC-15: Application Misconfiguration
7+
var ScanRuleMetadata = Java.type(
8+
"org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadata"
9+
);
10+
var CommonAlertTag = Java.type("org.zaproxy.addon.commonlib.CommonAlertTag");
11+
12+
function getMetadata() {
13+
return ScanRuleMetadata.fromYaml(`
14+
id: 100026
15+
name: JWT None Exploit
16+
description: >
17+
The application's JWT implementation allows for the usage of the 'none' algorithm,
18+
which bypasses the JWT hash verification.
19+
solution: >
20+
Use a secure JWT library, and (if your library supports it) restrict the allowed hash algorithms.
21+
references:
22+
- https://www.sjoerdlangkemper.nl/2016/09/28/attacking-jwt-authentication/
23+
category: server
24+
risk: high
25+
confidence: medium
26+
cweId: 347 # CWE-347: Improper Verification of Cryptographic Signature, http://cwe.mitre.org/data/definitions/347.html
27+
wascId: 15 # WASC-15: Application Misconfiguration
28+
alertTags:
29+
${CommonAlertTag.OWASP_2021_A01_BROKEN_AC.getTag()}: ${CommonAlertTag.OWASP_2021_A01_BROKEN_AC.getValue()}
30+
${CommonAlertTag.OWASP_2017_A02_BROKEN_AUTH.getTag()}: ${CommonAlertTag.OWASP_2017_A02_BROKEN_AUTH.getValue()}
31+
${CommonAlertTag.WSTG_V42_CRYP_04_WEAK_CRYPTO.getTag()}: ${CommonAlertTag.WSTG_V42_CRYP_04_WEAK_CRYPTO.getValue()}
32+
status: alpha
33+
codeLink: https://github.com/zaproxy/community-scripts/blob/main/active/JWT%20None%20Exploit.js
34+
helpLink: https://www.zaproxy.org/docs/desktop/addons/community-scripts/
35+
`);
36+
}
1937

2038
function b64encode(string) {
2139
// Terminate the string with a null byte prior to encoding. I suspect that
@@ -128,20 +146,8 @@ function scanNode(as, msg) {
128146

129147
function raise_alert(msg, cookie, payload, as) {
130148
print("Vulnerability found, sending alert");
131-
as.raiseAlert(
132-
RISK,
133-
CONFIDENCE,
134-
TITLE,
135-
DESCRIPTION,
136-
msg.getRequestHeader().getURI().toString(),
137-
"",
138-
"",
139-
"",
140-
SOLUTION,
141-
"Cookie: " + cookie.getName() + "=" + payload,
142-
REFERENCE,
143-
CWEID,
144-
WASCID,
145-
msg
146-
);
149+
as.newAlert()
150+
.setEvidence("Cookie: " + cookie.getName() + "=" + payload)
151+
.setMessage(msg)
152+
.raise();
147153
}

active/SSTI.js

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,36 @@
1111
var LoggerManager = Java.type("org.apache.logging.log4j.LogManager");
1212
var log = LoggerManager.getLogger("SSTI");
1313

14-
// HasMap for alertTags
15-
var HashMap = Java.type("java.util.HashMap");
14+
var ScanRuleMetadata = Java.type(
15+
"org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadata"
16+
);
17+
18+
function getMetadata() {
19+
return ScanRuleMetadata.fromYaml(`
20+
id: 100033
21+
name: Server Side Template Injection
22+
description: >
23+
Server Side Template Injection (SSTI) occurs when user input is directly embedded into the template without any
24+
proper sanitization, a hacker can use this vulnerability to inject malicious code and try to achieve remote code execution.
25+
solution: >
26+
Always use proper functions provided by the template engine to insert data,
27+
if that is not possible try to sanitize user input as efficiently as possible.
28+
references:
29+
- https://portswigger.net/research/server-side-template-injection
30+
category: injection
31+
risk: high
32+
confidence: medium
33+
cweId: 20 # CWE-20: Improper Input Validation
34+
wascId: 20 # WASC-20: Improper Input Handling
35+
alertTags:
36+
${CommonAlertTag.OWASP_2021_A03_INJECTION.getTag()}: ${CommonAlertTag.OWASP_2021_A03_INJECTION.getValue()}
37+
${CommonAlertTag.OWASP_2017_A01_INJECTION.getTag()}: ${CommonAlertTag.OWASP_2017_A01_INJECTION.getValue()}
38+
${CommonAlertTag.WSTG_V42_INPV_18_SSTI.getTag()}: ${CommonAlertTag.WSTG_V42_INPV_18_SSTI.getValue()}
39+
status: alpha
40+
codeLink: https://github.com/zaproxy/community-scripts/blob/main/active/SSTI.js
41+
helpLink: https://www.zaproxy.org/docs/desktop/addons/community-scripts/
42+
`);
43+
}
1644

1745
function logger() {
1846
print("[" + this["zap.script.name"] + "] " + arguments[0]);
@@ -168,44 +196,18 @@ function raiseAlert(as, msg, payload, evidence, confidence, param, engine) {
168196
var badErrors = ["Infinity", "INF"];
169197

170198
//Alert variables
171-
var pluginId = 100033;
172199
var alertName = "Server Side Template Injection";
173200
if (badErrors.indexOf(engine) == -1) {
174201
alertName += " - " + toTitleCase(engine);
175202
}
176-
var alertDesc =
177-
"Server Side Template Injection (SSTI) occurs when user input is directly embedded into the template without any proper sanitization, a hacker can use this vulnerability to inject malicious code and try to achieve remote code execution.";
178-
var alertSol =
179-
"Always use proper functions provided by the template engine to insert data, if that is not possible try to sanitize user input as efficiently as possible.";
180-
var alertRef =
181-
"https://portswigger.net/research/server-side-template-injection";
182-
var cweId = 20; // Improper Input Validation
183-
var wascId = 20; // Improper Input Handling
184-
var alertTags = new HashMap();
185-
alertTags.put(
186-
"OWASP_2021_A03",
187-
"https://owasp.org/Top10/A03_2021-Injection/"
188-
);
189-
alertTags.put(
190-
"OWASP_2017_A01",
191-
"https://owasp.org/www-project-top-ten/2017/A1_2017-Injection.html"
192-
);
193203

194204
as.newAlert()
195-
.setAlertId(pluginId)
196-
.setRisk(3)
197205
.setConfidence(confidence)
198206
.setName(alertName)
199-
.setDescription(alertDesc)
200207
.setParam(param)
201208
.setAttack(payload)
202209
.setEvidence(evidence)
203-
.setSolution(alertSol)
204-
.setReference(alertRef)
205-
.setCweId(cweId)
206-
.setWascId(wascId)
207210
.setMessage(msg)
208-
.setTags(alertTags)
209211
.raise();
210212
}
211213

active/cve-2019-5418.js

Lines changed: 35 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,39 @@
1-
// Note that new active scripts will initially be disabled
2-
// Right click the script in the Scripts tree and select "enable"
3-
41
// This active scanner script checks for CVE-2019-5418
52

6-
/**
7-
* Scans a "node", i.e. an individual entry in the Sites Tree.
8-
* The scanNode function will typically be called once for every page.
9-
*
10-
* @param as - the ActiveScan parent object that will do all the core interface tasks
11-
* (i.e.: sending and receiving messages, providing access to Strength and Threshold settings,
12-
* raising alerts, etc.). This is an ScriptsActiveScanner object.
13-
* @param msg - the HTTP Message being scanned. This is an HttpMessage object.
14-
*/
15-
function scanNode(as, msg) {
16-
// Set some details we will need for alerts later
17-
var alertRisk = 3;
18-
var alertConfidence = 2;
19-
var alertTitle = "CVE-2019-5418 - File Content Disclosure";
20-
var alertDesc =
21-
"The application seems to be subject to CVE-2019-5418. \
22-
By sending a specially crafted request it was possible to have the target return \
23-
data from the server file system.";
24-
var alertSolution =
25-
"Upgrade to a version of Ruby/Rails where this issue is fixed. (See references for further details).";
26-
var alertInfo =
27-
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5418\nhttps://github.com/mpgn/CVE-2019-5418";
28-
var cweId = 74; //Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
29-
var wascId = 33; // Path Traversal
30-
var url = msg.getRequestHeader().getURI().toString();
3+
var ScanRuleMetadata = Java.type(
4+
"org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadata"
5+
);
6+
var CommonAlertTag = Java.type("org.zaproxy.addon.commonlib.CommonAlertTag");
7+
8+
function getMetadata() {
9+
return ScanRuleMetadata.fromYaml(`
10+
id: 100029
11+
name: "File Content Disclosure (CVE-2019-5418)"
12+
description: >
13+
The application seems to be subject to CVE-2019-5418.
14+
By sending a specially crafted request it was possible to have the target return
15+
data from the server file system.
16+
solution: >
17+
Upgrade to a version of Ruby/Rails where this issue is fixed. (See references for further details).
18+
references:
19+
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5418
20+
- https://github.com/mpgn/CVE-2019-5418
21+
category: injection
22+
risk: high
23+
confidence: medium
24+
cweId: 74 # CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
25+
wascId: 33 # WASC-33: Path Traversal
26+
alertTags:
27+
${CommonAlertTag.OWASP_2021_A03_INJECTION.getTag()}: ${CommonAlertTag.OWASP_2021_A03_INJECTION.getValue()}
28+
${CommonAlertTag.OWASP_2017_A01_INJECTION.getTag()}: ${CommonAlertTag.OWASP_2017_A01_INJECTION.getValue()}
29+
${CommonAlertTag.WSTG_V42_ATHZ_01_DIR_TRAVERSAL.getTag()}: ${CommonAlertTag.WSTG_V42_ATHZ_01_DIR_TRAVERSAL.getValue()}
30+
status: alpha
31+
codeLink: https://github.com/zaproxy/community-scripts/blob/main/active/cve-2019-5418.js
32+
helpLink: https://www.zaproxy.org/docs/desktop/addons/community-scripts/
33+
`);
34+
}
3135

36+
function scanNode(as, msg) {
3237
var msg2 = msg.cloneRequest();
3338
msg2
3439
.getRequestHeader()
@@ -40,21 +45,7 @@ data from the server file system.";
4045
var body = msg2.getResponseBody().toString();
4146

4247
if (re.test(body)) {
43-
as.raiseAlert(
44-
alertRisk,
45-
alertConfidence,
46-
alertTitle,
47-
alertDesc,
48-
url,
49-
"",
50-
"",
51-
alertInfo,
52-
alertSolution,
53-
body.match(re)[0],
54-
cweId,
55-
wascId,
56-
msg2
57-
);
48+
as.newAlert().setEvidence(body.match(re)[0]).setMessage(msg2).raise();
5849
return; // No need to try further
5950
}
6051
// Just in case there's a simple WaF
@@ -68,24 +59,6 @@ data from the server file system.";
6859
re = /127.0.0.1/g;
6960
body = msg3.getResponseBody().toString();
7061
if (re.test(body)) {
71-
as.raiseAlert(
72-
alertRisk,
73-
alertConfidence,
74-
alertTitle,
75-
alertDesc,
76-
url,
77-
"",
78-
"",
79-
alertInfo,
80-
alertSolution,
81-
body.match(re)[0],
82-
cweId,
83-
wascId,
84-
msg3
85-
);
62+
as.newAlert().setEvidence(body.match(re)[0]).setMessage(msg3).raise();
8663
}
8764
}
88-
89-
function scan(as, msg, param, value) {
90-
//Unused
91-
}

0 commit comments

Comments
 (0)