Skip to content

Commit

Permalink
Add extender/ScanMonitor script
Browse files Browse the repository at this point in the history
Signed-off-by: Simon Bennetts <[email protected]>
  • Loading branch information
psiinon committed Sep 13, 2024
1 parent a727590 commit 8ab42a3
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added
- Standalone script 'PrivateMethodAccess.js'
- Variant script 'AddUrlParams.js'
- Extender script 'ScanMonitor.js'
### Changed
- Add cautionary note to help and readme.
### Fixed
Expand Down
88 changes: 88 additions & 0 deletions extender/ScanMonitor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// This script monitors the active scanner and ends the scan if certain conditions are met.
// By default it just ends the scan for high:
// * Connection failures
// * Authentication failures
// * Response times
// You can easily chane the script to end the scan for other conditions, such as high 4xx / 5xx response codes,
// but these tend to be application specific so they are not enabled by default.

var SessionStructure = Java.type("org.zaproxy.zap.model.SessionStructure");
var Timer = Java.type("java.util.Timer");
var TimerTask = Java.type("java.util.TimerTask");
var URI = Java.type("org.apache.commons.httpclient.URI");

var extAscan = control.getExtensionLoader().getExtension("ExtensionActiveScan");
var inMemoryStats = control
.getExtensionLoader()
.getExtension("ExtensionStats")
.getInMemoryStats();

var timer = new Timer();
var timerSecs = 10 * 1000; // Check every 10 secs

// Set to true to see the stats reported live
var log = false;

function install(helper) {
timer.scheduleAtFixedRate(
new TimerTask()
{
run() {
runchecks();
},
},
0,
timerSecs
);
}

function getStat(site, stat) {
var val =
site == null
? inMemoryStats.getStat(stat)
: inMemoryStats.getStat(site, stat);
return val == null ? 0 : val;
}

// Response times are recorded in logarithmic time slices
function getLongRespStats(site) {
return (
getStat(site, "stats.responseTime.16384") +
getStat(site, "stats.responseTime.32768") +
getStat(site, "stats.responseTime.65536")
);
}

function runchecks() {
if (log) print("Running checks..");
ascans = extAscan.getActiveScans();
ascans.forEach((as, i) => {
// For the full set of stats that can be monitored see https://www.zaproxy.org/docs/internal-statistics/
var site = SessionStructure.getHostName(new URI(as.getDisplayName(), true));
if (log) print("Site: " + site);
// Connection failures are global rather than site specific
var connFails = getStat(null, "stats.network.send.failure");
// All HTTP response codes are recorded, so you can add checks for 401, 403 etc etc
var stats401 = getStat(site, "stats.code.401");
var stats500 = getStat(site, "stats.code.500");
// Auth fails are only relevant for authenticated scans
var authFails = getStat(site, "stats.auth.failure");
var longResp = getLongRespStats(site);

if (log) {
print(" 401 resps:\t" + stats401);
print(" 500 resps:\t" + stats500);
print(" conn fails:\t" + connFails);
print(" auth fails:\t" + authFails);
print(" long resps:\t" + longResp);
}
if (connFails > 1000 || authFails > 1000 || longResp > 1000) {
if (log) print("Stopping ascan " + site);
as.stopScan();
}
});
}

function uninstall(helper) {
timer.cancel();
}
3 changes: 3 additions & 0 deletions other/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ All notable changes to the 'other' section of this repository will be documented

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

### 2024-08-30
- Added af-plans/ApiScanExample.yaml

### 2024-02-06
- Added af-plans/FullScanBrokenCrystals.yaml
- Added af-plans/ScriptEnvVarAccess.yaml
Expand Down

0 comments on commit 8ab42a3

Please sign in to comment.