Skip to content

Commit 794c7cd

Browse files
committed
Add Example ascan/pscan rules (Migrated from ext repo)
Signed-off-by: kingthorin <[email protected]>
1 parent 831bfc7 commit 794c7cd

File tree

10 files changed

+836
-2
lines changed

10 files changed

+836
-2
lines changed

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,14 @@ gradle-app.setting
1212

1313
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
1414
# gradle/wrapper/gradle-wrapper.properties
15+
16+
# Misc
17+
#-----
18+
.DS_Store
19+
20+
# Eclipse
21+
# -------
22+
*.classpath
23+
*.project
24+
*.settings
25+
/bin

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ All notable changes to this add-on will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

66
## [Unreleased]
7-
8-
First version
7+
### Changed
8+
- First version

build.gradle.kts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ zapAddOn {
2424
url.set("https://www.zaproxy.org/docs/desktop/addons/addonjava/")
2525
repo.set("https://github.com/zaproxy/addon-java")
2626
changesFile.set(tasks.named<ConvertMarkdownToHtml>("generateManifestChanges").flatMap { it.html })
27+
28+
dependencies {
29+
addOns {
30+
register("commonlib") {
31+
version.set(">= 1.36.0 & < 2.0.0")
32+
}
33+
}
34+
}
2735
}
2836
}
2937

@@ -38,3 +46,7 @@ spotless {
3846
ktlint()
3947
}
4048
}
49+
50+
dependencies {
51+
compileOnly("org.zaproxy.addon:commonlib:1.36.0")
52+
}
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
/*
2+
* Zed Attack Proxy (ZAP) and its related class files.
3+
*
4+
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
5+
*
6+
* Copyright 2014 The ZAP Development Team
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
package com.github.youruser.zap.javaexample;
21+
22+
import java.io.BufferedReader;
23+
import java.io.File;
24+
import java.io.FileReader;
25+
import java.io.IOException;
26+
import java.util.ArrayList;
27+
import java.util.List;
28+
import org.apache.logging.log4j.LogManager;
29+
import org.apache.logging.log4j.Logger;
30+
import org.parosproxy.paros.Constant;
31+
import org.parosproxy.paros.core.scanner.AbstractAppParamPlugin;
32+
import org.parosproxy.paros.core.scanner.Alert;
33+
import org.parosproxy.paros.core.scanner.Category;
34+
import org.parosproxy.paros.core.scanner.Plugin;
35+
import org.parosproxy.paros.network.HttpBody;
36+
import org.parosproxy.paros.network.HttpMessage;
37+
import org.zaproxy.zap.model.Tech;
38+
import org.zaproxy.zap.model.TechSet;
39+
40+
/**
41+
* An example active scan rule, for more details see
42+
* https://www.zaproxy.org/blog/2014-04-30-hacking-zap-4-active-scan-rules/
43+
*
44+
* @author psiinon
45+
*/
46+
public class ExampleFileActiveScanRule extends AbstractAppParamPlugin {
47+
48+
/** Prefix for internationalized messages used by this rule */
49+
private static final String MESSAGE_PREFIX = "javaexample.active.examplefile.";
50+
51+
private static final String exampleAscanFile = "txt/example-ascan-file.txt";
52+
private List<String> strings = null;
53+
private static final Logger LOGGER = LogManager.getLogger(ExampleFileActiveScanRule.class);
54+
55+
@Override
56+
public int getId() {
57+
/*
58+
* This should be unique across all active and passive rules.
59+
* The master list is https://github.com/zaproxy/zaproxy/blob/main/docs/scanners.md
60+
*/
61+
return 60101;
62+
}
63+
64+
@Override
65+
public String getName() {
66+
return Constant.messages.getString(MESSAGE_PREFIX + "name");
67+
}
68+
69+
@Override
70+
public boolean targets(
71+
TechSet technologies) { // This method allows the programmer or user to restrict when a
72+
// scanner is run based on the technologies selected. For example, to restrict the scanner
73+
// to run just when
74+
// C language is selected
75+
return technologies.includes(Tech.C);
76+
}
77+
78+
@Override
79+
public String getDescription() {
80+
return Constant.messages.getString(MESSAGE_PREFIX + "desc");
81+
}
82+
83+
private static String getOtherInfo() {
84+
return Constant.messages.getString(MESSAGE_PREFIX + "other");
85+
}
86+
87+
@Override
88+
public String getSolution() {
89+
return Constant.messages.getString(MESSAGE_PREFIX + "soln");
90+
}
91+
92+
@Override
93+
public String getReference() {
94+
return Constant.messages.getString(MESSAGE_PREFIX + "refs");
95+
}
96+
97+
@Override
98+
public int getCategory() {
99+
return Category.MISC;
100+
}
101+
102+
/*
103+
* This method is called by the active scanner for each GET and POST parameter for every page
104+
* @see org.parosproxy.paros.core.scanner.AbstractAppParamPlugin#scan(org.parosproxy.paros.network.HttpMessage, java.lang.String, java.lang.String)
105+
*/
106+
@Override
107+
public void scan(HttpMessage msg, String param, String value) {
108+
try {
109+
if (!Constant.isDevBuild()) {
110+
// Only run this example scan rule in dev mode
111+
// Uncomment locally if you want to see these alerts in non dev mode ;)
112+
return;
113+
}
114+
115+
if (this.strings == null) {
116+
this.strings = loadFile(exampleAscanFile);
117+
}
118+
// This is where you change the 'good' request to attack the application
119+
// You can make multiple requests if needed
120+
int numAttacks = 0;
121+
122+
switch (this.getAttackStrength()) {
123+
case LOW:
124+
numAttacks = 6;
125+
break;
126+
case MEDIUM:
127+
numAttacks = 12;
128+
break;
129+
case HIGH:
130+
numAttacks = 24;
131+
break;
132+
case INSANE:
133+
numAttacks = 96;
134+
break;
135+
default:
136+
break;
137+
}
138+
139+
for (int i = 0; i < numAttacks; i++) {
140+
if (this.isStop()) {
141+
// User has stopped the scan
142+
break;
143+
}
144+
if (i >= this.strings.size()) {
145+
// run out of attack strings
146+
break;
147+
}
148+
String attack = this.strings.get(i);
149+
// Always use getNewMsg() for each new request
150+
HttpMessage testMsg = getNewMsg();
151+
setParameter(testMsg, param, attack);
152+
sendAndReceive(testMsg);
153+
154+
// This is where you detect potential vulnerabilities in the response
155+
String evidence;
156+
if ((evidence = doesResponseContainString(msg.getResponseBody(), attack)) != null) {
157+
// Raise an alert
158+
createAlert(param, attack, evidence).setMessage(testMsg).raise();
159+
return;
160+
}
161+
}
162+
163+
} catch (IOException e) {
164+
LOGGER.error(e.getMessage(), e);
165+
}
166+
}
167+
168+
private String doesResponseContainString(HttpBody body, String str) {
169+
String sBody;
170+
if (Plugin.AlertThreshold.HIGH.equals(this.getAlertThreshold())) {
171+
// For a high threshold perform a case exact check
172+
sBody = body.toString();
173+
} else {
174+
// For all other thresholds perform a case ignore check
175+
sBody = body.toString().toLowerCase();
176+
}
177+
178+
if (!Plugin.AlertThreshold.HIGH.equals(this.getAlertThreshold())) {
179+
// Use case ignore unless a high threshold has been specified
180+
str = str.toLowerCase();
181+
}
182+
int start = sBody.indexOf(str);
183+
if (start >= 0) {
184+
// Return the original (case exact) string so we can match it in the response
185+
return body.toString().substring(start, start + str.length());
186+
}
187+
return null;
188+
}
189+
190+
private AlertBuilder createAlert(String param, String attack, String evidence) {
191+
return newAlert()
192+
.setConfidence(Alert.CONFIDENCE_MEDIUM)
193+
.setParam(param)
194+
.setAttack(attack)
195+
.setOtherInfo(getOtherInfo())
196+
.setEvidence(evidence);
197+
}
198+
199+
private static List<String> loadFile(String file) {
200+
/*
201+
* ZAP will have already extracted the file from the add-on and put it underneath the 'ZAP home' directory
202+
*/
203+
List<String> strings = new ArrayList<>();
204+
BufferedReader reader = null;
205+
File f = new File(Constant.getZapHome() + File.separator + file);
206+
if (!f.exists()) {
207+
LOGGER.error("No such file: {}", f.getAbsolutePath());
208+
return strings;
209+
}
210+
try {
211+
String line;
212+
reader = new BufferedReader(new FileReader(f));
213+
while ((line = reader.readLine()) != null) {
214+
if (!line.startsWith("#") && line.length() > 0) {
215+
strings.add(line);
216+
}
217+
}
218+
} catch (IOException e) {
219+
LOGGER.error(
220+
"Error on opening/reading example error file. Error: {}", e.getMessage(), e);
221+
} finally {
222+
if (reader != null) {
223+
try {
224+
reader.close();
225+
} catch (IOException e) {
226+
LOGGER.debug("Error on closing the file reader. Error: {}", e.getMessage(), e);
227+
}
228+
}
229+
}
230+
return strings;
231+
}
232+
233+
@Override
234+
public int getRisk() {
235+
return Alert.RISK_HIGH;
236+
}
237+
238+
@Override
239+
public int getCweId() {
240+
// The CWE id
241+
return 0;
242+
}
243+
244+
@Override
245+
public int getWascId() {
246+
// The WASC ID
247+
return 0;
248+
}
249+
250+
@Override
251+
public List<Alert> getExampleAlerts() {
252+
return List.of(createAlert("foo", "<SCRIPT>a=/XSS/", "<SCRIPT>a=/XSS/").build());
253+
}
254+
}

0 commit comments

Comments
 (0)