/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * Copyright 2010 psiinon@gmail.com * * 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.scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.htmlparser.jericho.Source; import org.apache.commons.httpclient.URIException; import org.parosproxy.paros.core.scanner.Alert; import org.parosproxy.paros.network.HttpMessage; import org.zaproxy.zap.extension.pscan.PassiveScanThread; import org.zaproxy.zap.extension.pscan.PluginPassiveScanner; import org.zaproxy.zap.model.SessionStructure; import org.zaproxy.zap.utils.Stats; public class RegexAutoTagScanner extends PluginPassiveScanner { public static final String TAG_STATS_PREFIX = "stats.tag."; // protected static final int PATTERN_SCAN = Pattern.CASE_INSENSITIVE | Pattern.MULTILINE; protected static final int PATTERN_SCAN = Pattern.CASE_INSENSITIVE; public enum TYPE {ALERT, TAG, TECH}; private String name = null; private String requestUrlRegex = null; private String requestHeaderRegex = null; private String responseHeaderRegex = null; private String responseBodyRegex = null; private Pattern requestUrlPattern = null; private Pattern requestHeaderPattern = null; private Pattern responseHeaderPattern = null; private Pattern responseBodyPattern = null; private TYPE type = null; private String config = null; private PassiveScanThread parent = null; public RegexAutoTagScanner() { // Null constructor to prevent error being logged;) } public RegexAutoTagScanner(String name, TYPE type, String config) { super(); this.name = name; this.type = type; this.config = config; } public RegexAutoTagScanner(String name, TYPE type, String config, String requestUrlregex, String requestHeaderRegex, String responseHeaderRegex, String responseBodyRegex, boolean enabled) { super(); this.name = name; this.setRequestUrlRegex(requestUrlregex); this.setRequestHeaderRegex(requestHeaderRegex); this.setResponseHeaderRegex(responseHeaderRegex); this.setResponseBodyRegex(responseBodyRegex); this.type = type; this.config = config; setEnabled(enabled); } public RegexAutoTagScanner(RegexAutoTagScanner scanner) { this(scanner.name, scanner.type, scanner.config, scanner.requestUrlRegex, scanner.requestHeaderRegex, scanner.responseHeaderRegex, scanner.responseBodyRegex, scanner.isEnabled()); } public Pattern getRequestUrlPattern() { return requestUrlPattern; } public Pattern getRequestHeaderPattern() { return requestHeaderPattern; } public Pattern getResponseHeaderPattern() { return responseHeaderPattern; } public Pattern getResponseBodyPattern() { return responseBodyPattern; } public TYPE getType() { return type; } public void setType(TYPE type) { this.type = type; } public String getConf() { return config; } public void setConf(String config) { this.config = config; } public String getRequestUrlRegex() { return requestUrlRegex; } public void setRequestUrlRegex(String requestUrlregex) { this.requestUrlRegex = requestUrlregex; if (requestUrlregex == null || requestUrlregex.length() == 0) { this.requestUrlPattern = null; } else { this.requestUrlPattern = Pattern.compile(requestUrlregex, PATTERN_SCAN); } } public String getRequestHeaderRegex() { return requestHeaderRegex; } public void setRequestHeaderRegex(String requestHeaderRegex) { this.requestHeaderRegex = requestHeaderRegex; if (requestHeaderRegex == null || requestHeaderRegex.length() == 0) { this.requestHeaderPattern = null; } else { this.requestHeaderPattern = Pattern.compile(requestHeaderRegex, PATTERN_SCAN); } } public String getResponseHeaderRegex() { return responseHeaderRegex; } public void setResponseHeaderRegex(String responseHeaderRegex) { this.responseHeaderRegex = responseHeaderRegex; if (responseHeaderRegex == null || responseHeaderRegex.length() == 0) { this.responseHeaderPattern = null; } else { this.responseHeaderPattern = Pattern.compile(responseHeaderRegex, PATTERN_SCAN); } } public String getResponseBodyRegex() { return responseBodyRegex; } public void setResponseBodyRegex(String responseBodyRegex) { this.responseBodyRegex = responseBodyRegex; if (responseBodyRegex == null || responseBodyRegex.length() == 0) { this.responseBodyPattern = null; } else { this.responseBodyPattern = Pattern.compile(responseBodyRegex, PATTERN_SCAN); } } @Override public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public void scanHttpRequestSend(HttpMessage msg, int id) { if (! this.isEnabled()) { return; } if (getRequestHeaderPattern() != null) { Matcher m = getRequestHeaderPattern().matcher( msg.getRequestHeader().toString()); if (m.find()) { // Scanner matches, so do what it wants... matched(msg, id); return; } } if (getRequestUrlPattern() != null) { Matcher m = getRequestUrlPattern().matcher( msg.getRequestHeader().getURI().toString()); if (m.find()) { // Scanner matches, so do what it wants... matched(msg, id); return; } } } public Alert getAlert(HttpMessage msg) { return null; } @Override public void scanHttpResponseReceive(HttpMessage msg, int id, Source source) { if (! this.isEnabled()) { return; } if (getResponseHeaderPattern() != null) { Matcher m = getResponseHeaderPattern().matcher( msg.getResponseHeader().toString()); if (m.find()) { // Scanner matches, so do what it wants... matched(msg, id); return; } } if (getResponseBodyPattern() != null) { Matcher m = getResponseBodyPattern().matcher( msg.getResponseBody().toString()); if (m.find()) { // Scanner matches, so do what it wants... matched(msg, id); return; } } } @Override public void setParent(PassiveScanThread parent) { this.parent = parent; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((config == null) ? 0 : config.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((requestHeaderRegex == null) ? 0 : requestHeaderRegex.hashCode()); result = prime * result + ((requestUrlRegex == null) ? 0 : requestUrlRegex.hashCode()); result = prime * result + ((responseBodyRegex == null) ? 0 : responseBodyRegex.hashCode()); result = prime * result + ((responseHeaderRegex == null) ? 0 : responseHeaderRegex.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @Override public boolean equals(Object object) { if (this == object) { return true; } if (!super.equals(object)) { return false; } if (getClass() != object.getClass()) { return false; } RegexAutoTagScanner other = (RegexAutoTagScanner) object; if (config == null) { if (other.config != null) { return false; } } else if (!config.equals(other.config)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (requestHeaderRegex == null) { if (other.requestHeaderRegex != null) { return false; } } else if (!requestHeaderRegex.equals(other.requestHeaderRegex)) { return false; } if (requestUrlRegex == null) { if (other.requestUrlRegex != null) { return false; } } else if (!requestUrlRegex.equals(other.requestUrlRegex)) { return false; } if (responseBodyRegex == null) { if (other.responseBodyRegex != null) { return false; } } else if (!responseBodyRegex.equals(other.responseBodyRegex)) { return false; } if (responseHeaderRegex == null) { if (other.responseHeaderRegex != null) { return false; } } else if (!responseHeaderRegex.equals(other.responseHeaderRegex)) { return false; } if (type != other.type) { return false; } return true; } private void matched(HttpMessage msg, int id) { if (tagHistoryType(msg.getHistoryRef().getHistoryType())) { parent.addTag(id, this.getConf()); } try { Stats.incCounter(SessionStructure.getHostName(msg), TAG_STATS_PREFIX + this.getConf()); } catch (URIException e) { // Ignore } } private boolean tagHistoryType(int historyType) { return PluginPassiveScanner.getDefaultHistoryTypes().contains(historyType); } @Override public boolean appliesToHistoryType(int historyType) { return true; } }