org.zaproxy.zap.extension.pscan.ExtensionPassiveScan Maven / Gradle / Ivy
Show all versions of zap Show documentation
/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2010 [email protected]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.zaproxy.zap.extension.pscan;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.ImageIcon;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.FileConfiguration;
import org.apache.log4j.Logger;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.control.Control;
import org.parosproxy.paros.control.Control.Mode;
import org.parosproxy.paros.core.scanner.Plugin;
import org.parosproxy.paros.core.scanner.Plugin.AlertThreshold;
import org.parosproxy.paros.extension.ExtensionAdaptor;
import org.parosproxy.paros.extension.ExtensionHook;
import org.parosproxy.paros.extension.ExtensionLoader;
import org.parosproxy.paros.extension.SessionChangedListener;
import org.parosproxy.paros.extension.history.ExtensionHistory;
import org.parosproxy.paros.model.Session;
import org.parosproxy.paros.view.View;
import org.zaproxy.zap.ZAP;
import org.zaproxy.zap.control.CoreFunctionality;
import org.zaproxy.zap.control.ExtensionFactory;
import org.zaproxy.zap.extension.alert.ExtensionAlert;
import org.zaproxy.zap.extension.pscan.scanner.RegexAutoTagScanner;
import org.zaproxy.zap.extension.script.ExtensionScript;
import org.zaproxy.zap.extension.script.ScriptType;
public class ExtensionPassiveScan extends ExtensionAdaptor implements SessionChangedListener {
public static final String NAME = "ExtensionPassiveScan";
private static final ImageIcon SCRIPT_ICON =
new ImageIcon(ZAP.class.getResource("/resource/icon/16/script-pscan.png"));
public static final String SCRIPT_TYPE_PASSIVE = "passive";
private static final Logger logger = Logger.getLogger(ExtensionPassiveScan.class);
private PassiveScannerList scannerList;
private OptionsPassiveScan optionsPassiveScan = null;
private PolicyPassiveScanPanel policyPanel = null;
private PassiveScanThread pst = null;
private boolean passiveScanEnabled;
private PassiveScanParam passiveScanParam;
private static final List> DEPENDENCIES;
static {
List> dep = new ArrayList<>(1);
dep.add(ExtensionAlert.class);
DEPENDENCIES = Collections.unmodifiableList(dep);
}
private PassiveScannerOptionsPanel passiveScannerOptionsPanel;
public ExtensionPassiveScan() {
super();
initialize();
}
private void initialize() {
this.setOrder(26);
this.setName(NAME);
}
@Override
public void init() {
super.init();
passiveScanEnabled = true;
}
@Override
public void hook(ExtensionHook extensionHook) {
super.hook(extensionHook);
extensionHook.addOptionsParamSet(getPassiveScanParam());
extensionHook.addProxyListener(getPassiveScanThread());
extensionHook.addSessionListener(this);
if (getView() != null) {
extensionHook.getHookView().addOptionPanel(getPassiveScannerOptionsPanel());
extensionHook.getHookView().addOptionPanel(getOptionsPassiveScan(getPassiveScanThread()));
extensionHook.getHookView().addOptionPanel(getPolicyPanel());
}
ExtensionScript extScript = (ExtensionScript) Control.getSingleton().getExtensionLoader().getExtension(ExtensionScript.NAME);
if (extScript != null) {
extScript.registerScriptType(new ScriptType(SCRIPT_TYPE_PASSIVE, "pscan.scripts.type.passive", SCRIPT_ICON, true));
}
extensionHook.addApiImplementor(new PassiveScanAPI(this));
}
@Override
public void optionsLoaded() {
getPassiveScannerList().setAutoTagScanners(getPassiveScanParam().getAutoTagScanners());
}
/**
* @deprecated (2.4.3) Use {@link #addPluginPassiveScanner(PluginPassiveScanner)} instead, the status of the
* scanner is not properly set.
* @see PluginPassiveScanner#getStatus()
*/
@Deprecated
@SuppressWarnings("javadoc")
public boolean addPassiveScanner(String className) {
try {
Class> c = ExtensionFactory.getAddOnLoader().loadClass(className);
this.addPassiveScanner((PluginPassiveScanner) c.newInstance());
return true;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return false;
}
}
public boolean removePassiveScanner(String className) {
PassiveScanner scanner = getPassiveScannerList().removeScanner(className);
if (scanner != null && View.isInitialised() && scanner instanceof PluginPassiveScanner) {
getPolicyPanel().getPassiveScanTableModel().removeScanner((PluginPassiveScanner) scanner);
}
return scanner != null;
}
/**
* Adds the given passive scanner to the list of passive scanners that will be used to scan proxied messages.
*
* The passive scanner will not be added if there is already a passive scanner with the same name.
*
*
* If the passive scanner extends from {@code PluginPassiveScanner} it will be added with the method
* {@code addPluginPassiveScanner(PluginPassiveScanner)}.
*
*
* @param passiveScanner the passive scanner that will be added
* @return {@code true} if the scanner was added, {@code false} otherwise.
* @throws IllegalArgumentException if the given passive scanner is {@code null}.
* @see PluginPassiveScanner
* @see #addPluginPassiveScanner(PluginPassiveScanner)
* @see PassiveScanner
*/
public boolean addPassiveScanner(PassiveScanner passiveScanner) {
if (passiveScanner == null) {
throw new IllegalArgumentException("Parameter passiveScanner must not be null.");
}
if (passiveScanner instanceof PluginPassiveScanner) {
return addPluginPassiveScannerImpl((PluginPassiveScanner) passiveScanner);
}
return addPassiveScannerImpl(passiveScanner);
}
/**
* Removes the given passive scanner from the list of passive scanners that are used to scan proxied messages.
*
* The passive scanners are removed using their class name.
*
*
* @param passiveScanner the passive scanner that will be removed
* @return {@code true} if the scanner was removed, {@code false} otherwise.
* @throws IllegalArgumentException if the given passive scanner is {@code null}.
* @see PassiveScanner
*/
public boolean removePassiveScanner(PassiveScanner passiveScanner) {
if (passiveScanner == null) {
throw new IllegalArgumentException("Parameter passiveScanner must not be null.");
}
return removePassiveScanner(passiveScanner.getClass().getName());
}
/**
* Adds the given plug-in passive scanner to the list of passive scanners that will be used to scan proxied messages.
*
* The passive scanner will not be added if there is already a passive scanner with the same name.
*
*
* @param pluginPassiveScanner the plug-in passive scanner that will be added
* @return {@code true} if the plug-in scanner was added, {@code false} otherwise.
* @throws IllegalArgumentException if the given plug-in passive scanner is {@code null}.
* @see PluginPassiveScanner
*/
public boolean addPluginPassiveScanner(PluginPassiveScanner pluginPassiveScanner) {
if (pluginPassiveScanner == null) {
throw new IllegalArgumentException("Parameter pluginPassiveScanner must not be null.");
}
return addPluginPassiveScannerImpl(pluginPassiveScanner);
}
/**
* Removes the given plug-in passive scanner from the list of passive scanners that are used to scan proxied messages.
*
* The plug-in passive scanners are removed using their class name.
*
*
* @param pluginPassiveScanner the passive scanner that will be removed
* @return {@code true} if the plug-in scanner was removed, {@code false} otherwise.
* @throws IllegalArgumentException if the given plug-in passive scanner is {@code null}.
* @see PluginPassiveScanner
*/
public boolean removePluginPassiveScanner(PluginPassiveScanner pluginPassiveScanner) {
if (pluginPassiveScanner == null) {
throw new IllegalArgumentException("Parameter pluginPassiveScanner must not be null.");
}
return removePassiveScanner(pluginPassiveScanner.getClass().getName());
}
private boolean addPassiveScannerImpl(PassiveScanner passiveScanner) {
return scannerList.add(passiveScanner);
}
private boolean addPluginPassiveScannerImpl(PluginPassiveScanner scanner) {
if (scanner instanceof RegexAutoTagScanner) {
return false;
}
boolean added = false;
try {
FileConfiguration config = this.getModel().getOptionsParam().getConfig();
scanner.setConfig(config);
added = addPassiveScannerImpl(scanner);
if (View.isInitialised()) {
getPolicyPanel().getPassiveScanTableModel().addScanner(scanner);
}
logger.info("loaded passive scan rule: " + scanner.getName());
if (scanner.getPluginId() == -1) {
logger.error(
"The passive scan rule \"" + scanner.getName() + "\" [" + scanner.getClass().getCanonicalName()
+ "] does not have a defined ID.");
}
} catch (Exception e) {
logger.error("Failed to load passive scanner " + scanner.getName(), e);
}
return added;
}
private PassiveScannerList getPassiveScannerList() {
if (scannerList == null) {
scannerList = new PassiveScannerList();
// Read from the configs
scannerList.setAutoTagScanners(getPassiveScanParam().getAutoTagScanners());
// Load the 'switchable' plugins
List listTest = new ArrayList<>(CoreFunctionality.getBuiltInPassiveScanRules());
listTest.addAll(ExtensionFactory.getAddOnLoader().getPassiveScanRules());
for (PluginPassiveScanner scanner : listTest) {
addPluginPassiveScannerImpl(scanner);
}
}
return scannerList;
}
protected List getPluginPassiveScanners() {
List pluginPassiveScanners = new ArrayList<>();
for (PassiveScanner scanner : getPassiveScannerList().list()) {
if ((scanner instanceof PluginPassiveScanner) && !(scanner instanceof RegexAutoTagScanner)) {
pluginPassiveScanners.add((PluginPassiveScanner) scanner);
}
}
return pluginPassiveScanners;
}
/**
* Sets whether or not all plug-in passive scanners are {@code enabled}.
*
* @param enabled {@code true} if the scanners should be enabled, {@code false} otherwise
*/
void setAllPluginPassiveScannersEnabled(boolean enabled) {
for (PluginPassiveScanner scanner : getPluginPassiveScanners()) {
scanner.setEnabled(enabled);
scanner.save();
}
}
/**
* Sets whether or not the plug-in passive scanner with the given {@code pluginId} is {@code enabled}.
*
* @param pluginId the ID of the plug-in passive scanner
* @param enabled {@code true} if the scanner should be enabled, {@code false} otherwise
*/
void setPluginPassiveScannerEnabled(int pluginId, boolean enabled) {
for (PluginPassiveScanner scanner : getPluginPassiveScanners()) {
if (pluginId == scanner.getPluginId()) {
scanner.setEnabled(enabled);
scanner.save();
}
}
}
/**
* Tells whether or not a plug-in passive scanner with the given {@code pluginId} exist.
*
* @param pluginId the ID of the plug-in passive scanner
* @return {@code true} if the scanner exist, {@code false} otherwise.
*/
boolean hasPluginPassiveScanner(int pluginId) {
for (PluginPassiveScanner scanner : getPluginPassiveScanners()) {
if (pluginId == scanner.getPluginId()) {
return true;
}
}
return false;
}
/**
* Sets the value of {@code alertThreshold} of the plug-in passive scanner with the given {@code pluginId}.
*
* If the {@code alertThreshold} is {@code OFF} the scanner is also disabled. The call to this method has no effect if no
* scanner with the given {@code pluginId} exist.
*
* @param pluginId the ID of the plug-in passive scanner
* @param alertThreshold the alert threshold that will be set
* @see org.parosproxy.paros.core.scanner.Plugin.AlertThreshold
*/
void setPluginPassiveScannerAlertThreshold(int pluginId, Plugin.AlertThreshold alertThreshold) {
for (PluginPassiveScanner scanner : getPluginPassiveScanners()) {
if (pluginId == scanner.getPluginId()) {
scanner.setLevel(alertThreshold);
scanner.setEnabled(!Plugin.AlertThreshold.OFF.equals(alertThreshold));
scanner.save();
}
}
}
/**
*
* @param at
*/
public void setAllScannerThreshold(AlertThreshold at) {
for (PluginPassiveScanner test : getPluginPassiveScanners()) {
test.setLevel(at);
test.setEnabled(!AlertThreshold.OFF.equals(at));
test.save();
}
}
/**
*
* @return
*/
public AlertThreshold getAllScannerThreshold() {
AlertThreshold at = null;
for (PluginPassiveScanner test : getPluginPassiveScanners()) {
if (at == null) {
at = test.getLevel();
} else if (!at.equals(test.getLevel())) {
// Not all the same
return null;
}
}
return at;
}
protected PolicyPassiveScanPanel getPolicyPanel() {
if (policyPanel == null) {
policyPanel = new PolicyPassiveScanPanel();
}
return policyPanel;
}
public int getRecordsToScan() {
if (passiveScanEnabled) {
return this.getPassiveScanThread().getRecordsToScan();
}
return 0;
}
private PassiveScanThread getPassiveScanThread() {
if (pst == null) {
final ExtensionLoader extensionLoader = Control.getSingleton().getExtensionLoader();
final ExtensionHistory extHist = (ExtensionHistory) extensionLoader.getExtension(ExtensionHistory.NAME);
final ExtensionAlert extAlert = (ExtensionAlert) extensionLoader.getExtension(ExtensionAlert.NAME);
pst = new PassiveScanThread(getPassiveScannerList(), extHist, extAlert, getPassiveScanParam());
pst.start();
}
return pst;
}
PassiveScanParam getPassiveScanParam() {
if (passiveScanParam == null) {
passiveScanParam = new PassiveScanParam();
}
return passiveScanParam;
}
private PassiveScannerOptionsPanel getPassiveScannerOptionsPanel() {
if (passiveScannerOptionsPanel == null) {
passiveScannerOptionsPanel = new PassiveScannerOptionsPanel(Constant.messages);
}
return passiveScannerOptionsPanel;
}
private OptionsPassiveScan getOptionsPassiveScan(PassiveScanThread passiveScanThread) {
if (optionsPassiveScan == null) {
optionsPassiveScan = new OptionsPassiveScan(scannerList);
}
return optionsPassiveScan;
}
@Override
public void sessionAboutToChange(Session session) {
stopPassiveScanThread();
}
private void stopPassiveScanThread() {
if (this.pst != null) {
getPassiveScanThread().shutdown();
this.pst = null;
}
}
@Override
public void sessionChanged(Session session) {
startPassiveScanThread();
}
private void startPassiveScanThread() {
if (passiveScanEnabled && pst == null) {
// Will create a new thread if one doesnt exist
getPassiveScanThread();
}
}
@Override
public void destroy() {
super.destroy();
stopPassiveScanThread();
}
@Override
public List> getDependencies() {
return DEPENDENCIES;
}
@Override
public void sessionScopeChanged(Session session) {
}
@Override
public String getAuthor() {
return Constant.ZAP_TEAM;
}
@Override
public String getDescription() {
return Constant.messages.getString("pscan.desc");
}
@Override
public URL getURL() {
try {
return new URL(Constant.ZAP_HOMEPAGE);
} catch (MalformedURLException e) {
return null;
}
}
@Override
public void sessionModeChanged(Mode mode) {
// Ignore
}
void setPassiveScanEnabled(boolean enabled) {
if (passiveScanEnabled != enabled) {
passiveScanEnabled = enabled;
if (enabled) {
startPassiveScanThread();
} else {
stopPassiveScanThread();
}
}
}
public void saveTo(Configuration conf) {
for (PassiveScanner scanner : getPassiveScannerList().list()) {
if ((scanner instanceof PluginPassiveScanner) && !(scanner instanceof RegexAutoTagScanner)) {
((PluginPassiveScanner) scanner).saveTo(conf);
}
}
}
public void loadFrom(Configuration conf) {
for (PassiveScanner scanner : getPassiveScannerList().list()) {
if ((scanner instanceof PluginPassiveScanner) && !(scanner instanceof RegexAutoTagScanner)) {
((PluginPassiveScanner) scanner).loadFrom(conf);
}
}
}
@Override
public boolean supportsLowMemory() {
return true;
}
/**
* No database tables used, so all supported
*/
@Override
public boolean supportsDb(String type) {
return true;
}
}