Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement getMetadata for active JS scripts #442

Merged
merged 1 commit into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Changed
- Use Prettier to format all JavaScript scripts.
- Update the following scripts to implement the `getMetadata()` function:
- active/Cross Site WebSocket Hijacking.js
- active/cve-2019-5418.js
- active/gof_lite.js
- active/JWT None Exploit.js
- active/SSTI.js

## [18] - 2024-01-29
### Added
Expand Down
61 changes: 33 additions & 28 deletions active/Cross Site WebSocket Hijacking.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,45 @@ var Base64 = Java.type("java.util.Base64");
var Random = Java.type("java.util.Random");
var String = Java.type("java.lang.String");
var ByteArray = Java.type("byte[]");
var ScanRuleMetadata = Java.type(
"org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadata"
);
var CommonAlertTag = Java.type("org.zaproxy.addon.commonlib.CommonAlertTag");

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

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

function scanNode(as, msg) {
var target = msg.getRequestHeader().getURI().toString();

// check if this is a WebSocket HTTP Upgrade request (the message should include also "Connection: Upgrade" header if we wanted to check it strictly)
// TODO: in ZAP 2.11 we might use msg.isWebSocketUpgrade() check instead
var upgradeHeader = msg.getRequestHeader().getHeader("Upgrade");
if (!upgradeHeader || upgradeHeader.toLowerCase() !== "websocket") {
// check if this is a WebSocket HTTP Upgrade request
if (msg.isWebSocketUpgrade()) {
if (LOG_DEBUG_MESSAGES) {
print(
"Cross-Site WebSocket Hijacking rule skipped for url=" +
Expand Down Expand Up @@ -102,17 +116,8 @@ function scanNode(as, msg) {
);
}
as.newAlert()
.setRisk(RISK)
.setConfidence(CONFIDENCE)
.setName(TITLE)
.setDescription(DESCRIPTION)
.setParam(target)
.setEvidence(msg.getResponseHeader().getPrimeHeader())
.setOtherInfo(OTHER)
.setSolution(SOLUTION)
.setReference(REFERENCE)
.setCweId(CWEID)
.setWascId(WASCID)
.setMessage(msg)
.raise();
}
Expand Down
62 changes: 34 additions & 28 deletions active/JWT None Exploit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,36 @@ var Cookie = Java.type("java.net.HttpCookie");
var Base64 = Java.type("java.util.Base64");
var String = Java.type("java.lang.String");

// Exploit information, used for raising alerts
var RISK = 3;
var CONFIDENCE = 2;
var TITLE = "JWT None Exploit";
var DESCRIPTION =
"The application's JWT implementation allows for the usage of the 'none' algorithm, which bypasses the JWT hash verification.";
var SOLUTION =
"Use a secure JWT library, and (if your library supports it) restrict the allowed hash algorithms.";
var REFERENCE =
"https://www.sjoerdlangkemper.nl/2016/09/28/attacking-jwt-authentication/";
var CWEID = 347; // CWE-347: Improper Verification of Cryptographic Signature
var WASCID = 15; // WASC-15: Application Misconfiguration
var ScanRuleMetadata = Java.type(
"org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadata"
);
var CommonAlertTag = Java.type("org.zaproxy.addon.commonlib.CommonAlertTag");

function getMetadata() {
return ScanRuleMetadata.fromYaml(`
id: 100026
name: JWT None Exploit
description: >
The application's JWT implementation allows for the usage of the 'none' algorithm,
which bypasses the JWT hash verification.
solution: >
Use a secure JWT library, and (if your library supports it) restrict the allowed hash algorithms.
references:
- https://www.sjoerdlangkemper.nl/2016/09/28/attacking-jwt-authentication/
category: server
risk: high
confidence: medium
cweId: 347 # CWE-347: Improper Verification of Cryptographic Signature, http://cwe.mitre.org/data/definitions/347.html
wascId: 15 # WASC-15: Application Misconfiguration
alertTags:
${CommonAlertTag.OWASP_2021_A01_BROKEN_AC.getTag()}: ${CommonAlertTag.OWASP_2021_A01_BROKEN_AC.getValue()}
${CommonAlertTag.OWASP_2017_A02_BROKEN_AUTH.getTag()}: ${CommonAlertTag.OWASP_2017_A02_BROKEN_AUTH.getValue()}
${CommonAlertTag.WSTG_V42_CRYP_04_WEAK_CRYPTO.getTag()}: ${CommonAlertTag.WSTG_V42_CRYP_04_WEAK_CRYPTO.getValue()}
status: alpha
codeLink: https://github.com/zaproxy/community-scripts/blob/main/active/JWT%20None%20Exploit.js
helpLink: https://www.zaproxy.org/docs/desktop/addons/community-scripts/
`);
}

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

function raise_alert(msg, cookie, payload, as) {
print("Vulnerability found, sending alert");
as.raiseAlert(
RISK,
CONFIDENCE,
TITLE,
DESCRIPTION,
msg.getRequestHeader().getURI().toString(),
"",
"",
"",
SOLUTION,
"Cookie: " + cookie.getName() + "=" + payload,
REFERENCE,
CWEID,
WASCID,
msg
);
as.newAlert()
.setEvidence("Cookie: " + cookie.getName() + "=" + payload)
.setMessage(msg)
.raise();
}
58 changes: 30 additions & 28 deletions active/SSTI.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,36 @@
var LoggerManager = Java.type("org.apache.logging.log4j.LogManager");
var log = LoggerManager.getLogger("SSTI");

// HasMap for alertTags
var HashMap = Java.type("java.util.HashMap");
var ScanRuleMetadata = Java.type(
"org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadata"
);

function getMetadata() {
return ScanRuleMetadata.fromYaml(`
id: 100033
name: Server Side Template Injection
description: >
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.
solution: >
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.
references:
- https://portswigger.net/research/server-side-template-injection
category: injection
risk: high
confidence: medium
cweId: 20 # CWE-20: Improper Input Validation
wascId: 20 # WASC-20: Improper Input Handling
alertTags:
${CommonAlertTag.OWASP_2021_A03_INJECTION.getTag()}: ${CommonAlertTag.OWASP_2021_A03_INJECTION.getValue()}
${CommonAlertTag.OWASP_2017_A01_INJECTION.getTag()}: ${CommonAlertTag.OWASP_2017_A01_INJECTION.getValue()}
${CommonAlertTag.WSTG_V42_INPV_18_SSTI.getTag()}: ${CommonAlertTag.WSTG_V42_INPV_18_SSTI.getValue()}
status: alpha
codeLink: https://github.com/zaproxy/community-scripts/blob/main/active/SSTI.js
helpLink: https://www.zaproxy.org/docs/desktop/addons/community-scripts/
`);
}

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

//Alert variables
var pluginId = 100033;
var alertName = "Server Side Template Injection";
if (badErrors.indexOf(engine) == -1) {
alertName += " - " + toTitleCase(engine);
}
var alertDesc =
"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.";
var alertSol =
"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.";
var alertRef =
"https://portswigger.net/research/server-side-template-injection";
var cweId = 20; // Improper Input Validation
var wascId = 20; // Improper Input Handling
var alertTags = new HashMap();
alertTags.put(
"OWASP_2021_A03",
"https://owasp.org/Top10/A03_2021-Injection/"
);
alertTags.put(
"OWASP_2017_A01",
"https://owasp.org/www-project-top-ten/2017/A1_2017-Injection.html"
);

as.newAlert()
.setAlertId(pluginId)
.setRisk(3)
.setConfidence(confidence)
.setName(alertName)
.setDescription(alertDesc)
.setParam(param)
.setAttack(payload)
.setEvidence(evidence)
.setSolution(alertSol)
.setReference(alertRef)
.setCweId(cweId)
.setWascId(wascId)
.setMessage(msg)
.setTags(alertTags)
.raise();
}

Expand Down
97 changes: 35 additions & 62 deletions active/cve-2019-5418.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
// Note that new active scripts will initially be disabled
// Right click the script in the Scripts tree and select "enable"

// This active scanner script checks for CVE-2019-5418

/**
* Scans a "node", i.e. an individual entry in the Sites Tree.
* The scanNode function will typically be called once for every page.
*
* @param as - the ActiveScan parent object that will do all the core interface tasks
* (i.e.: sending and receiving messages, providing access to Strength and Threshold settings,
* raising alerts, etc.). This is an ScriptsActiveScanner object.
* @param msg - the HTTP Message being scanned. This is an HttpMessage object.
*/
function scanNode(as, msg) {
// Set some details we will need for alerts later
var alertRisk = 3;
var alertConfidence = 2;
var alertTitle = "CVE-2019-5418 - File Content Disclosure";
var alertDesc =
"The application seems to be subject to CVE-2019-5418. \
By sending a specially crafted request it was possible to have the target return \
data from the server file system.";
var alertSolution =
"Upgrade to a version of Ruby/Rails where this issue is fixed. (See references for further details).";
var alertInfo =
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5418\nhttps://github.com/mpgn/CVE-2019-5418";
var cweId = 74; //Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
var wascId = 33; // Path Traversal
var url = msg.getRequestHeader().getURI().toString();
var ScanRuleMetadata = Java.type(
"org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadata"
);
var CommonAlertTag = Java.type("org.zaproxy.addon.commonlib.CommonAlertTag");

function getMetadata() {
return ScanRuleMetadata.fromYaml(`
id: 100029
name: "File Content Disclosure (CVE-2019-5418)"
description: >
The application seems to be subject to CVE-2019-5418.
By sending a specially crafted request it was possible to have the target return
data from the server file system.
solution: >
Upgrade to a version of Ruby/Rails where this issue is fixed. (See references for further details).
references:
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5418
- https://github.com/mpgn/CVE-2019-5418
category: injection
risk: high
confidence: medium
cweId: 74 # CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
wascId: 33 # WASC-33: Path Traversal
alertTags:
${CommonAlertTag.OWASP_2021_A03_INJECTION.getTag()}: ${CommonAlertTag.OWASP_2021_A03_INJECTION.getValue()}
${CommonAlertTag.OWASP_2017_A01_INJECTION.getTag()}: ${CommonAlertTag.OWASP_2017_A01_INJECTION.getValue()}
${CommonAlertTag.WSTG_V42_ATHZ_01_DIR_TRAVERSAL.getTag()}: ${CommonAlertTag.WSTG_V42_ATHZ_01_DIR_TRAVERSAL.getValue()}
status: alpha
codeLink: https://github.com/zaproxy/community-scripts/blob/main/active/cve-2019-5418.js
helpLink: https://www.zaproxy.org/docs/desktop/addons/community-scripts/
`);
}

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

if (re.test(body)) {
as.raiseAlert(
alertRisk,
alertConfidence,
alertTitle,
alertDesc,
url,
"",
"",
alertInfo,
alertSolution,
body.match(re)[0],
cweId,
wascId,
msg2
);
as.newAlert().setEvidence(body.match(re)[0]).setMessage(msg2).raise();
return; // No need to try further
}
// Just in case there's a simple WaF
Expand All @@ -68,24 +59,6 @@ data from the server file system.";
re = /127.0.0.1/g;
body = msg3.getResponseBody().toString();
if (re.test(body)) {
as.raiseAlert(
alertRisk,
alertConfidence,
alertTitle,
alertDesc,
url,
"",
"",
alertInfo,
alertSolution,
body.match(re)[0],
cweId,
wascId,
msg3
);
as.newAlert().setEvidence(body.match(re)[0]).setMessage(msg3).raise();
}
}

function scan(as, msg, param, value) {
//Unused
}
Loading