Java tutorial
/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * Copyright 2012 The ZAP Development Team * * 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.ascanrulesBeta; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeSet; import net.htmlparser.jericho.Element; import net.htmlparser.jericho.HTMLElementName; import net.htmlparser.jericho.Source; import org.apache.commons.httpclient.URIException; import org.apache.log4j.Logger; import org.parosproxy.paros.Constant; import org.parosproxy.paros.core.scanner.AbstractAppPlugin; import org.parosproxy.paros.core.scanner.Alert; import org.parosproxy.paros.core.scanner.Category; import org.parosproxy.paros.network.HtmlParameter; import org.parosproxy.paros.network.HttpMessage; /** * HPP is an effort to improve the anti-CSRF token detection of ZAP It is based on previous plugins * such as csrfcountermeasuresscan and sessionfixation * * <p>TODO note that this should extend AbstractAppParamPlugin rather than find parameters * internally */ public class HPP extends AbstractAppPlugin { private static Logger log = Logger.getLogger(HPP.class); private final String payload = "%26zap%3Dzaproxy"; /** Constructor of the class, sets the logging level */ public HPP() { // log.setLevel(Level.ALL); //uncomment this for debugging } /** @return the Id of the plugin */ @Override public int getId() { return 20014; } /** @return the name of the plugin */ @Override public String getName() { return Constant.messages.getString("ascanbeta.HTTPParamPoll.name"); } /** @return dependencies of the plugin (none) */ @Override public String[] getDependency() { return null; } /** @return the description of the vulnerability */ @Override public String getDescription() { return Constant.messages.getString("ascanbeta.HTTPParamPoll.desc"); } /** @return the category of the vulnerability (INJECTION). */ @Override public int getCategory() { return Category.INJECTION; } /** @return The solution of the vulnerability */ @Override public String getSolution() { return Constant.messages.getString("ascanbeta.HTTPParamPoll.sol"); } /** @return Reference for more information about the vulnerability */ @Override public String getReference() { return Constant.messages.getString("ascanbeta.HTTPParamPoll.extrainfo"); } /** */ @Override public void init() { } /** * Main method of the class. It is executed for each page. Determined whether the page in * vulnerable to HPP or not. */ @Override public void scan() { try { log.debug("Targeting " + getBaseMsg().getRequestHeader().getURI()); // pages are not vulnerable if not proved otherwise List<String> vulnLinks = new ArrayList<String>(); // We parse the HTML of the response and get all its parameters Source s = new Source(getBaseMsg().getResponseBody().toString()); List<Element> inputTags = s.getAllElements(HTMLElementName.INPUT); TreeSet<HtmlParameter> tags = this.getParams(s, inputTags); /* If there are input fields, they can potentially be polluted */ if (!inputTags.isEmpty()) { if (!tags.isEmpty()) { // We send the request with the injected payload in the parameters log.debug("Injecting payload..."); HttpMessage newMsg = getNewMsg(); newMsg.setGetParams(tags); try { sendAndReceive(newMsg); } catch (IllegalStateException | UnknownHostException ex) { if (log.isDebugEnabled()) log.debug("Caught " + ex.getClass().getName() + " " + ex.getMessage() + " when accessing: " + newMsg.getRequestHeader().getURI().toString() + "\n The target may have replied with a poorly formed redirect due to our input."); return; } // We check all the links of the response to find our payload s = new Source(newMsg.getResponseBody().toString()); List<Element> links = s.getAllElements(HTMLElementName.A); if (!links.isEmpty()) { vulnLinks = this.findPayload(s, inputTags, vulnLinks); // If vulnerable, generates the alert if (!vulnLinks.isEmpty()) { this.generateReport(vulnLinks); } } } } if (vulnLinks.isEmpty()) { log.debug("Page not vulnerable to HPP attacks"); } } catch (URIException e) { if (log.isDebugEnabled()) { log.debug("Failed to send HTTP message, cause: " + e.getMessage()); } } catch (Exception e) { log.error(e.getMessage(), e); } } /** * @param s the source code of the targeted page * @param inputTags list of input parameters * @param vulnLinks empty list of the vulnerable links in the page * @return filled list of the vulnerable links in the page */ public List<String> findPayload(Source s, List<Element> inputTags, List<String> vulnLinks) { // TODO: we should consider other tags besides <a href=> and <form action=> // checks the <a> tags List<Element> links = s.getAllElements(HTMLElementName.A); for (Element link : links) { for (Element tag : inputTags) { Map<String, List<String>> map = getUrlParameters(link.getAttributeValue("href")); if (map.get(tag.getAttributeValue("name")) != null) { if (map.get(tag.getAttributeValue("name")).contains(this.payload)) { log.debug("Found Vulnerable Parameter in a link with the injected payload: " + tag.getAttributeValue("name") + ", " + map.get(tag.getAttributeValue("name"))); vulnLinks .add(tag.getAttributeValue("name") + ", " + map.get(tag.getAttributeValue("name"))); } } } } // checks the <form> tags links = s.getAllElements(HTMLElementName.FORM); for (Element link : links) { for (Element tag : inputTags) { Map<String, List<String>> map = getUrlParameters(link.getAttributeValue("action")); if (map.get(tag.getAttributeValue("name")) != null) { if (map.get(tag.getAttributeValue("name")).contains(this.payload)) { log.debug("Found Vulnerable Parameter in a form with the injected payload: " + tag.getAttributeValue("name") + ", " + map.get(tag.getAttributeValue("name"))); vulnLinks .add(tag.getAttributeValue("name") + ", " + map.get(tag.getAttributeValue("name"))); } } } } return vulnLinks; } /** * @param s the source code of the targeted page * @param inputTags list of input parameters * @return the set of url form and input parameters */ public TreeSet<HtmlParameter> getParams(Source s, List<Element> inputTags) { // We store all the page fields in a hash map and add the payload TreeSet<HtmlParameter> tags = new TreeSet<HtmlParameter>(); for (HtmlParameter p : getBaseMsg().getFormParams()) { if (p.getName() != null && p.getValue() != null) { tags.add(new HtmlParameter(HtmlParameter.Type.url, p.getName(), p.getValue() + this.payload)); log.debug("The following form parameters have been found:"); log.debug("Input Tag: " + p.getName() + ", " + p.getValue()); } } for (HtmlParameter p : getBaseMsg().getUrlParams()) { if (p.getName() != null && p.getValue() != null) { tags.add(new HtmlParameter(HtmlParameter.Type.url, p.getName(), p.getValue() + this.payload)); log.debug("The following url parameters have been found:"); log.debug("Input Tag: " + p.getName() + ", " + p.getValue()); } } for (Element element : inputTags) { if (element.getAttributeValue("name") != null && element.getAttributeValue("value") != null) { tags.add(new HtmlParameter(HtmlParameter.Type.url, element.getAttributeValue("name"), element.getAttributeValue("value") + this.payload)); log.debug("The following input parameters have been found:"); log.debug("Input Tag: " + element.getAttributeValue("name") + ", " + element.getAttributeValue("value")); } } return tags; } /** * @param url found in the body of the targeted page * @return a hashmap of the query string */ private Map<String, List<String>> getUrlParameters(String url) { Map<String, List<String>> params = new HashMap<String, List<String>>(); if (url != null) { String[] urlParts = url.split("\\?"); if (urlParts.length > 1) { String query = urlParts[1]; for (String param : query.split("&")) { String pair[] = param.split("="); String key; key = pair[0]; String value = ""; if (pair.length > 1) { value = pair[1]; } List<String> values = params.get(key); if (values == null) { values = new ArrayList<String>(); params.put(key, values); } values.add(value); } } } return params; } /** @param vulnLinks list of the vulnerable links in the page */ public void generateReport(List<String> vulnLinks) { String vulnParams = ""; for (String s : vulnLinks) { vulnParams = vulnParams + ", " + s; } log.debug("Page vulnerable to HPP attacks"); String attack = Constant.messages.getString("ascanbeta.HTTPParamPoll.alert.attack"); try { bingo(Alert.RISK_MEDIUM, Alert.CONFIDENCE_MEDIUM, attack, getDescription(), getBaseMsg().getRequestHeader().getURI().getURI(), vulnParams, attack, getReference(), getSolution(), getBaseMsg()); } catch (URIException e) { log.error(e.getMessage(), e); } } @Override public int getRisk() { // TODO Auto-generated method stub return 0; } @Override public int getCweId() { return 20; // CWE-20: Improper Input Validation } @Override public int getWascId() { return 20; // WASC-20: Improper Input Handling } }