/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * Copyright 2013 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.parosproxy.paros.core.scanner; import java.util.regex.Pattern; import org.apache.commons.lang.StringEscapeUtils; /** * Variant to allow scanning of Direct Web Remoting (DWR) parameters * * @author 70pointer@gmail.com */ public class VariantDirectWebRemotingQuery extends VariantAbstractRPCQuery { public static final String DWR_CONTENT_TYPE = "text/plain"; //parameter names to not scan private static final Pattern patternIgnoreScriptName = Pattern.compile ("c[0-9]+-scriptName", Pattern.CASE_INSENSITIVE); private static final Pattern patternIgnoreMethodName = Pattern.compile ("c[0-9]+-methodName", Pattern.CASE_INSENSITIVE); //parameter values to not scan private static final Pattern patternIgnoreArray = Pattern.compile ("Array:\\[.*\\]", Pattern.CASE_INSENSITIVE); private static final Pattern patternIgnoreObject = Pattern.compile ("Object_Object:\\{.*\\}", Pattern.CASE_INSENSITIVE); //strongly typed parameter values private static final Pattern patternNumberValue = Pattern.compile ("number:.+", Pattern.CASE_INSENSITIVE); private static final Pattern patternStringValue = Pattern.compile ("string:.*", Pattern.CASE_INSENSITIVE); private static final Pattern patternBooleanValue = Pattern.compile ("boolean:.+", Pattern.CASE_INSENSITIVE); private static final Pattern patternNullValue = Pattern.compile ("null:null", Pattern.CASE_INSENSITIVE); /** * * @param contentType * @return */ @Override public boolean isValidContentType(String contentType) { return contentType.startsWith(DWR_CONTENT_TYPE); } /** * * @param value * @param toQuote * @return */ @Override public String getEscapedValue(String value, boolean toQuote) { return StringEscapeUtils.escapeJava(value); } /** * * @param value * @return */ @Override public String getUnescapedValue(String value) { return StringEscapeUtils.unescapeJava(value); } /** * * @param content */ @Override public void parseContent(String content) { //System.out.println("Getting parameters from ["+content + "]"); int offie = content.indexOf("\n"); int accumulatedOffset = 0; while (offie > 0) { String paramString = content.substring(0, offie); String paramDetails[] = paramString.split ("=",2); //do not interpret the DWR script or method as parameters to be scanned //take care to handle the case where a single POST request contains multiple DWR calls (c0, c1, c2, etc) if ( (! patternIgnoreScriptName.matcher(paramDetails[0]).matches()) && (! patternIgnoreMethodName.matcher(paramDetails[0]).matches()) && paramDetails.length == 2 ) { if (paramDetails[1]== null) paramDetails[1]=""; //if the parameter value has one of the following patterns, ignore it. // Array:[<<some possible stuff>>] // Object_Object:{<<some possible stuff>>} if ( patternIgnoreArray.matcher(paramDetails[1]).matches()) continue; //to the next iteration if ( patternIgnoreObject.matcher(paramDetails[1]).matches()) continue; //to the next iteration int valueOffset = 0; String paramValue = paramDetails[1]; //if the parameter value has one of the following formats, then adjust the value offset, so that the "type" of the value is not corrupted. // number:<<some number>> // string:<<some string>> // boolean:<<true or false>> // null:null if (patternNumberValue.matcher(paramDetails[1]).matches() || patternStringValue.matcher(paramDetails[1]).matches() || patternBooleanValue.matcher(paramDetails[1]).matches() || patternNullValue.matcher(paramDetails[1]).matches() ) { //the value has a type built in. valueOffset = paramDetails[1].indexOf(":")+1; paramValue = paramDetails[1].substring(valueOffset); } int beginOffset = accumulatedOffset + paramDetails[0].length() + 1 + valueOffset; int endOffset = accumulatedOffset + offie; //System.out.println("Adding parameter ["+paramDetails[0]+"]=["+paramValue+"], value offset1:" + beginOffset+ ", value offset2:" + endOffset); addParameter(paramDetails[0], beginOffset, endOffset, false, paramValue); } accumulatedOffset+=(1 + offie); //cater for the \n separator as well. content = content.substring(offie + 1); offie = content.indexOf("\n"); } } }