Skip to content

Commit 846c68e

Browse files
committed
Add extender/ScanMonitor script
Signed-off-by: Simon Bennetts <[email protected]>
1 parent a727590 commit 846c68e

File tree

4 files changed

+93
-1
lines changed

4 files changed

+93
-1
lines changed

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
### Added
88
- Standalone script 'PrivateMethodAccess.js'
99
- Variant script 'AddUrlParams.js'
10+
- Extender script 'ScanMonitor.js'
1011
### Changed
1112
- Add cautionary note to help and readme.
1213
### Fixed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ spotless {
125125
}
126126
javascript {
127127
target("**/*.js")
128-
targetExclude("extender/HTTP Message Logger.js", "standalone/domainFinder.js")
128+
targetExclude("extender/HTTP Message Logger.js", "extender/ScanMonitor.js", "standalone/domainFinder.js")
129129
// get the npm executable path from gradle-node-plugin
130130
val npmDir = (tasks.named("npmSetup").get().property("npmDir") as TransformBackedProvider<*, *>).get().toString()
131131
val npmExecutable = if (System.getProperty("os.name").lowercase().contains("windows")) "/npm.cmd" else "/bin/npm"

extender/ScanMonitor.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// This script monitors the active scanner and ends the scan if certain conditions are met.
2+
// By default it just ends the scan for high:
3+
// * Connection failures
4+
// * Authentication failures
5+
// * Response times
6+
// You can easily chane the script to end the scan for other conditions, such as high 4xx / 5xx response codes,
7+
// but these tend to be application specific so they are not enabled by default.
8+
9+
var SessionStructure = Java.type("org.zaproxy.zap.model.SessionStructure");
10+
var Timer = Java.type("java.util.Timer");
11+
var TimerTask = Java.type("java.util.TimerTask");
12+
var URI = Java.type("org.apache.commons.httpclient.URI");
13+
14+
var extAscan = control.getExtensionLoader().getExtension("ExtensionActiveScan");
15+
var inMemoryStats = control
16+
.getExtensionLoader()
17+
.getExtension("ExtensionStats")
18+
.getInMemoryStats();
19+
20+
var timer = new Timer();
21+
var timerSecs = 10 * 1000; // Check every 10 secs
22+
23+
// Set to true to see the stats reported live
24+
var log = false;
25+
26+
function install(helper) {
27+
timer.scheduleAtFixedRate(
28+
new TimerTask() {
29+
run: function () {
30+
runchecks();
31+
},
32+
},
33+
0,
34+
timerSecs
35+
);
36+
}
37+
38+
function getStat(site, stat) {
39+
var val =
40+
site == null
41+
? inMemoryStats.getStat(stat)
42+
: inMemoryStats.getStat(site, stat);
43+
return val == null ? 0 : val;
44+
}
45+
46+
// Response times are recorded in logarithmic millisec time slices
47+
function getLongRespStats(site) {
48+
return (
49+
getStat(site, "stats.responseTime.16384") +
50+
getStat(site, "stats.responseTime.32768") +
51+
getStat(site, "stats.responseTime.65536")
52+
);
53+
}
54+
55+
function runchecks() {
56+
if (log) print("Running checks..");
57+
ascans = extAscan.getActiveScans();
58+
ascans.forEach((as, i) => {
59+
// For the full set of stats that can be monitored see https://www.zaproxy.org/docs/internal-statistics/
60+
var site = SessionStructure.getHostName(new URI(as.getDisplayName(), true));
61+
if (log) print("Site: " + site);
62+
// Connection failures are global rather than site specific
63+
var connFails = getStat(null, "stats.network.send.failure");
64+
// All HTTP response codes are recorded, so you can add checks for 401, 403 etc etc
65+
var stats401 = getStat(site, "stats.code.401");
66+
var stats500 = getStat(site, "stats.code.500");
67+
// Auth fails are only relevant for authenticated scans
68+
var authFails = getStat(site, "stats.auth.failure");
69+
var longResp = getLongRespStats(site);
70+
71+
if (log) {
72+
print(" 401 resps:\t" + stats401);
73+
print(" 500 resps:\t" + stats500);
74+
print(" conn fails:\t" + connFails);
75+
print(" auth fails:\t" + authFails);
76+
print(" long resps:\t" + longResp);
77+
}
78+
// Change this test to meet your requirements as needed.
79+
if (connFails > 1000 || authFails > 1000 || longResp > 1000) {
80+
if (log) print("Stopping ascan " + site);
81+
as.stopScan();
82+
}
83+
});
84+
}
85+
86+
function uninstall(helper) {
87+
timer.cancel();
88+
}

other/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ All notable changes to the 'other' section of this repository will be documented
33

44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

6+
### 2024-08-30
7+
- Added af-plans/ApiScanExample.yaml
8+
69
### 2024-02-06
710
- Added af-plans/FullScanBrokenCrystals.yaml
811
- Added af-plans/ScriptEnvVarAccess.yaml

0 commit comments

Comments
 (0)