Java tutorial
/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * 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.ascanrulesAlpha; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.htmlparser.jericho.Source; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.URI; 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.HttpMessage; import org.zaproxy.zap.model.Vulnerabilities; import org.zaproxy.zap.model.Vulnerability; /** * a scanner that looks for, and exploits CVE-2012-1823 to disclose PHP application source code * * @author 70pointer * */ public class SourceCodeDisclosureCVE20121823 extends AbstractAppPlugin { /** * match on PHP tags in the response */ private static final Pattern PHP_PATTERN1 = Pattern.compile(".*(<\\?php.+?\\?>).*", Pattern.MULTILINE | Pattern.DOTALL); //PHP standard tags private static final Pattern PHP_PATTERN2 = Pattern.compile(".*(<\\?=.+?\\?>).*", Pattern.MULTILINE | Pattern.DOTALL); //PHP "echo short tag" /** * details of the vulnerability which we are attempting to find * WASC 20 = Improper Input Handling */ private static final Vulnerability vuln = Vulnerabilities.getVulnerability("wasc_20"); /** * the logger object */ private static final Logger log = Logger.getLogger(SourceCodeDisclosureCVE20121823.class); /** * returns the plugin id */ @Override public int getId() { return 20017; } /** * returns the name of the plugin */ @Override public String getName() { return Constant.messages.getString("ascanalpha.sourcecodedisclosurecve-2012-1823.name"); } @Override public String[] getDependency() { return null; } @Override public String getDescription() { if (vuln != null) { return vuln.getDescription(); } return "Failed to load vulnerability description from file"; } @Override public int getCategory() { return Category.INFO_GATHER; } @Override public String getSolution() { if (vuln != null) { return vuln.getSolution(); } return "Failed to load vulnerability solution from file"; } @Override public String getReference() { if (vuln != null) { StringBuilder sb = new StringBuilder(); for (String ref : vuln.getReferences()) { if (sb.length() > 0) { sb.append('\n'); } sb.append(ref); } return sb.toString(); } return "Failed to load vulnerability reference from file"; } @Override public void init() { } @Override public void scan() { try { //at Low or Medium strength, do not attack URLs which returned "Not Found" AttackStrength attackStrength = getAttackStrength(); if ((attackStrength == AttackStrength.LOW || attackStrength == AttackStrength.MEDIUM) && (getBaseMsg().getResponseHeader().getStatusCode() == HttpStatus.SC_NOT_FOUND)) return; URI originalURI = getBaseMsg().getRequestHeader().getURI(); //construct a new URL based on the original URL, but without any of the original parameters String attackParam = "?-s"; URI attackURI = new URI(originalURI.getScheme() + "://" + originalURI.getAuthority() + (originalURI.getPath() != null ? originalURI.getPath() : "/") + attackParam, true); //and send it as a GET, unauthorised. HttpMessage attackmsg = new HttpMessage(attackURI); sendAndReceive(attackmsg, false); //do not follow redirects if (attackmsg.getResponseHeader().getStatusCode() == HttpStatus.SC_OK) { //double-check: does the response contain HTML encoded PHP? //Ignore the case where it contains encoded HTML for now, since thats not a source code disclosure anyway //(HTML is always sent back to the web browser) String responseBody = new String(attackmsg.getResponseBody().getBytes()); String responseBodyDecoded = new Source(responseBody).getRenderer().toString(); Matcher matcher1 = PHP_PATTERN1.matcher(responseBodyDecoded); Matcher matcher2 = PHP_PATTERN2.matcher(responseBodyDecoded); boolean match1 = matcher1.matches(); boolean match2 = matcher2.matches(); if ((!responseBody.equals(responseBodyDecoded)) && (match1 || match2)) { if (log.isDebugEnabled()) { log.debug("Source Code Disclosure alert for: " + originalURI.getURI()); } String sourceCode = null; if (match1) { sourceCode = matcher1.group(1); } else { sourceCode = matcher2.group(1); } //bingo. bingo(Alert.RISK_HIGH, Alert.WARNING, Constant.messages.getString("ascanalpha.sourcecodedisclosurecve-2012-1823.name"), Constant.messages.getString("ascanalpha.sourcecodedisclosurecve-2012-1823.desc"), null, // originalMessage.getRequestHeader().getURI().getURI(), null, // parameter being attacked: none. "", // attack: none (it's not a parameter being attacked) sourceCode, //extrainfo Constant.messages.getString("ascanalpha.sourcecodedisclosurecve-2012-1823.soln"), "", //evidence, highlighted in the message (cannot use the source code here, since it is encoded in the message response, and so will not match up) attackmsg //raise the alert on the attack message ); } } } catch (Exception e) { log.error("Error scanning a Host for Source Code Disclosure via CVE-2012-1823: " + e.getMessage(), e); } } @Override public int getRisk() { return Alert.RISK_HIGH; } @Override public int getCweId() { return 20; //Improper Input Validation } @Override public int getWascId() { return 20; //Improper Input Handling } }