Skip to content

Commit e90863c

Browse files
committed
ascanrules: address FPs in scan rule 20017
Do not scan binary responses and responses that already contain PHP source. Fix zaproxy/zaproxy#8638. Signed-off-by: thc202 <[email protected]>
1 parent 354c81b commit e90863c

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

addOns/ascanrules/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88
- Maintenance changes.
99
- The Spring Actuator Scan Rule now includes example alert functionality for documentation generation purposes (Issue 6119).
1010

11+
### Fixed
12+
- Address false positives with Source Code Disclosure - CVE-2012-1823 scan rule, by not scanning binary responses and responses that already contain PHP source (Issue 8638).
13+
1114
## [67] - 2024-07-22
1215

1316
### Changed

addOns/ascanrules/src/main/java/org/zaproxy/zap/extension/ascanrules/SourceCodeDisclosureCve20121823ScanRule.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,18 @@ public String getReference() {
121121
public void scan() {
122122
try {
123123

124-
if (!getBaseMsg().getResponseHeader().isText()) {
124+
if (!getBaseMsg().getResponseHeader().isText()
125+
|| ResourceIdentificationUtils.responseContainsControlChars(getBaseMsg())) {
125126
return; // Ignore images, pdfs, etc.
126127
}
127128
if (getAlertThreshold() != AlertThreshold.LOW
128129
&& ResourceIdentificationUtils.isJavaScript(getBaseMsg())) {
129130
return;
130131
}
132+
133+
if (isEvidenceInOriginalResponse()) {
134+
return;
135+
}
131136
// at Low or Medium strength, do not attack URLs which returned "Not Found"
132137
AttackStrength attackStrength = getAttackStrength();
133138
if ((attackStrength == AttackStrength.LOW || attackStrength == AttackStrength.MEDIUM)
@@ -181,6 +186,13 @@ public void scan() {
181186
}
182187
}
183188

189+
private boolean isEvidenceInOriginalResponse() {
190+
var response = getBaseMsg().getResponseBody().toString();
191+
String responseBodyDecoded = new Source(response).getRenderer().toString();
192+
return PHP_PATTERN1.matcher(responseBodyDecoded).matches()
193+
|| PHP_PATTERN2.matcher(responseBodyDecoded).matches();
194+
}
195+
184196
private AlertBuilder buildAlert(String otherInfo) {
185197
return newAlert()
186198
.setConfidence(Alert.CONFIDENCE_MEDIUM)

addOns/ascanrules/src/test/java/org/zaproxy/zap/extension/ascanrules/SourceCodeDisclosureCve20121823ScanRuleUnitTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import java.util.Map;
3232
import org.apache.commons.text.StringEscapeUtils;
3333
import org.junit.jupiter.api.Test;
34+
import org.junit.jupiter.params.ParameterizedTest;
35+
import org.junit.jupiter.params.provider.ValueSource;
3436
import org.parosproxy.paros.core.scanner.Alert;
3537
import org.parosproxy.paros.core.scanner.Plugin.AlertThreshold;
3638
import org.parosproxy.paros.core.scanner.Plugin.AttackStrength;
@@ -253,6 +255,36 @@ protected Response serve(IHTTPSession session) {
253255
assertThat(alertsRaised, hasSize(0));
254256
}
255257

258+
@ParameterizedTest
259+
@ValueSource(strings = {PHP_SOURCE_TAGS, PHP_SOURCE_ECHO_TAG})
260+
void shouldNotScanIfPhpSourceWasAlreadyPresentInResponse(String source) throws Exception {
261+
// Given
262+
var response =
263+
"<html><body>PHP Tutorial: <code>"
264+
+ StringEscapeUtils.escapeHtml4(source)
265+
+ "</code></body></html>";
266+
HttpMessage message = getHttpMessage("GET", "/", response);
267+
rule.init(message, parent);
268+
// When
269+
rule.scan();
270+
// Then
271+
assertThat(httpMessagesSent, hasSize(0));
272+
assertThat(alertsRaised, hasSize(0));
273+
}
274+
275+
@Test
276+
void shouldNotScanBinaryResponse() throws Exception {
277+
// Given
278+
var response = "�PNG\n\n";
279+
HttpMessage message = getHttpMessage("GET", "/", response);
280+
rule.init(message, parent);
281+
// When
282+
rule.scan();
283+
// Then
284+
assertThat(httpMessagesSent, hasSize(0));
285+
assertThat(alertsRaised, hasSize(0));
286+
}
287+
256288
@Test
257289
void shouldAlertIfPhpEchoTagsWereDisclosedInResponseBody() throws Exception {
258290
// Given

0 commit comments

Comments
 (0)