Skip to content

Commit

Permalink
ascanrulesBeta: Add more example alerts
Browse files Browse the repository at this point in the history
- CHANGELOG > Add change notes.
- Scan rules > Add example alert functionality (6119).
- Unit tests > Assert the new example alerts.
- Messages.properties > Updated some http references (8262).

Signed-off-by: kingthorin <[email protected]>
  • Loading branch information
kingthorin committed Feb 13, 2024
1 parent 8455e68 commit a1f5eb7
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 76 deletions.
12 changes: 10 additions & 2 deletions addOns/ascanrulesBeta/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Unreleased
### Changed
- The Backup File Disclosure scan rule now includes example alert functionality for documentation generation purposes (Issue 6119).
- Updated reference for scan rule: Session Fixation (Issue 8262)
- The following scan rules now include example alert functionality for documentation generation purposes (Issue 6119):
- Backup File Disclosure
- Httpoxy - Proxy Header Misuse
- Anti-CSRF Tokens Check
- HTTP Parameter Pollution
- Cross-Domain Misconfiguration
- Alerts from the HTTP Parameter Pollution scan rule are now raised with Low confidence.
- Updated reference for scan rules (Issue 8262):
- Session Fixation
- Cross-Domain Misconfiguration
- Add website alert links to the help page (Issue 8189).

## [50] - 2024-01-26
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
Expand Down Expand Up @@ -192,21 +193,7 @@ private void scanAdobeCrossdomainPolicyFile(URI originalURI)
String domain = exprAllowAccessFromDomainNodes.item(i).getNodeValue();
if (domain.equals("*")) {
// oh dear me.
newAlert()
.setConfidence(Alert.CONFIDENCE_MEDIUM)
.setName(
Constant.messages.getString(MESSAGE_PREFIX_ADOBE_READ + "name"))
.setDescription(
Constant.messages.getString(MESSAGE_PREFIX_ADOBE + "desc"))
.setOtherInfo(
Constant.messages.getString(
MESSAGE_PREFIX_ADOBE_READ + "extrainfo",
"/" + ADOBE_CROSS_DOMAIN_POLICY_FILE))
.setSolution(
Constant.messages.getString(MESSAGE_PREFIX_ADOBE_READ + "soln"))
.setEvidence("<allow-access-from domain=\"*\"")
.setMessage(crossdomainmessage)
.raise();
buildAdobeReadAlert().setMessage(crossdomainmessage).raise();
}
}
// check for cross domain send (upload) access
Expand All @@ -223,21 +210,7 @@ private void scanAdobeCrossdomainPolicyFile(URI originalURI)
String domain = exprRequestHeadersFromDomainNodes.item(i).getNodeValue();
if (domain.equals("*")) {
// oh dear, dear me.
newAlert()
.setConfidence(Alert.CONFIDENCE_MEDIUM)
.setName(
Constant.messages.getString(MESSAGE_PREFIX_ADOBE_SEND + "name"))
.setDescription(
Constant.messages.getString(MESSAGE_PREFIX_ADOBE + "desc"))
.setOtherInfo(
Constant.messages.getString(
MESSAGE_PREFIX_ADOBE_SEND + "extrainfo",
"/" + ADOBE_CROSS_DOMAIN_POLICY_FILE))
.setSolution(
Constant.messages.getString(MESSAGE_PREFIX_ADOBE_SEND + "soln"))
.setEvidence("<allow-http-request-headers-from domain=\"*\"")
.setMessage(crossdomainmessage)
.raise();
buildAdobeSendAlert().setMessage(crossdomainmessage).raise();
}
}
} catch (SAXException | IOException e) {
Expand All @@ -249,6 +222,35 @@ private void scanAdobeCrossdomainPolicyFile(URI originalURI)
}
}

private AlertBuilder buildAdobeAlert(String ref) {
return newAlert()
.setConfidence(Alert.CONFIDENCE_MEDIUM)
.setDescription(Constant.messages.getString(MESSAGE_PREFIX_ADOBE + "desc"))
.setAlertRef(getId() + ref);
}

private AlertBuilder buildAdobeReadAlert() {
return buildAdobeAlert("-1")
.setName(Constant.messages.getString(MESSAGE_PREFIX_ADOBE_READ + "name"))
.setOtherInfo(
Constant.messages.getString(
MESSAGE_PREFIX_ADOBE_READ + "extrainfo",
"/" + ADOBE_CROSS_DOMAIN_POLICY_FILE))
.setSolution(Constant.messages.getString(MESSAGE_PREFIX_ADOBE_READ + "soln"))
.setEvidence("<allow-access-from domain=\"*\"");
}

private AlertBuilder buildAdobeSendAlert() {
return buildAdobeAlert("-2")
.setName(Constant.messages.getString(MESSAGE_PREFIX_ADOBE_SEND + "name"))
.setOtherInfo(
Constant.messages.getString(
MESSAGE_PREFIX_ADOBE_SEND + "extrainfo",
"/" + ADOBE_CROSS_DOMAIN_POLICY_FILE))
.setSolution(Constant.messages.getString(MESSAGE_PREFIX_ADOBE_SEND + "soln"))
.setEvidence("<allow-http-request-headers-from domain=\"*\"");
}

private void scanSilverlightCrossdomainPolicyFile(URI originalURI)
throws IOException, XPathExpressionException {
// retrieve the Silverlight client access policy file, and assess it.
Expand Down Expand Up @@ -292,23 +294,7 @@ private void scanSilverlightCrossdomainPolicyFile(URI originalURI)
LOGGER.debug(
"Bingo! {}, at /access-policy/cross-domain-access/policy/allow-from/domain/@uri",
SILVERLIGHT_CROSS_DOMAIN_POLICY_FILE);
newAlert()
.setConfidence(Alert.CONFIDENCE_MEDIUM)
.setName(
Constant.messages.getString(
MESSAGE_PREFIX_SILVERLIGHT + "name"))
.setDescription(
Constant.messages.getString(
MESSAGE_PREFIX_SILVERLIGHT + "desc"))
.setOtherInfo(
Constant.messages.getString(
MESSAGE_PREFIX_SILVERLIGHT + "extrainfo"))
.setSolution(
Constant.messages.getString(
MESSAGE_PREFIX_SILVERLIGHT + "soln"))
.setEvidence("<domain uri=\"*\"")
.setMessage(clientaccesspolicymessage)
.raise();
buildSilverlightAlert().setMessage(clientaccesspolicymessage).raise();
}
}

Expand All @@ -321,6 +307,17 @@ private void scanSilverlightCrossdomainPolicyFile(URI originalURI)
}
}

private AlertBuilder buildSilverlightAlert() {
return newAlert()
.setConfidence(Alert.CONFIDENCE_MEDIUM)
.setName(Constant.messages.getString(MESSAGE_PREFIX_SILVERLIGHT + "name"))
.setDescription(Constant.messages.getString(MESSAGE_PREFIX_SILVERLIGHT + "desc"))
.setOtherInfo(Constant.messages.getString(MESSAGE_PREFIX_SILVERLIGHT + "extrainfo"))
.setSolution(Constant.messages.getString(MESSAGE_PREFIX_SILVERLIGHT + "soln"))
.setEvidence("<domain uri=\"*\"")
.setAlertRef(getId() + "-3");
}

@Override
public int getRisk() {
return Alert.RISK_HIGH;
Expand All @@ -341,4 +338,12 @@ public int getWascId() {
public Map<String, String> getAlertTags() {
return ALERT_TAGS;
}

@Override
public List<Alert> getExampleAlerts() {
return List.of(
buildAdobeReadAlert().build(),
buildAdobeSendAlert().build(),
buildSilverlightAlert().build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,7 @@ public void scan() {
Constant.messages.getString(
MESSAGE_PREFIX + "extrainfo.annotation");
}
newAlert()
.setRisk(risk)
.setConfidence(Alert.CONFIDENCE_MEDIUM)
.setOtherInfo(otherInfo)
.setEvidence(evidence)
.setMessage(getBaseMsg())
.raise();
buildAlert(risk, otherInfo, evidence).setMessage(getBaseMsg()).raise();
}
}

Expand All @@ -237,6 +231,14 @@ public void scan() {
}
}

private AlertBuilder buildAlert(int risk, String otherInfo, String evidence) {
return newAlert()
.setRisk(risk)
.setConfidence(Alert.CONFIDENCE_MEDIUM)
.setOtherInfo(otherInfo)
.setEvidence(evidence);
}

private boolean formOnIgnoreList(Element formElement) {
String id = formElement.getAttributeValue("id");
String name = formElement.getAttributeValue("name");
Expand Down Expand Up @@ -301,4 +303,14 @@ public int getWascId() {
public Map<String, String> getAlertTags() {
return ALERT_TAGS;
}

@Override
public List<Alert> getExampleAlerts() {
return List.of(
buildAlert(
Alert.RISK_MEDIUM,
"",
"<input type=\"hidden\" name=\"firstName\" value=\"\">")
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -142,13 +143,10 @@ public void scan() {

if (listener.isMsgReceived()) {
// the server is vulnerable
newAlert()
.setConfidence(Alert.CONFIDENCE_HIGH)
.setUri(getBaseMsg().getRequestHeader().getURI().toString())
.setAttack(HttpFieldsNames.PROXY + ": " + hostPort)
.setOtherInfo(
Constant.messages.getString(
MESSAGE_PREFIX + "otherinfo", listener.getMsgUrl()))
buildAlert(
hostPort,
getBaseMsg().getRequestHeader().getURI().toString(),
listener.getMsgUrl())
.setMessage(newRequest)
.raise();

Expand All @@ -162,6 +160,21 @@ public void scan() {
}
}

private AlertBuilder buildAlert(String hostPort, String baseUrl, String url) {
return newAlert()
.setConfidence(Alert.CONFIDENCE_HIGH)
.setUri(baseUrl)
.setAttack(HttpFieldsNames.PROXY + ": " + hostPort)
.setOtherInfo(Constant.messages.getString(MESSAGE_PREFIX + "otherinfo", url));
}

@Override
public List<Alert> getExampleAlerts() {
return List.of(
buildAlert("192.168.0.11:1080", "http://example.com/", "http://192.168.0.11:1080/")
.build());
}

private class HttpoxyListener implements HttpMessageHandler {

private boolean msgReceived;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,20 +278,16 @@ public void generateReport(List<String> vulnLinks) {
vulnParams = vulnParams + ", " + s;
}
LOGGER.debug("Page vulnerable to HPP attacks");
String attack = Constant.messages.getString("ascanbeta.HTTPParamPoll.alert.attack");
newAlert()
.setConfidence(Alert.CONFIDENCE_MEDIUM)
.setName(attack)
.setParam(vulnParams)
.setAttack(attack)
.setMessage(getBaseMsg())
.raise();
buildAlert(vulnParams).setMessage(getBaseMsg()).raise();
}

private AlertBuilder buildAlert(String vulnParams) {
return newAlert().setConfidence(Alert.CONFIDENCE_LOW).setParam(vulnParams);
}

@Override
public int getRisk() {
// TODO Auto-generated method stub
return 0;
return Alert.RISK_INFO;
}

@Override
Expand All @@ -308,4 +304,9 @@ public int getWascId() {
public Map<String, String> getAlertTags() {
return ALERT_TAGS;
}

@Override
public List<Alert> getExampleAlerts() {
return List.of(buildAlert("Id").build());
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
ascanbeta.HTTPParamPoll.alert.attack = HTTP Parameter Pollution
ascanbeta.HTTPParamPoll.desc = HTTP Parameter Pollution (HPP) attacks consist of injecting encoded query string delimiters into other existing parameters. If a web application does not properly sanitize the user input, a malicious user can compromise the logic of the application to perform either client-side or server-side attacks. One consequence of HPP attacks is that the attacker can potentially override existing hard-coded HTTP parameters to modify the behavior of an application, bypass input validation checkpoints, and access and possibly exploit variables that may be out of direct reach.
ascanbeta.HTTPParamPoll.extrainfo = https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/07-Input_Validation_Testing/04-Testing_for_HTTP_Parameter_Pollution
ascanbeta.HTTPParamPoll.name = HTTP Parameter Pollution
Expand Down Expand Up @@ -35,8 +34,7 @@ ascanbeta.crossdomain.adobe.send.extrainfo = The web server permits malicious cr
ascanbeta.crossdomain.adobe.send.name = Cross-Domain Misconfiguration - Adobe - Send
ascanbeta.crossdomain.adobe.send.soln = Configure the crossdomain.xml file to restrict the list of domains that are allowed to make cross-domain send (but not necessarily read) requests to this web server, using <allow-http-request-headers-from domain="example.com" headers="Authorization,X-Blahh">. You should only grant access to "*" (all domains) if you are certain that this service is not vulnerable to Cross Site Request Forgery (CSRF) attacks.
ascanbeta.crossdomain.name = Cross-Domain Misconfiguration
#the refs cannot be customised for each sub-category (Adobe, Silverlight, etc.)
ascanbeta.crossdomain.refs = http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html\nhttp://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/CrossDomain_PolicyFile_Specification.pdf\nhttp://msdn.microsoft.com/en-US/library/cc197955%28v=vs.95%29.aspx\nhttp://msdn.microsoft.com/en-us/library/cc838250%28v=vs.95%29.aspx
ascanbeta.crossdomain.refs = https://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/CrossDomain_PolicyFile_Specification.pdf\nhttps://learn.microsoft.com/en-us/previous-versions/windows/silverlight/dotnet-windows-silverlight/cc197955(v=vs.95)\nhttps://learn.microsoft.com/en-us/previous-versions/windows/silverlight/dotnet-windows-silverlight/cc838250(v=vs.95)
ascanbeta.crossdomain.silverlight.desc = Silverlight based cross-site request forgery may be possible, due to a misconfiguration on the web server.
ascanbeta.crossdomain.silverlight.extrainfo = The web server permits malicious cross-domain requests originating from Silverlight components served from any third party domain, to this domain. If the victim user is logged into this service, the malicious requests are processed using the privileges of the victim, and can result in data from this service being compromised by an unauthorised third party web site, via the victim's web browsers. It can also result in Cross Site Request Forgery (CSRF) type attacks. This is particularly likely to be an issue if a Cookie based session implementation is in use.
ascanbeta.crossdomain.silverlight.name = Cross-Domain Misconfiguration - Silverlight
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;

import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.parosproxy.paros.core.scanner.Alert;
import org.zaproxy.addon.commonlib.CommonAlertTag;

class CrossDomainScanRuleUnitTest extends ActiveScannerTest<CrossDomainScanRule> {
Expand Down Expand Up @@ -63,4 +65,24 @@ void shouldReturnExpectedMappings() {
tags.get(CommonAlertTag.WSTG_V42_CONF_08_RIA_CROSS_DOMAIN.getTag()),
is(equalTo(CommonAlertTag.WSTG_V42_CONF_08_RIA_CROSS_DOMAIN.getValue())));
}

@Test
void shouldHaveExpectedExampleAlert() {
// Given / When
List<Alert> alerts = rule.getExampleAlerts();
// Then
assertThat(alerts.size(), is(equalTo(3)));
Alert adobeRead = alerts.get(0);
assertThat(adobeRead.getAlertRef(), is(equalTo("20016-1")));
Alert adobeSend = alerts.get(1);
assertThat(adobeSend.getAlertRef(), is(equalTo("20016-2")));
Alert silverlight = alerts.get(2);
assertThat(silverlight.getAlertRef(), is(equalTo("20016-3")));
}

@Test
@Override
public void shouldHaveValidReferences() {
super.shouldHaveValidReferences();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.TreeSet;
import org.apache.commons.httpclient.URIException;
import org.junit.jupiter.api.Test;
import org.parosproxy.paros.core.scanner.Alert;
import org.parosproxy.paros.core.scanner.Plugin.AlertThreshold;
import org.parosproxy.paros.model.Model;
import org.parosproxy.paros.model.OptionsParam;
Expand Down Expand Up @@ -316,6 +317,20 @@ void shouldReturnExpectedMappings() {
is(equalTo(CommonAlertTag.WSTG_V42_SESS_05_CSRF.getValue())));
}

@Test
void shouldHaveExpectedExampleAlert() {
// Given / When
List<Alert> alerts = rule.getExampleAlerts();
// Then
assertThat(alerts.size(), is(equalTo(1)));
}

@Test
@Override
public void shouldHaveValidReferences() {
super.shouldHaveValidReferences();
}

private HttpMessage createMessage(boolean isInScope)
throws URIException, HttpMalformedHeaderException {
HttpMessage msg =
Expand Down
Loading

0 comments on commit a1f5eb7

Please sign in to comment.