Skip to content

Commit 4e3ccf3

Browse files
committed
InsecureHttpMethodScanRule Example Alert Functionality and Alert refs
Added example alert functionality Removed unnecessary import Adheres to google-java style Unnecessary exception Applied spotlessApply Signed-off-by: Brandosp <[email protected]> Added more examples and added Alert refs Signed-off-by: Brandosp <[email protected]>
1 parent 378e2b0 commit 4e3ccf3

File tree

3 files changed

+156
-73
lines changed

3 files changed

+156
-73
lines changed

addOns/ascanrulesBeta/CHANGELOG.md

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

66
## Unreleased
77

8+
### Changed
9+
- The Insecure Http Method Scan rule now includes example alert functionality for documentation generation purposes and added alert refs (Issue 6119).
810

911
## [62] - 2025-09-18
1012
### Added

addOns/ascanrulesBeta/src/main/java/org/zaproxy/zap/extension/ascanrulesBeta/InsecureHttpMethodScanRule.java

Lines changed: 129 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,24 @@ public class InsecureHttpMethodScanRule extends AbstractAppPlugin
113113
ALERT_TAGS = Collections.unmodifiableMap(alertTags);
114114
}
115115

116+
private enum VulnType {
117+
DELETE_METHOD_ENABLED(1),
118+
OTHER_INSECURE_HTTP_METHOD(2),
119+
TRACE_TRACK_REFLECTS_COOKIES(3),
120+
OPEN_PROXY_THIRD_PARTY_CONNECT(4),
121+
INSECURE_WEBDAV_METHOD(5);
122+
123+
private final int ref;
124+
125+
private VulnType(int ref) {
126+
this.ref = ref;
127+
}
128+
129+
public int getRef() {
130+
return this.ref;
131+
}
132+
}
133+
116134
@Override
117135
public int getId() {
118136
return 90028;
@@ -196,23 +214,13 @@ public void scan() {
196214
enabledMethodsSet.remove(
197215
HttpRequestHeader
198216
.DELETE); // We don't actually want to make a DELETE request
199-
newAlert()
200-
.setConfidence(Alert.CONFIDENCE_MEDIUM)
201-
.setName(
202-
Constant.messages.getString(
203-
"ascanbeta.insecurehttpmethod.detailed.name",
204-
HttpRequestHeader.DELETE))
205-
.setDescription(
206-
Constant.messages.getString(
207-
"ascanbeta.insecurehttpmethod.desc",
208-
HttpRequestHeader.DELETE))
209-
.setOtherInfo(
210-
Constant.messages.getString(
211-
"ascanbeta.insecurehttpmethod.extrainfo", allowedmethods))
212-
.setSolution(
213-
Constant.messages.getString("ascanbeta.insecurehttpmethod.soln"))
214-
.setEvidence(HttpRequestHeader.DELETE)
215-
.setMessage(optionsmsg)
217+
buildAlert(
218+
HttpRequestHeader.DELETE,
219+
HttpRequestHeader.DELETE,
220+
allowedmethods,
221+
HttpRequestHeader.DELETE,
222+
optionsmsg,
223+
VulnType.DELETE_METHOD_ENABLED)
216224
.raise();
217225
}
218226

@@ -307,20 +315,14 @@ public void scan() {
307315
if (raiseAlert) {
308316
LOGGER.debug("Raising alert for Insecure HTTP Method");
309317

310-
newAlert()
318+
buildAlert(
319+
insecureMethod,
320+
description,
321+
extraInfo,
322+
evidence,
323+
alertMessage,
324+
VulnType.OTHER_INSECURE_HTTP_METHOD)
311325
.setRisk(riskLevel)
312-
.setConfidence(Alert.CONFIDENCE_MEDIUM)
313-
.setName(
314-
Constant.messages.getString(
315-
"ascanbeta.insecurehttpmethod.detailed.name",
316-
insecureMethod))
317-
.setDescription(description)
318-
.setOtherInfo(extraInfo)
319-
.setSolution(
320-
Constant.messages.getString(
321-
"ascanbeta.insecurehttpmethod.soln"))
322-
.setEvidence(evidence)
323-
.setMessage(alertMessage)
324326
.raise();
325327
}
326328
}
@@ -376,22 +378,14 @@ private void testTraceOrTrack(String method) throws Exception {
376378

377379
// if the response *body* from the TRACE request contains the cookie,we're in business :)
378380
if (msg.getResponseBody().toString().contains(randomcookievalue)) {
379-
newAlert()
380-
.setConfidence(Alert.CONFIDENCE_MEDIUM)
381-
.setName(
382-
Constant.messages.getString(
383-
"ascanbeta.insecurehttpmethod.detailed.name", method))
384-
.setDescription(
385-
Constant.messages.getString(
386-
"ascanbeta.insecurehttpmethod.trace.exploitable.desc", method))
381+
buildAlert(
382+
method,
383+
method,
384+
randomcookievalue,
385+
randomcookievalue,
386+
msg,
387+
VulnType.TRACE_TRACK_REFLECTS_COOKIES)
387388
.setUri(msg.getRequestHeader().getURI().toString())
388-
.setOtherInfo(
389-
Constant.messages.getString(
390-
"ascanbeta.insecurehttpmethod.trace.exploitable.extrainfo",
391-
randomcookievalue))
392-
.setSolution(Constant.messages.getString("ascanbeta.insecurehttpmethod.soln"))
393-
.setEvidence(randomcookievalue)
394-
.setMessage(msg)
395389
.raise();
396390
}
397391
}
@@ -495,25 +489,13 @@ private void handleConnectResponse(
495489
Matcher m = thirdPartyContentPattern.matcher(response);
496490
if (m.matches()) {
497491
LOGGER.debug("Response matches expected third party pattern!");
498-
newAlert()
499-
.setConfidence(Alert.CONFIDENCE_MEDIUM)
500-
.setName(
501-
Constant.messages.getString(
502-
"ascanbeta.insecurehttpmethod.detailed.name",
503-
HttpRequestHeader.CONNECT))
504-
.setDescription(
505-
Constant.messages.getString(
506-
"ascanbeta.insecurehttpmethod.connect.exploitable.desc",
507-
HttpRequestHeader.CONNECT))
508-
.setOtherInfo(
509-
Constant.messages.getString(
510-
"ascanbeta.insecurehttpmethod.connect.exploitable.extrainfo",
511-
thirdpartyHost))
512-
.setSolution(
513-
Constant.messages.getString(
514-
"ascanbeta.insecurehttpmethod.soln"))
515-
.setEvidence(response)
516-
.setMessage(this.getBaseMsg())
492+
buildAlert(
493+
HttpRequestHeader.CONNECT,
494+
HttpRequestHeader.CONNECT,
495+
thirdpartyHost,
496+
response,
497+
this.getBaseMsg(),
498+
VulnType.OPEN_PROXY_THIRD_PARTY_CONNECT)
517499
.raise();
518500
} else {
519501
LOGGER.debug("Response does *not* match expected third party pattern");
@@ -624,16 +606,14 @@ private void testHttpMethod(String httpMethod) throws Exception {
624606
}
625607
try {
626608

627-
newAlert()
609+
buildAlert(
610+
httpMethod,
611+
exploitableDesc,
612+
exploitableExtraInfo,
613+
evidence,
614+
msg,
615+
VulnType.INSECURE_WEBDAV_METHOD)
628616
.setRisk(riskLevel)
629-
.setConfidence(Alert.CONFIDENCE_MEDIUM)
630-
.setName(
631-
Constant.messages.getString(
632-
"ascanbeta.insecurehttpmethod.detailed.name", httpMethod))
633-
.setDescription(exploitableDesc)
634-
.setOtherInfo(exploitableExtraInfo)
635-
.setEvidence(evidence)
636-
.setMessage(msg)
637617
.raise();
638618
} catch (Exception e) {
639619
}
@@ -642,4 +622,80 @@ private void testHttpMethod(String httpMethod) throws Exception {
642622
private static String randomAlphanumeric(int count) {
643623
return RandomStringUtils.secure().nextAlphanumeric(count);
644624
}
625+
626+
private AlertBuilder buildAlert(
627+
String vulnName,
628+
String vulnDesc,
629+
String extraInfo,
630+
String evidence,
631+
HttpMessage msg,
632+
VulnType currentVT) {
633+
return newAlert()
634+
.setConfidence(Alert.CONFIDENCE_MEDIUM)
635+
.setName(
636+
Constant.messages.getString(
637+
"ascanbeta.insecurehttpmethod.detailed.name", vulnName))
638+
.setDescription(vulnDesc)
639+
.setOtherInfo(extraInfo)
640+
.setSolution(Constant.messages.getString("ascanbeta.insecurehttpmethod.soln"))
641+
.setEvidence(evidence)
642+
.setMessage(msg)
643+
.setCweId(getCweId())
644+
.setWascId(getWascId())
645+
.setAlertRef(getId() + "-" + currentVT.getRef());
646+
}
647+
648+
@Override
649+
public List<Alert> getExampleAlerts() {
650+
List<Alert> alerts = new ArrayList<>();
651+
652+
for (VulnType vulnType : VulnType.values()) {
653+
String name = "";
654+
String description = "";
655+
String extraInfo = "";
656+
String evidence = "";
657+
658+
switch (vulnType) {
659+
case DELETE_METHOD_ENABLED:
660+
name = "DELETE Method Enabled";
661+
description = "The server allows the DELETE HTTP method which can be unsafe.";
662+
extraInfo = "DELETE requests could remove resources if exploited.";
663+
evidence = "DELETE";
664+
break;
665+
666+
case OTHER_INSECURE_HTTP_METHOD:
667+
name = "Other Insecure HTTP Method Enabled";
668+
description = "An insecure HTTP method (like PUT or PATCH) is enabled.";
669+
extraInfo = "These methods may allow resource modification.";
670+
evidence = "PUT/PATCH/etc.";
671+
break;
672+
673+
case TRACE_TRACK_REFLECTS_COOKIES:
674+
name = "TRACE/TRACK Reflects Cookies";
675+
description = "The server reflects cookies in TRACE/TRACK responses.";
676+
extraInfo = "Sensitive cookies may be exposed to attackers.";
677+
evidence = "Sample cookie value";
678+
break;
679+
680+
case OPEN_PROXY_THIRD_PARTY_CONNECT:
681+
name = "Open Proxy via CONNECT";
682+
description = "The server allows CONNECT to a third-party host.";
683+
extraInfo = "The server could be abused as an open proxy.";
684+
evidence = "CONNECT to www.example.com";
685+
break;
686+
687+
case INSECURE_WEBDAV_METHOD:
688+
name = "Insecure WebDAV Method Enabled";
689+
description = "A WebDAV method like COPY, LOCK, or MKCOL is enabled.";
690+
extraInfo = "These methods may allow unauthorized resource manipulation.";
691+
evidence = "MKCOL";
692+
break;
693+
}
694+
695+
// Build and add the example alert
696+
alerts.add(buildAlert(name, description, extraInfo, evidence, null, vulnType).build());
697+
}
698+
699+
return alerts;
700+
}
645701
}

addOns/ascanrulesBeta/src/test/java/org/zaproxy/zap/extension/ascanrulesBeta/InsecureHttpMethodScanRuleUnitTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,19 @@
2323
import static org.hamcrest.MatcherAssert.assertThat;
2424
import static org.hamcrest.Matchers.equalTo;
2525
import static org.hamcrest.Matchers.is;
26+
import static org.hamcrest.Matchers.matchesPattern;
27+
import static org.hamcrest.Matchers.notNullValue;
2628

2729
import fi.iki.elonen.NanoHTTPD.IHTTPSession;
2830
import fi.iki.elonen.NanoHTTPD.Method;
2931
import fi.iki.elonen.NanoHTTPD.Response;
32+
import java.util.List;
3033
import java.util.Map;
3134
import org.junit.jupiter.api.Test;
3235
import org.junit.jupiter.params.ParameterizedTest;
3336
import org.junit.jupiter.params.provider.CsvSource;
3437
import org.junit.jupiter.params.provider.ValueSource;
38+
import org.parosproxy.paros.core.scanner.Alert;
3539
import org.parosproxy.paros.network.HttpMessage;
3640
import org.zaproxy.addon.commonlib.CommonAlertTag;
3741
import org.zaproxy.addon.commonlib.PolicyTag;
@@ -139,4 +143,25 @@ void shouldReturnExpectedMappings() {
139143
tags.get(CommonAlertTag.WSTG_V42_CONF_06_HTTP_METHODS.getTag()),
140144
is(equalTo(CommonAlertTag.WSTG_V42_CONF_06_HTTP_METHODS.getValue())));
141145
}
146+
147+
@Test
148+
void shouldHaveExpectedExampleAlert() {
149+
// Given / When
150+
List<Alert> alerts = rule.getExampleAlerts();
151+
// Then
152+
assertThat(alerts.size(), is(equalTo(5)));
153+
// Verify each alert has a non-null name, alertRef, evidence, and PLUGIN_ID-X pattern
154+
for (Alert alert : alerts) {
155+
assertThat(alert.getName(), is(notNullValue()));
156+
assertThat(alert.getAlertRef(), is(notNullValue()));
157+
assertThat(alert.getEvidence(), is(notNullValue()));
158+
assertThat(alert.getAlertRef().trim(), matchesPattern("\\d+-\\d+"));
159+
}
160+
}
161+
162+
@Test
163+
@Override
164+
public void shouldHaveValidReferences() {
165+
super.shouldHaveValidReferences();
166+
}
142167
}

0 commit comments

Comments
 (0)