Skip to content

Commit 17536ad

Browse files
committed
SQLiPlugin: Use Comparable Response instead of Response Matcher
Signed-off-by: ganesh-dagadi <[email protected]>
1 parent dcee0ee commit 17536ad

File tree

6 files changed

+224
-197
lines changed

6 files changed

+224
-197
lines changed

addOns/sqliplugin/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
77
### Changed
88
- Update minimum ZAP version to 2.14.0.
99
- Maintenance changes.
10+
- Changed ResponseMatcher to ComparableResponse for assessing similarity between responses.
1011

1112
## [15] - 2021-10-20
1213
### Fixed

addOns/sqliplugin/sqliplugin.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ crowdin {
3333

3434
dependencies {
3535
zapAddOn("commonlib")
36-
36+
testImplementation(project(":testutils"))
3737
implementation("org.jdom:jdom:2.0.2")
3838
}
3939

addOns/sqliplugin/src/main/java/org/zaproxy/zap/extension/sqliplugin/ResponseMatcher.java

Lines changed: 0 additions & 163 deletions
This file was deleted.

addOns/sqliplugin/src/main/java/org/zaproxy/zap/extension/sqliplugin/SQLInjectionScanRule.java

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.parosproxy.paros.network.HttpHeader;
3939
import org.parosproxy.paros.network.HttpMessage;
4040
import org.zaproxy.addon.commonlib.CommonAlertTag;
41+
import org.zaproxy.addon.commonlib.http.ComparableResponse;
4142
import org.zaproxy.zap.model.Tech;
4243
import org.zaproxy.zap.model.TechSet;
4344

@@ -54,6 +55,10 @@ public class SQLInjectionScanRule extends AbstractAppParamPlugin {
5455
// ------------------------------------------------------------------
5556
// Plugin Constants
5657
// ------------------------------------------------------------------
58+
59+
// Similarity ratio required to determine if two responses are similar (used in boolean based
60+
// blind check)
61+
private static final double REQUIRED_SIMILARITY = 0.90;
5762
// Coefficient used for a time-based query delay checking (must be >= 7)
5863
public static final int TIME_STDEV_COEFF = 7;
5964
// Standard deviation after which a warning message should be displayed about connection lags
@@ -114,7 +119,7 @@ public class SQLInjectionScanRule extends AbstractAppParamPlugin {
114119
private static final Pattern randstrPattern = Pattern.compile("\\[RANDSTR(?:\\d+)?\\]");
115120

116121
// Internal dynamic properties
117-
private final ResponseMatcher responseMatcher;
122+
private ComparableResponse originalResponse;
118123
private final List<Long> responseTimes;
119124

120125
private int lastRequestUID;
@@ -131,7 +136,6 @@ public class SQLInjectionScanRule extends AbstractAppParamPlugin {
131136
*/
132137
public SQLInjectionScanRule() {
133138
responseTimes = new ArrayList<>();
134-
responseMatcher = new ResponseMatcher();
135139
lastRequestUID = 0;
136140
lastErrorPageUID = -1;
137141
}
@@ -601,6 +605,7 @@ public void scan(HttpMessage msg, String parameter, String value) {
601605
// each plugin execution, then we have to work
602606
// with message copies and use getNewMsg()
603607
origMsg = getBaseMsg();
608+
originalResponse = new ComparableResponse(origMsg, null);
604609

605610
// Threat the parameter original value according to the
606611
// test's <where> tag
@@ -639,7 +644,7 @@ public void scan(HttpMessage msg, String parameter, String value) {
639644
// exit the plugin
640645
return;
641646
}
642-
647+
originalResponse = new ComparableResponse(origMsg, payloadValue);
643648
break;
644649

645650
case SQLiPayloadManager.WHERE_REPLACE:
@@ -678,12 +683,10 @@ public void scan(HttpMessage msg, String parameter, String value) {
678683

679684
// prepare string diff matcher
680685
// cleaned by reflective values
681-
// and according to the replacement
682-
// logic set by the plugin
683686
content = origMsg.getResponseBody().toString();
684687
content = SQLiPayloadManager.removeReflectiveValues(content, payloadValue);
685-
responseMatcher.setOriginalResponse(content);
686-
responseMatcher.setLogic(where);
688+
origMsg.setResponseBody(content);
689+
originalResponse = new ComparableResponse(origMsg, payloadValue);
687690

688691
// -----------------------------------------------
689692
// Check 1: Boolean-based blind SQL injection
@@ -710,7 +713,7 @@ public void scan(HttpMessage msg, String parameter, String value) {
710713
cmpPayload = payloadValue + cmpPayload;
711714

712715
// Send False payload
713-
// Useful to set first matchRatio on
716+
// Useful to tune original to
714717
// the False response content
715718
tempMsg = sendPayload(parameter, cmpPayload, true);
716719
if (tempMsg == null) {
@@ -722,9 +725,11 @@ public void scan(HttpMessage msg, String parameter, String value) {
722725
content = tempMsg.getResponseBody().toString();
723726
content =
724727
SQLiPayloadManager.removeReflectiveValues(content, cmpPayload);
725-
responseMatcher.setInjectedResponse(content);
726-
// set initial matchRatio
727-
responseMatcher.isComparable();
728+
tempMsg.setResponseBody(content);
729+
730+
ComparableResponse tempResponse =
731+
new ComparableResponse(tempMsg, cmpPayload);
732+
originalResponse.tuneHeuristicsWithResponse(tempResponse);
728733

729734
// Perform the test's True request
730735
tempMsg = sendPayload(parameter, reqPayload, true);
@@ -737,13 +742,12 @@ public void scan(HttpMessage msg, String parameter, String value) {
737742
content = tempMsg.getResponseBody().toString();
738743
content =
739744
SQLiPayloadManager.removeReflectiveValues(content, reqPayload);
740-
responseMatcher.setInjectedResponse(content);
741-
745+
tempMsg.setResponseBody(content);
746+
tempResponse = new ComparableResponse(tempMsg, reqPayload);
742747
// Check if the TRUE response is equal or
743748
// at less strongly comparable respect to
744749
// the Original response value
745-
if (responseMatcher.isComparable()) {
746-
750+
if (this.isComparableToOriginal(tempResponse)) {
747751
// Perform again the test's False request
748752
tempMsg = sendPayload(parameter, cmpPayload, true);
749753
if (tempMsg == null) {
@@ -756,13 +760,14 @@ public void scan(HttpMessage msg, String parameter, String value) {
756760
content =
757761
SQLiPayloadManager.removeReflectiveValues(
758762
content, cmpPayload);
759-
responseMatcher.setInjectedResponse(content);
763+
tempMsg.setResponseBody(content);
764+
tempResponse = new ComparableResponse(tempMsg, cmpPayload);
760765

761766
// Now check if the FALSE response is
762767
// completely different from the
763768
// Original response according to the
764-
// responseMatcher ratio criteria
765-
if (!responseMatcher.isComparable()) {
769+
// required ratio criteria
770+
if (!this.isComparableToOriginal(tempResponse)) {
766771
// We Found IT!
767772
// Now create the alert message
768773
String info =
@@ -1195,20 +1200,26 @@ public boolean wasLastRequestDBMSError() {
11951200
* @param pageContent the content that need to be compared
11961201
* @return true if similar, false otherwise
11971202
*/
1198-
protected boolean isComparableToOriginal(String pageContent) {
1199-
responseMatcher.setInjectedResponse(pageContent);
1200-
return responseMatcher.isComparable();
1201-
}
12021203

12031204
/**
12041205
* Get the page comparison ration against the original content
12051206
*
1206-
* @param pageContent the content that need to be compared
1207+
* @param ComparableResponse that need to be compared
12071208
* @return a ratio value for this comparison
12081209
*/
1209-
protected double compareToOriginal(String pageContent) {
1210-
responseMatcher.setInjectedResponse(pageContent);
1211-
return responseMatcher.getQuickRatio();
1210+
protected double compareToOriginal(ComparableResponse response) {
1211+
return originalResponse.compareWith(response);
1212+
}
1213+
1214+
/**
1215+
* Check if the response is similar to original Response
1216+
*
1217+
* @param ComparableResponse that need to be compared
1218+
* @return boolean indicating similar (true) or not similar(false)
1219+
*/
1220+
protected boolean isComparableToOriginal(ComparableResponse otherResponse) {
1221+
float similarity = originalResponse.compareWith(otherResponse);
1222+
return similarity >= REQUIRED_SIMILARITY;
12121223
}
12131224

12141225
/**

0 commit comments

Comments
 (0)