Example usage for org.apache.commons.httpclient URI getName

List of usage examples for org.apache.commons.httpclient URI getName

Introduction

In this page you can find the example usage for org.apache.commons.httpclient URI getName.

Prototype

public String getName() throws URIException 

Source Link

Document

Get the basename of the path.

Usage

From source file:com.serena.rlc.provider.artifactory.domain.Artifact.java

public static Artifact parseSingle(JSONObject jsonObject) {
    Artifact aObj = null;/*from ww  w . j a  v a  2  s .  c  om*/
    if (jsonObject != null) {
        aObj = new Artifact((String) getJSONValue(jsonObject, "uri"), (String) jsonObject.get("path"),
                (String) jsonObject.get("downloadUri"));
        aObj.setRepo((String) jsonObject.get("repo"));
        aObj.setCreated((String) jsonObject.get("created"));
        aObj.setCreatedBy((String) jsonObject.get("createdBy"));
        aObj.setLastModified((String) jsonObject.get("lastModified"));
        aObj.setModifiedBy((String) jsonObject.get("modifiedBy"));
        aObj.setLastUpdated((String) jsonObject.get("lastUpdated"));
        aObj.setMimeType((String) jsonObject.get("mimeType"));
        aObj.setSize((String) jsonObject.get("size"));
        try {
            URI uri = new URI((String) getJSONValue(jsonObject, "uri"));
            aObj.setName(uri.getName());
            String[] segments = uri.getPath().split("/");
            aObj.setVersion(segments[segments.length - 2]);
        } catch (URIException ex) {
            logger.error("Error while parsing input JSON - " + (String) getJSONValue(jsonObject, "uri"), ex);
        }
    }
    return aObj;
}

From source file:org.zaproxy.zap.extension.ascanrulesAlpha.BackupFileDisclosure.java

@Override
public void scan() {
    if (log.isDebugEnabled()) {
        log.debug("Attacking at Attack Strength: " + this.getAttackStrength());
        log.debug("Checking [" + getBaseMsg().getRequestHeader().getMethod() + "] ["
                + getBaseMsg().getRequestHeader().getURI() + "], for Backup File Disclosure");
    }/*from ww  w.  j a v a2 s.  com*/

    try {
        URI uri = this.getBaseMsg().getRequestHeader().getURI();
        String filename = uri.getName();

        int statusCode = this.getBaseMsg().getResponseHeader().getStatusCode();
        if (log.isDebugEnabled())
            log.debug("About to look for a backup for '" + uri.getURI() + "', which returned " + statusCode);

        //is it worth looking for a copy of the file?
        //why do we even get a status code of 0? 
        //eliminate it from our enquiries, because it causes nothing but false positives.         
        if (statusCode == HttpStatus.SC_NOT_FOUND || statusCode == 0) {
            if (log.isDebugEnabled())
                log.debug("The original file request was not successfuly retrieved (status = " + statusCode
                        + "), so there is not much point in looking for a backup of a non-existent file!");
            return;
        }
        if (filename != null && filename.length() > 0) {
            //there is a file name at the end of the path, so look for a backup file for the file
            findBackupFile(this.getBaseMsg());
        } else {
            if (log.isDebugEnabled()) {
                log.debug(
                        "The URI has no filename component, so there is not much point in looking for a corresponding backup file!");
            }
        }
    } catch (Exception e) {
        log.error("Error scanning a request for Backup File Disclosure: " + e.getMessage(), e);
    }
}

From source file:org.zaproxy.zap.extension.ascanrulesAlpha.BackupFileDisclosure.java

/**
 * attempts to find a backup file for the given file
 * @param uri the URI of a file//from   ww  w. ja  va2  s .co m
 * @return 
 */
private void findBackupFile(HttpMessage originalMessage) throws Exception {

    try {
        boolean gives404s = true;
        boolean parentgives404s = true;
        byte[] nonexistparentmsgdata = null;

        URI originalURI = originalMessage.getRequestHeader().getURI();

        //request a file in the same directory to see how it handles "File not found". Using a 404? Something else?
        String temppath = originalURI.getPath();
        if (temppath == null)
            temppath = "";
        int slashposition = temppath.lastIndexOf("/");
        if (slashposition < 0) {
            //WTF? there was no slash in the path..
            throw new Exception("The message has a path with a malformed path component");
        }
        String filename = originalMessage.getRequestHeader().getURI().getName();

        String randomfilename = RandomStringUtils.random(filename.length(),
                "abcdefghijklmoopqrstuvwxyz9123456789");
        String randomfilepath = temppath.substring(0, slashposition) + "/" + randomfilename;

        if (log.isDebugEnabled())
            log.debug("Trying non-existent file: " + randomfilepath);
        HttpMessage nonexistfilemsg = new HttpMessage(
                new URI(originalURI.getScheme(), originalURI.getAuthority(), randomfilepath, null, null));
        try {
            nonexistfilemsg.setCookieParams(originalMessage.getCookieParams());
        } catch (Exception e) {
            if (log.isDebugEnabled())
                log.debug("Could not set the cookies from the base request:" + e);
        }
        sendAndReceive(nonexistfilemsg, false);
        byte[] nonexistfilemsgdata = nonexistfilemsg.getResponseBody().getBytes();
        //does the server give a 404 for a non-existent file? 
        if (nonexistfilemsg.getResponseHeader().getStatusCode() != HttpStatus.SC_NOT_FOUND) {
            gives404s = false;
            if (log.isDebugEnabled())
                log.debug("The server does not return a 404 status for a non-existent path: "
                        + nonexistfilemsg.getRequestHeader().getURI().getURI());
        } else {
            gives404s = true;
            if (log.isDebugEnabled())
                log.debug("The server gives a 404 status for a non-existent path: "
                        + nonexistfilemsg.getRequestHeader().getURI().getURI());
        }

        //now request a different (and non-existent) parent directory, 
        //to see whether a non-existent parent folder causes a 404 
        String[] pathbreak = temppath.split("/");
        if (pathbreak.length > 2) { //the file has a parent folder that is not the root folder (ie, there is a parent folder to mess with)
            String[] temppathbreak = pathbreak;
            String parentfoldername = pathbreak[pathbreak.length - 2];
            String randomparentfoldername = RandomStringUtils.random(parentfoldername.length(),
                    "abcdefghijklmoopqrstuvwxyz9123456789");

            //replace the parent folder name with the random one, and build it back into a string
            temppathbreak[pathbreak.length - 2] = randomparentfoldername;
            String randomparentpath = StringUtils.join(temppathbreak, "/");

            if (log.isDebugEnabled())
                log.debug("Trying non-existent parent path: " + randomparentpath);
            HttpMessage nonexistparentmsg = new HttpMessage(
                    new URI(originalURI.getScheme(), originalURI.getAuthority(), randomparentpath, null, null));
            try {
                nonexistparentmsg.setCookieParams(originalMessage.getCookieParams());
            } catch (Exception e) {
                if (log.isDebugEnabled())
                    log.debug("Could not set the cookies from the base request:" + e);
            }
            sendAndReceive(nonexistparentmsg, false);
            nonexistparentmsgdata = nonexistparentmsg.getResponseBody().getBytes();
            //does the server give a 404 for a non-existent parent folder? 
            if (nonexistparentmsg.getResponseHeader().getStatusCode() != HttpStatus.SC_NOT_FOUND) {
                parentgives404s = false;
                if (log.isDebugEnabled())
                    log.debug("The server does not return a 404 status for a non-existent parent path: "
                            + nonexistparentmsg.getRequestHeader().getURI().getURI());
            } else {
                parentgives404s = true;
                if (log.isDebugEnabled())
                    log.debug("The server gives a 404 status for a non-existent parent path: "
                            + nonexistparentmsg.getRequestHeader().getURI().getURI());
            }
        }

        String actualfilename = originalURI.getName();
        String actualfileExtension = null;
        String path = originalURI.getPath();
        if (path == null)
            path = "";

        //record the position of the various injection points, always relative to the full path         
        int positionExtensionInjection = 0;
        int positionFileSuffixInjection = 0;
        if (actualfilename.contains(".")) {
            positionExtensionInjection = path.lastIndexOf(".");
            positionFileSuffixInjection = positionExtensionInjection;
            actualfileExtension = actualfilename.substring(actualfilename.lastIndexOf("."));
        } else {
            positionExtensionInjection = path.length();
            positionFileSuffixInjection = path.length();
            actualfileExtension = "";
        }
        int positionFilePrefixInjection = path.lastIndexOf("/") + 1;
        int positionDirectorySuffixInjection = path.lastIndexOf("/");
        int positionDirectoryPrefixInjection = 0;
        if (positionDirectorySuffixInjection >= 0)
            positionDirectoryPrefixInjection = path.substring(0, positionDirectorySuffixInjection)
                    .lastIndexOf("/") + 1;

        //the set of files we will try, in the order of insertion
        Set<URI> candidateBackupFileURIs = new LinkedHashSet<URI>();
        Set<URI> candidateBackupFileChangedFolderURIs = new LinkedHashSet<URI>(); //for a changed parent folder name, which we need to handle separately 

        log.debug("The path is " + path);

        //for each file extension to try (both appending, and replacing)
        int counted = 0;
        for (String fileExtensionToTry : fileExtensions) {
            //to append, inject the file extension at the end of the path  
            String candidateBackupFilePath = path + fileExtensionToTry;
            log.debug("File Extension (append): '" + candidateBackupFilePath + "'");
            candidateBackupFileURIs.add(new URI(originalURI.getScheme(), originalURI.getAuthority(),
                    candidateBackupFilePath, null, null));

            //to replace the extension, append the file extension at positionExtensionInjection
            candidateBackupFilePath = path.substring(0, positionExtensionInjection) + fileExtensionToTry;
            log.debug("File Extension (replace): '" + candidateBackupFilePath + "'");
            candidateBackupFileURIs.add(new URI(originalURI.getScheme(), originalURI.getAuthority(),
                    candidateBackupFilePath, null, null));

            //to switch the extension (if there was one), append the file extension at positionExtensionInjection
            if (!actualfileExtension.equals("") && doSwitchFileExtension) {
                candidateBackupFilePath = path.substring(0, positionExtensionInjection) + fileExtensionToTry
                        + actualfileExtension;
                log.debug("File Extension (switch): '" + candidateBackupFilePath + "'");
                candidateBackupFileURIs.add(new URI(originalURI.getScheme(), originalURI.getAuthority(),
                        candidateBackupFilePath, null, null));
            }
            counted++;
            if (counted > numExtensionsToTry) {
                break; //out of the loop.
            }
        }

        //for each file suffix to try
        counted = 0;
        for (String fileSuffixToTry : fileSuffixes) {
            //inject the file suffix at positionFileSuffixInjection
            String candidateBackupFilePath = path.substring(0, positionFileSuffixInjection) + fileSuffixToTry
                    + (positionFileSuffixInjection >= path.length() ? ""
                            : path.substring(positionFileSuffixInjection));
            log.debug("File Suffix (insert): '" + candidateBackupFilePath + "'");
            candidateBackupFileURIs.add(new URI(originalURI.getScheme(), originalURI.getAuthority(),
                    candidateBackupFilePath, null, null));
            counted++;
            if (counted > numSuffixesToTry) {
                break; //out of the loop.
            }
        }

        //for each file prefix to try
        counted = 0;
        for (String filePrefixToTry : filePrefixes) {
            //inject the file prefix at positionFilePrefixInjection
            String candidateBackupFilePath = path.substring(0, positionFilePrefixInjection) + filePrefixToTry
                    + (positionFilePrefixInjection >= path.length() ? ""
                            : path.substring(positionFilePrefixInjection));
            log.debug("File Prefix (insert): '" + candidateBackupFilePath + "'");
            candidateBackupFileURIs.add(new URI(originalURI.getScheme(), originalURI.getAuthority(),
                    candidateBackupFilePath, null, null));
            counted++;
            if (counted > numPrefixesToTry) {
                break; //out of the loop.
            }
        }

        //for each directory suffix/prefix to try (using the file prefixes/suffixes - or whatever the plural of prefix/suffix is)         
        counted = 0;
        if (pathbreak.length > 2) {
            //if there is a a parent folder to play with 
            for (String fileSuffixToTry : fileSuffixes) {
                //inject the directory suffix at positionDirectorySuffixInjection
                String candidateBackupFilePath = path.substring(0, positionDirectorySuffixInjection)
                        + fileSuffixToTry + (positionDirectorySuffixInjection >= path.length() ? ""
                                : path.substring(positionDirectorySuffixInjection));
                log.debug("Directory Suffix (insert): '" + candidateBackupFilePath + "'");
                candidateBackupFileChangedFolderURIs.add(new URI(originalURI.getScheme(),
                        originalURI.getAuthority(), candidateBackupFilePath, null, null));
                counted++;
                if (counted > numSuffixesToTry) {
                    break; //out of the loop.
                }
            }
            for (String filePrefixToTry : filePrefixes) {
                //inject the directory prefix at positionDirectorySuffixInjection
                String candidateBackupFilePath = path.substring(0, positionDirectoryPrefixInjection)
                        + filePrefixToTry + (positionDirectoryPrefixInjection >= path.length() ? ""
                                : path.substring(positionDirectoryPrefixInjection));
                log.debug("Directory Suffix (insert): '" + candidateBackupFilePath + "'");
                candidateBackupFileChangedFolderURIs.add(new URI(originalURI.getScheme(),
                        originalURI.getAuthority(), candidateBackupFilePath, null, null));
                counted++;
                if (counted > numSuffixesToTry) {
                    break; //out of the loop.
                }
            }
        }

        //now we have a set of candidate URIs appropriate to the attack strength chosen by the user
        //try each candidate URI in turn.
        for (URI candidateBackupFileURI : candidateBackupFileURIs) {
            byte[] disclosedData = {};
            if (log.isDebugEnabled())
                log.debug("Trying possible backup file path: " + candidateBackupFileURI.getURI());
            HttpMessage requestmsg = new HttpMessage(candidateBackupFileURI);
            try {
                requestmsg.setCookieParams(originalMessage.getCookieParams());
            } catch (Exception e) {
                if (log.isDebugEnabled())
                    log.debug("Could not set the cookies from the base request:" + e);
            }
            //Do not follow redirects. They're evil. Yep.
            sendAndReceive(requestmsg, false);
            disclosedData = requestmsg.getResponseBody().getBytes();
            int requestStatusCode = requestmsg.getResponseHeader().getStatusCode();

            //just to complicate things.. I have a test case which for the random file, does NOT give a 404 (so gives404s == false) 
            //but for a "Copy of" file, actually gives a 404 (for some unknown reason). We need to handle this case.
            if ((gives404s && requestStatusCode != HttpStatus.SC_NOT_FOUND)
                    || ((!gives404s) && requestStatusCode != HttpStatus.SC_NOT_FOUND
                            && (!Arrays.equals(disclosedData, nonexistfilemsgdata)))) {
                bingo(Alert.RISK_MEDIUM, Alert.WARNING,
                        Constant.messages.getString("ascanalpha.backupfiledisclosure.name"),
                        Constant.messages.getString("ascanalpha.backupfiledisclosure.desc"),
                        requestmsg.getRequestHeader().getURI().getURI(), // originalMessage.getRequestHeader().getURI().getURI(),
                        null, //parameter being attacked: none.
                        candidateBackupFileURI.getURI(), //attack
                        originalMessage.getRequestHeader().getURI().getURI(), //new String (disclosedData),  //extrainfo
                        Constant.messages.getString("ascanalpha.backupfiledisclosure.soln"),
                        Constant.messages.getString("ascanalpha.backupfiledisclosure.evidence", originalURI,
                                candidateBackupFileURI.getURI()),
                        requestmsg //originalMessage
                );
            }

            if (isStop()) {
                if (log.isDebugEnabled())
                    log.debug("The scanner was stopped in response to a user request");
                return;
            }
        }

        //now try the changed parent folders (if any)
        //the logic here needs to check using the parent 404 logic, and the output for a non-existent parent folder.
        for (URI candidateBackupFileURI : candidateBackupFileChangedFolderURIs) {
            byte[] disclosedData = {};
            if (log.isDebugEnabled())
                log.debug("Trying possible backup file path (with changed parent folder): "
                        + candidateBackupFileURI.getURI());
            HttpMessage requestmsg = new HttpMessage(candidateBackupFileURI);
            try {
                requestmsg.setCookieParams(originalMessage.getCookieParams());
            } catch (Exception e) {
                if (log.isDebugEnabled())
                    log.debug("Could not set the cookies from the base request:" + e);
            }
            //Do not follow redirects. They're evil. Yep.
            sendAndReceive(requestmsg, false);
            disclosedData = requestmsg.getResponseBody().getBytes();
            int requestStatusCode = requestmsg.getResponseHeader().getStatusCode();

            if ((parentgives404s && requestStatusCode != HttpStatus.SC_NOT_FOUND)
                    || ((!parentgives404s) && requestStatusCode != HttpStatus.SC_NOT_FOUND
                            && (!Arrays.equals(disclosedData, nonexistparentmsgdata)))) {
                bingo(Alert.RISK_MEDIUM, Alert.WARNING,
                        Constant.messages.getString("ascanalpha.backupfiledisclosure.name"),
                        Constant.messages.getString("ascanalpha.backupfiledisclosure.desc"),
                        requestmsg.getRequestHeader().getURI().getURI(), //originalMessage.getRequestHeader().getURI().getURI(),
                        null, //parameter being attacked: none.
                        candidateBackupFileURI.getURI(), //attack
                        originalMessage.getRequestHeader().getURI().getURI(), //new String (disclosedData),  //extrainfo
                        Constant.messages.getString("ascanalpha.backupfiledisclosure.soln"),
                        Constant.messages.getString("ascanalpha.backupfiledisclosure.evidence", originalURI,
                                candidateBackupFileURI.getURI()),
                        requestmsg //originalMessage
                );
            }

            if (isStop()) {
                if (log.isDebugEnabled())
                    log.debug("The scanner was stopped in response to a user request");
                return;
            }
        }

    } catch (Exception e) {
        e.printStackTrace();
        log.error("Some error occurred when looking for a backup file for '"
                + originalMessage.getRequestHeader().getURI() + "': " + e);
        return;
    }

}

From source file:org.zaproxy.zap.extension.ascanrulesAlpha.RelativePathConfusionScanner.java

@Override
public void scan() {

    // get the base message. What else did you think this line of code might do??
    HttpMessage originalMsg = getBaseMsg();

    if (log.isDebugEnabled()) {
        log.debug("Attacking at Attack Strength: " + this.getAttackStrength());
        log.debug("Checking [" + originalMsg.getRequestHeader().getMethod() + "] ["
                + originalMsg.getRequestHeader().getURI() + "], for Relative Path Confusion issues");
    }//from   w  w w .  j a va2  s . c  om

    try {
        URI baseUri = originalMsg.getRequestHeader().getURI();
        String filename = baseUri.getName();
        String fileext = "";

        // is there a file extension at the end of the file name?
        if (filename != null && filename.length() > 0) {
            fileext = FilenameUtils.getExtension(filename);
        }

        // only filenames that have a file extension are potentially vulnerable to Relative Path
        // Confusion
        // (based on the instances of this that I've in seen in the wild, at least)
        if (fileext != null && fileext.length() > 0) {
            if (log.isDebugEnabled())
                log.debug("The file extension of " + baseUri.getURI() + " is " + fileext);

            // 1: First manipulate the URL, using a URL which is ambiguous..
            URI originalURI = originalMsg.getRequestHeader().getURI();
            String path = originalURI.getPath();
            if (path == null)
                path = "";
            String query = originalURI.getQuery();
            if (query == null)
                query = "";

            URI hackedUri = new URI(originalURI.getScheme(), originalURI.getAuthority(),
                    path + RANDOM_ATTACK_PATH + "?" + query, null, null);
            HttpMessage hackedMessage = new HttpMessage(hackedUri);
            try {
                hackedMessage.setCookieParams(originalMsg.getCookieParams());
            } catch (Exception e) {
                log.warn("Could not set the cookies from the base request:" + e);
            }
            try {
                sendAndReceive(hackedMessage, true); // follow redirects
            } catch (CircularRedirectException e) {
                log.warn("Ignoring a CircularRedirectException" + e);
            }

            // get ready to parse the HTML
            Document doc = Jsoup.parse(new String(hackedMessage.getResponseBody().getBytes()));
            String extraInfo = null;

            // 2: check if the response has a "<base>" tag specifying the base location for any
            // relative URLs
            // there can be a max of 1 <base> element in a document, and it must be inside the
            // <head> element
            // Example: <head><base href="http://www.w3schools.com/images/"
            // target="_blank"></head>
            Elements baseHrefInstances = doc.select("html > head > base[href]");
            if (!baseHrefInstances.isEmpty() && baseHrefInstances.size() == 1) {
                // a single base was specified, in line with HTTP spec
                if (log.isDebugEnabled())
                    log.debug(
                            "A base was specified, so there should be no confusion over relative paths (unless the User Agent is completely broken)");
                return;
            } else {
                if (!baseHrefInstances.isEmpty() && baseHrefInstances.size() > 1) {
                    extraInfo = Constant.messages.getString(MESSAGE_PREFIX + "extrainfo.morethanonebasetag");
                    if (log.isDebugEnabled())
                        log.debug("There more than one base (which is not valid HTML) specified for the page");
                } else {
                    if (extraInfo == null)
                        extraInfo = Constant.messages.getString(MESSAGE_PREFIX + "extrainfo.nobasetag");
                    if (log.isDebugEnabled())
                        log.debug("There is no base specified for the page");
                }
            }

            // 3: check if there are any resources that are loaded using relative URLs in the
            // response. (images, CSS, etc)
            boolean relativeReferenceFound = false;
            String relativeReferenceEvidence = "";

            Set<String> loadingHtmlAttributes = RELATIVE_LOADING_ATTRIBUTE_TO_TAGS.keySet();
            Iterator<String> i = loadingHtmlAttributes.iterator();
            for (; i.hasNext() && !relativeReferenceFound;) {
                String loadingHtmlAttribute = i.next();
                String[] loadingHtmlTags = RELATIVE_LOADING_ATTRIBUTE_TO_TAGS.get(loadingHtmlAttribute);

                for (int tagIndex = 0; tagIndex < loadingHtmlTags.length
                        && !relativeReferenceFound; tagIndex++) {
                    String tag = loadingHtmlTags[tagIndex];

                    // get instances of the specified HTML attribute and tag from the original
                    // response
                    // and see if is loading a relative URL.
                    // (ie, could it be confused if the server side can confuse the client side
                    // as to the absolute path to use when loading)
                    String selectStatement = (tag.equals("") ? "" : tag)
                            + (loadingHtmlAttribute.equals("") ? "" : "[" + loadingHtmlAttribute + "]");
                    Elements loadingTagInstances = doc.select(selectStatement);
                    int size = loadingTagInstances.size();

                    for (int index = 0; index < size && !relativeReferenceFound; index++) {
                        Element tagInstance = loadingTagInstances.get(index);

                        // handle style tags differently to other tags (for which we look at an
                        // attribute)
                        if (tag.toUpperCase().equals("STYLE")) {
                            // for the style tag, look at the entire body, not an attribute..
                            String styleBody = tagInstance.data();
                            if (log.isDebugEnabled())
                                log.debug("Got <style> data: " + styleBody);
                            Matcher matcher = STYLE_URL_LOAD.matcher(styleBody);
                            if (matcher.find()) {
                                relativeReferenceFound = true;
                                relativeReferenceEvidence = matcher.group();
                                if (log.isDebugEnabled())
                                    log.debug("Got relative STYLE reference in a style tag. Evidence: "
                                            + relativeReferenceEvidence);
                            }
                        } else {
                            // it's not the style tag, so look at the named attribute.
                            String attributeValue = tagInstance.attr(loadingHtmlAttribute);

                            if (log.isDebugEnabled())
                                log.debug("Got " + attributeValue + " for statement " + selectStatement);

                            // is it a relative reference?
                            String attributeUpper = attributeValue.toUpperCase().trim();
                            // if the reference starts with a scheme, it's absolute
                            // if it starts with "/", it's probably an absolute path (the host
                            // and scheme are inferred)
                            // if it starts with "//, it's a reference to the host and path (but
                            // not the scheme), and it's essentially an absolute reference..
                            if (!loadingHtmlAttribute.equals("style")) {
                                if (!attributeUpper.startsWith("HTTP://")
                                        && !attributeUpper.startsWith("HTTPS://")
                                        && !attributeUpper.startsWith("/")) {
                                    // it's a relative reference..
                                    relativeReferenceFound = true;
                                    // Note: since we parsed the HTML, and are reconstructing
                                    // the tag, this value may not exactly mirror the original
                                    // value in the HTML, but it's better than nothing. Whatcha
                                    // gonna do?
                                    // relativeReferenceEvidence = "<"+ tag + " " +
                                    // loadingHtmlAttribute + "=\"" + attributeValue + "\"";
                                    relativeReferenceEvidence = tagInstance.outerHtml();

                                    if (log.isDebugEnabled())
                                        log.debug("Got relative reference: " + attributeValue
                                                + " for statement " + selectStatement + ". Evidence: "
                                                + relativeReferenceEvidence);
                                }
                            } else {
                                // for the style attribute (on various tags), look for a pattern
                                // like "background: url(image.png)"
                                Matcher matcher = STYLE_URL_LOAD.matcher(attributeUpper);
                                if (matcher.find()) {
                                    relativeReferenceFound = true;
                                    relativeReferenceEvidence = attributeValue; // matcher.group();
                                    if (log.isDebugEnabled())
                                        log.debug("Got relative STYLE reference: " + attributeValue + " for "
                                                + tag + "." + loadingHtmlAttribute + ". Evidence: "
                                                + relativeReferenceEvidence);
                                }
                            }
                        }
                    }
                }
            }
            // TODO: what if the relative reference is occurring in the JavaScript??
            // if there are no relative references in the response, bale out, because there is
            // nothing to worry about
            if (!relativeReferenceFound) {
                if (log.isDebugEnabled())
                    log.debug(
                            "No relative references were found in the original response, so there is no possibility for confusion over relative path references)");
                return;
            }

            // 4: Now check the content type of the response.
            // If no Content Type was specified, happy days, we can move to the next check in
            // the knowledge that the content can
            // be interpreted a non-HTML content type by the web browser, if we can fool the
            // browser into loading the page.
            // If a content type is "Content-Type: text/html", we need to see if there is a way
            // to override the Content Type.
            // Known ways are:
            // a: Get the browser to render in Quirks Mode
            //      Note 1: Quirks mode might have been set in the response, without us having to do
            // anything else.. check!
            //      Note 2: Quirks mode is set if the response does not set a doctype, or uses an
            // old doctype
            //      Note 3: If quirks mode is not enabled, we may be able to enable it by setting it
            // on a framing page (if the page in question allows framing)
            //
            // TODO: Pass in a random filename (something like the
            // aaa/bbb/blah.php/xxx/yyy/zzz?a=1&b=2 request we use here)
            //       that ends in ".css", to see if the web server changes the content type to
            // "text/css" (unlikely!)
            String contentType = hackedMessage.getResponseHeader().getHeader(HttpHeader.CONTENT_TYPE);
            if (contentType != null) {

                if (log.isDebugEnabled())
                    log.debug("Content Type is set, so we need to see if there is a way to bypass it");
                boolean quirksMode = false;
                if (extraInfo == null)
                    extraInfo = Constant.messages.getString(MESSAGE_PREFIX + "extrainfo.contenttypeenabled",
                            contentType);
                else
                    extraInfo += "\n" + Constant.messages
                            .getString(MESSAGE_PREFIX + "extrainfo.contenttypeenabled", contentType);

                // a: Quirks mode!
                // Is it already enabled?
                // In the HEAD.. (Note: X-UA-Compatible trumps the doctype in IE)
                // <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
                // <meta http-equiv="X-UA-Compatible" content="IE=8" />
                // <meta http-equiv="x-ua-compatible" content="IE=9">
                // <meta http-equiv="x-ua-compatible" content="IE=edge" >   sets the page to
                // HTML5 mode, not quirks mode!!!

                // HTML 5: <!doctype html>                           sets the page to HTML5 mode

                Elements httpEquivInstances = doc.select("html > head > meta[http-equiv]");
                int size = httpEquivInstances.size();

                for (int index = 0; index < size; index++) {
                    Element e = httpEquivInstances.get(index);
                    String httpEquivAttributeValue = e.attr("http-equiv");
                    String contentAttributeValue = e.attr("content");

                    if (log.isDebugEnabled())
                        log.debug("Got " + httpEquivAttributeValue + " for html > head > meta[http-equiv]");
                    if (httpEquivAttributeValue.toUpperCase().trim().equals("X-UA-COMPATIBLE")
                            && !contentAttributeValue.toUpperCase().trim().equals("IE=EDGE")) {
                        // Quirks mode is already enabled!
                        // Note: if this is present, it overrides any "<!doctype html>" that
                        // would otherwise set the page to HTML5 mode
                        quirksMode = true;
                        if (log.isDebugEnabled())
                            log.debug(
                                    "Quirks mode is explicitly enabled via <meta http-equiv=\"x-ua-compatible\" (which overrides any \"<!doctype html>\" HTML 5 directive) ... This allows the specified Content Type to be bypassed");
                        if (extraInfo == null)
                            extraInfo = Constant.messages.getString(
                                    MESSAGE_PREFIX + "extrainfo.quirksmodeenabledexplicitly",
                                    httpEquivAttributeValue);
                        else
                            extraInfo += "\n" + Constant.messages.getString(
                                    MESSAGE_PREFIX + "extrainfo.quirksmodeenabledexplicitly",
                                    httpEquivAttributeValue);
                    }
                }
                // is quirks mode implicitly enabled via the absence of a doctype?
                // is quirks mode implicitly enabled via an old doctype?
                if (!quirksMode) {
                    boolean docTypeSpecified = false;
                    List<Node> nodes = doc.childNodes();
                    for (Node node : nodes) {
                        if (node instanceof DocumentType) {
                            docTypeSpecified = true;
                            DocumentType documentType = (DocumentType) node;
                            String docTypePublicId = documentType.attr("publicid");
                            // is the doctype old enough to enable quirks mode?
                            for (String doctypePublicIdTiggerQuirks : DOCTYPE_PUBLIC_IDS_TRIGGERING_QUIRKS_MODE) {
                                if (docTypePublicId.toUpperCase()
                                        .equals(doctypePublicIdTiggerQuirks.toUpperCase())) {
                                    // this doctype is know to trigger quirks mode in some
                                    // browsers..
                                    quirksMode = true;
                                    if (log.isDebugEnabled())
                                        log.debug(
                                                "Quirks mode is implicitly triggered via the use of old doctype "
                                                        + docTypePublicId
                                                        + ". This allows the specified Content Type to be bypassed");
                                    if (extraInfo == null)
                                        extraInfo = Constant.messages.getString(
                                                MESSAGE_PREFIX + "extrainfo.quirksmodeenabledimplicitly",
                                                docTypePublicId);
                                    else
                                        extraInfo += "\n" + Constant.messages.getString(
                                                MESSAGE_PREFIX + "extrainfo.quirksmodeenabledimplicitly",
                                                docTypePublicId);
                                    break;
                                }
                            }
                            if (log.isDebugEnabled())
                                log.debug("DocType public id: " + docTypePublicId + ". Entire thing: "
                                        + documentType);
                        }
                    }
                    if (!docTypeSpecified) {
                        quirksMode = true;
                        if (log.isDebugEnabled())
                            log.debug(
                                    "Quirks mode is implicitly enabled via the absence of a doctype... This allows the specified Content Type to be bypassed");
                        if (extraInfo == null)
                            extraInfo = Constant.messages.getString(
                                    MESSAGE_PREFIX + "extrainfo.quirksmodeenabledimplicitlynodoctype");
                        else
                            extraInfo += "\n" + Constant.messages.getString(
                                    MESSAGE_PREFIX + "extrainfo.quirksmodeenabledimplicitlynodoctype");
                    }
                }

                // if quirksMode is enabled, we do not need to check to see if framing attacks
                // are feasible
                boolean framingAttackPossible = false;
                if (!quirksMode) {
                    // if the framing attack does not work, check for a framing attack
                    String frameHeader = hackedMessage.getResponseHeader().getHeader(HttpHeader.X_FRAME_OPTION);
                    if (frameHeader != null) {
                        if (frameHeader.toUpperCase().equals("DENY")) {
                            // definitely rules out the framing attack (unless the user is using
                            // a dozy web browser that doesn't understand "X-FRAME-OPTIONS:
                            // DENY")
                            framingAttackPossible = false;
                            if (log.isDebugEnabled())
                                log.debug(
                                        "\"X-FRAME-OPTIONS: DENY\" rules out a framing attack, unless a really old browser is used (IE < 8.0, for instance)");
                        } else if (frameHeader.toUpperCase().equals("SAMEORIGIN")) {
                            // let's say this rules it out (unless the attacker has a persistent
                            // XSS, or already owns the site)
                            framingAttackPossible = false;
                            if (log.isDebugEnabled())
                                log.debug(
                                        "\"X-FRAME-OPTIONS: SAMEORIGIN\" rules out a framing attack, unless a really old browser is used (IE < 8.0, for instance)");
                        } else if (frameHeader.toUpperCase().startsWith("ALLOW-FROM")) {
                            // let's say this rules it out (unless the attacker has a persistent
                            // XSS, or already owns the site)
                            framingAttackPossible = false;
                            if (log.isDebugEnabled())
                                log.debug(
                                        "\"X-FRAME-OPTIONS: ALLOW-FROM\" probably rules out a framing attack, unless the attacker owns the website in the ALLOW-FROM, which is generally very unlikely");
                        }
                    } else {
                        // no framing headers were specified, so a framing attack is possible to
                        // force quicks mode, to bypass the Content-Type, which was specified
                        framingAttackPossible = true;
                        if (extraInfo == null)
                            extraInfo = Constant.messages
                                    .getString(MESSAGE_PREFIX + "extrainfo.framingallowed");
                        else
                            extraInfo += "\n"
                                    + Constant.messages.getString(MESSAGE_PREFIX + "extrainfo.framingallowed");
                    }
                }

                // if quirks mode is off, and a framing attack is not possible, we can't "break
                // out" of the content type.. boo hoo..
                if ((!quirksMode) && (!framingAttackPossible)) {
                    if (log.isDebugEnabled())
                        log.debug(
                                "Can't see a way to break out of the Content-Type, since Quirks mode is off (both explicit and implicit), and the page cannot be framed.");
                    return;
                }
            } else {
                // happy days. Content type is not set, so no hacks required to bypass it.
                if (log.isDebugEnabled())
                    log.debug("Content Type is not set, so no hacks are required to bypass it!");
                if (extraInfo == null)
                    extraInfo = Constant.messages.getString(MESSAGE_PREFIX + "extrainfo.nocontenttype");
                else
                    extraInfo += "\n" + Constant.messages.getString(MESSAGE_PREFIX + "extrainfo.nocontenttype");
            }

            // alert it..
            bingo(getRisk(), Alert.CONFIDENCE_MEDIUM, getName(), getDescription(),
                    getBaseMsg().getRequestHeader().getURI().getURI(), null, // parameter being attacked: none.
                    hackedUri.getURI(), // the attack is the URL itself
                    extraInfo, getSolution(), relativeReferenceEvidence, this.getCweId(), this.getWascId(),
                    hackedMessage);

            if (log.isDebugEnabled()) {
                log.debug("A Relative Path Confusion issue exists on "
                        + getBaseMsg().getRequestHeader().getURI().getURI());
            }
            return;

        } else {
            if (log.isDebugEnabled()) {
                log.debug(
                        "The URI has no filename component, so there is unlikely to be any ambiguity over any relative paths");
            }
        }
    } catch (Exception e) {
        log.error("Error scanning a request for Relative Path confusion: " + e.getMessage(), e);
    }
}

From source file:org.zaproxy.zap.extension.ascanrulesAlpha.SourceCodeDisclosureFileInclusion.java

/**
 * scans the given parameter for source code disclosure vulnerabilities, using path traversal
 * vulnerabilities/* w  ww .j a v a  2  s .co m*/
 */
@Override
public void scan(HttpMessage originalmsg, String paramname, String paramvalue) {
    try {
        URI uri = originalmsg.getRequestHeader().getURI();
        String path = uri.getPath();
        if (path == null || "/".equals(path)) {
            // No path or empty path, no point continuing.
            return;
        }

        if (log.isDebugEnabled()) {
            log.debug("Attacking at Attack Strength: " + this.getAttackStrength());
            log.debug("Checking [" + getBaseMsg().getRequestHeader().getMethod() + "] ["
                    + getBaseMsg().getRequestHeader().getURI() + "], parameter [" + paramname
                    + "], with original value [" + paramvalue + "] for Source Code Disclosure");
        }
        // the response of the original message is not populated! so populate it.
        sendAndReceive(originalmsg, false); // do nto follow redirects

        // first send a query for a random parameter value
        // then try a query for the file paths and names that we are using to try to get out the
        // source code for the current URL
        HttpMessage randomfileattackmsg = getNewMsg();
        setParameter(randomfileattackmsg, paramname, NON_EXISTANT_FILENAME);
        sendAndReceive(randomfileattackmsg, false); // do not follow redirects

        int originalversusrandommatchpercentage = calcMatchPercentage(originalmsg.getResponseBody().toString(),
                randomfileattackmsg.getResponseBody().toString());
        if (originalversusrandommatchpercentage > this.thresholdPercentage) {
            // the output for the "random" file does not sufficiently differ. bale out.
            if (log.isDebugEnabled()) {
                log.debug("The output for a non-existent filename [" + NON_EXISTANT_FILENAME
                        + "] does not sufficiently differ from that of the original parameter [" + paramvalue
                        + "], at " + originalversusrandommatchpercentage + "%, compared to a threshold of "
                        + this.thresholdPercentage + "%");
            }
            return;
        }

        if (this.isStop()) {
            if (log.isDebugEnabled())
                log.debug("Stopped, due to a user request");
            return;
        }

        // at this point, there was a sufficient difference between the random filename and the
        // original parameter
        // so lets try the various path names that might point at the source code for this URL
        String pathMinusLeadingSlash = uri.getPath().substring(1);
        String pathMinusApplicationContext = uri.getPath().substring(uri.getPath().indexOf("/", 1) + 1);

        // in the case of wavsep, should give us "wavsep"
        // use this later to build up "wavsep.war", and "wavsep.ear", for instance :)
        String applicationContext = uri.getPath().substring(1, uri.getPath().indexOf("/", 1));

        // all of the sourceFileNames should *not* lead with a slash.
        String[] sourceFileNames = { uri.getName(), pathMinusLeadingSlash, pathMinusApplicationContext };

        // and get the file extension (in uppercase), so we can switch on it (if there was an
        // extension, that is)
        String fileExtension = null;
        if (uri.getName().contains(".")) {
            fileExtension = uri.getName().substring(uri.getName().lastIndexOf(".") + 1);
            fileExtension = fileExtension.toUpperCase();
        }

        // for each of the file names in turn, try it with each of the prefixes
        for (String sourcefilename : sourceFileNames) {
            if (log.isDebugEnabled()) {
                log.debug("Source file is [" + sourcefilename + "]");
            }
            // for the url filename, try each of the prefixes in turn
            for (int h = 0; h < LOCAL_SOURCE_FILE_TARGET_PREFIXES.length; h++) {

                String prefixedUrlfilename = LOCAL_SOURCE_FILE_TARGET_PREFIXES[h] + sourcefilename;
                if (log.isDebugEnabled()) {
                    log.debug("Trying file name [" + prefixedUrlfilename + "]");
                }

                HttpMessage sourceattackmsg = getNewMsg();
                setParameter(sourceattackmsg, paramname, prefixedUrlfilename);
                // send the modified message (with the url filename), and see what we get back
                sendAndReceive(sourceattackmsg, false); // do not follow redirects

                int randomversussourcefilenamematchpercentage = calcMatchPercentage(
                        randomfileattackmsg.getResponseBody().toString(),
                        sourceattackmsg.getResponseBody().toString());
                if (randomversussourcefilenamematchpercentage > this.thresholdPercentage) {
                    // the output for the "source" file does not sufficiently differ from the
                    // random file name. bale out.
                    if (log.isDebugEnabled()) {
                        log.debug("The output for the source code filename [" + prefixedUrlfilename
                                + "] does not sufficiently differ from that of the random parameter, at "
                                + randomversussourcefilenamematchpercentage + "%, compared to a threshold of "
                                + this.thresholdPercentage + "%");
                    }
                } else {
                    // if we verified the response
                    if (dataMatchesExtension(sourceattackmsg.getResponseBody().getBytes(), fileExtension)) {
                        if (log.isDebugEnabled()) {
                            log.debug("Source code disclosure!  The output for the source code filename ["
                                    + prefixedUrlfilename
                                    + "] differs sufficiently from that of the random parameter, at "
                                    + randomversussourcefilenamematchpercentage
                                    + "%, compared to a threshold of " + this.thresholdPercentage + "%");
                        }

                        // if we get to here, is is very likely that we have source file
                        // inclusion attack. alert it.
                        bingo(Alert.RISK_HIGH, Alert.CONFIDENCE_MEDIUM,
                                Constant.messages.getString("ascanalpha.sourcecodedisclosure.lfibased.name"),
                                Constant.messages.getString("ascanalpha.sourcecodedisclosure.desc"),
                                getBaseMsg().getRequestHeader().getURI().getURI(), paramname,
                                prefixedUrlfilename,
                                Constant.messages.getString(
                                        "ascanalpha.sourcecodedisclosure.lfibased.extrainfo",
                                        prefixedUrlfilename, NON_EXISTANT_FILENAME,
                                        randomversussourcefilenamematchpercentage, this.thresholdPercentage),
                                Constant.messages.getString("ascanalpha.sourcecodedisclosure.lfibased.soln"),
                                Constant.messages.getString(
                                        "ascanalpha.sourcecodedisclosure.lfibased.evidence"),
                                sourceattackmsg);
                        // All done on this parameter
                        return;
                    } else {
                        if (log.isDebugEnabled()) {
                            log.debug("Could not verify that the HTML output is source code of type "
                                    + fileExtension + ". Next!");
                        }
                    }
                }
                if (this.isStop()) {
                    if (log.isDebugEnabled())
                        log.debug("Stopped, due to a user request");
                    return;
                }
            }
        }

        if (!inScope(Tech.Tomcat)) {
            return;
        }

        // if the above fails, get the entire WAR/EAR
        // but only if in HIGH or INSANE attack strength, since this generates more work and
        // slows Zap down badly if it actually
        // finds and returns the application WAR file!

        if (this.getAttackStrength() == AttackStrength.INSANE
                || this.getAttackStrength() == AttackStrength.HIGH) {

            // all of the warearFileNames should *not* lead with a slash.
            // TODO: should we consider uppercase / lowercase on (real) OSs such as Linux that
            // support such a thing?
            // Note that each of these file types can contain the Java class files, which can be
            // disassembled into the Java source code.
            // this in fact is one of my favourite hacking techniques.
            String[] warearFileNames = { applicationContext + ".war", applicationContext + ".ear",
                    applicationContext + ".rar" };

            // for each of the EAR / file names in turn, try it with each of the prefixes
            for (String sourcefilename : warearFileNames) {
                if (log.isDebugEnabled()) {
                    log.debug("WAR/EAR file is [" + sourcefilename + "]");
                }
                // for the url filename, try each of the prefixes in turn
                for (int h = 0; h < LOCAL_WAR_EAR_FILE_TARGET_PREFIXES.length; h++) {

                    String prefixedUrlfilename = LOCAL_WAR_EAR_FILE_TARGET_PREFIXES[h] + sourcefilename;
                    if (log.isDebugEnabled()) {
                        log.debug("Trying WAR/EAR file name [" + prefixedUrlfilename + "]");
                    }

                    HttpMessage sourceattackmsg = getNewMsg();
                    setParameter(sourceattackmsg, paramname, prefixedUrlfilename);
                    // send the modified message (with the url filename), and see what we get
                    // back
                    sendAndReceive(sourceattackmsg, false); // do not follow redirects
                    if (log.isDebugEnabled()) {
                        log.debug("Completed WAR/EAR file name [" + prefixedUrlfilename + "]");
                    }

                    // since the WAR/EAR file may be large, and since the LCS does not work well
                    // with such large files, lets just look at the file size,
                    // compared to the original
                    int randomversussourcefilenamematchpercentage = calcLengthMatchPercentage(
                            sourceattackmsg.getResponseBody().length(),
                            randomfileattackmsg.getResponseBody().length());
                    if (randomversussourcefilenamematchpercentage < this.thresholdPercentage) {
                        if (log.isDebugEnabled()) {
                            log.debug("Source code disclosure!  The output for the WAR/EAR filename ["
                                    + prefixedUrlfilename
                                    + "] differs sufficiently (in length) from that of the random parameter, at "
                                    + randomversussourcefilenamematchpercentage
                                    + "%, compared to a threshold of " + this.thresholdPercentage + "%");
                        }

                        // Note: no verification of the file contents in this case.

                        // if we get to here, is is very likely that we have source file
                        // inclusion attack. alert it.
                        bingo(Alert.RISK_HIGH, Alert.CONFIDENCE_MEDIUM,
                                Constant.messages.getString("ascanalpha.sourcecodedisclosure.lfibased.name"),
                                Constant.messages.getString("ascanalpha.sourcecodedisclosure.desc"),
                                getBaseMsg().getRequestHeader().getURI().getURI(), paramname,
                                prefixedUrlfilename,
                                Constant.messages.getString(
                                        "ascanalpha.sourcecodedisclosure.lfibased.extrainfo",
                                        prefixedUrlfilename, NON_EXISTANT_FILENAME,
                                        randomversussourcefilenamematchpercentage, this.thresholdPercentage),
                                Constant.messages.getString("ascanalpha.sourcecodedisclosure.lfibased.soln"),
                                Constant.messages.getString(
                                        "ascanalpha.sourcecodedisclosure.lfibased.evidence"),
                                sourceattackmsg);

                        // All done. No need to look for vulnerabilities on subsequent
                        // parameters on the same request (to reduce performance impact)
                        return;
                    } else {
                        if (log.isDebugEnabled()) {
                            log.debug("The output for the WAR/EAR code filename [" + prefixedUrlfilename
                                    + "] does not sufficiently differ in length from that of the random parameter, at "
                                    + randomversussourcefilenamematchpercentage
                                    + "%, compared to a threshold of " + this.thresholdPercentage + "%");
                        }
                    }
                    if (this.isStop()) {
                        if (log.isDebugEnabled())
                            log.debug("Stopped, due to a user request");
                        return;
                    }
                }
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug(
                        "Not checking for EAR/WAR files for this request, since the Attack Strength is not HIGH or INSANE");
            }
        }

    } catch (Exception e) {
        log.error("Error scanning parameters for Source Code Disclosure: " + e.getMessage(), e);
    }
}

From source file:org.zaproxy.zap.extension.ascanrulesAlpha.SourceCodeDisclosureGit.java

@Override
public void scan() {
    // 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;//  w  w w  .  j  a v a  2  s. co  m

    // scan the node itself (ie, at URL level, rather than at parameter level)
    if (log.isDebugEnabled()) {
        log.debug("Attacking at Attack Strength: " + this.getAttackStrength());
        log.debug("Checking [" + getBaseMsg().getRequestHeader().getMethod() + "] ["
                + getBaseMsg().getRequestHeader().getURI()
                + "], for Source Code Disclosure using Git meta-data");
    }

    try {
        URI uri = this.getBaseMsg().getRequestHeader().getURI();
        String filename = uri.getName();

        if (filename != null && filename.length() > 0) {
            // there is a file name at the end of the path.

            // Look for Git metadata that can be exploited to give us the source code.
            if (findSourceCodeGit(this.getBaseMsg())) {
                // found one. bale out.
                return;
            }

        } else {
            if (log.isDebugEnabled()) {
                log.debug(
                        "The URI has no filename component, so there is not much point in looking for corresponding source code!");
            }
        }
    } catch (Exception e) {
        log.error("Error scanning a request for Git based Source Code Disclosure: " + e.getMessage(), e);
    }
}

From source file:org.zaproxy.zap.extension.ascanrulesAlpha.SourceCodeDisclosureGit.java

/**
 * finds the source code for the given file, using Git metadata on the server (if this is
 * available)/*from w w w.  j a va2s.c o  m*/
 *
 * @param uri the URI of a file, whose source code we want to find
 * @return Did we find the source code?
 */
private boolean findSourceCodeGit(HttpMessage originalMessage) throws Exception {
    byte[] disclosedData = {};
    String gitsha1 = null;
    String gitindexpath = null;
    try {
        URI originalURI = originalMessage.getRequestHeader().getURI();
        // String originalURIWithoutQuery = originalURI.getScheme() + "://" +
        // originalURI.getAuthority() + originalURI.getPath();
        // String canonicalisedOriginalURIStringWithoutQuery =
        // URLCanonicalizer.getCanonicalURL(originalURIWithoutQuery);
        String path = originalURI.getPath();
        if (path == null)
            path = "";
        String filename = originalURI.getName();

        String fileExtension = null;
        if (filename.contains(".")) {
            fileExtension = filename.substring(filename.lastIndexOf(".") + 1);
            fileExtension = fileExtension.toUpperCase();
        }

        URI originalURIWithoutQuery = new URI(originalURI.getScheme(), originalURI.getAuthority(), path, null,
                null);
        GitMetadata git = new GitMetadata(this.getParent(), 4096);
        GitIndexEntryCache gitindexentrycache = GitIndexEntryCache.getSingleton();

        // look for the .git/index file in the directory and parent directories of the file for
        // which we are attempting to get the source code.
        String modifiedpath = path;
        byte[] data = {};
        boolean gitSHA1located = false;
        // work backwards from the original path, stripping off one folder at a time
        // until we find a valid Git index file that contains our file name!
        modifiedpath = modifiedpath.substring(0, modifiedpath.lastIndexOf("/") + 1); // leave the trailing slash on, if there was one
        while ((!modifiedpath.equals("")) && (!gitSHA1located)) {

            if (log.isDebugEnabled())
                log.debug("Path is " + modifiedpath);

            gitindexpath = modifiedpath + ".git/index";

            URI gitindexuri = new URI(originalURI.getScheme(), originalURI.getAuthority(), gitindexpath, null,
                    null);
            try {
                if (log.isDebugEnabled())
                    log.debug("Trying for a Git index file " + gitindexuri.getURI());

                if (!gitindexentrycache.isIndexCached(gitindexuri)) {
                    // The Git index is not cached, so parse it and cache it.
                    if (log.isDebugEnabled())
                        log.debug("Git Index " + gitindexuri.getURI()
                                + " is not cached. We will parse and cache it");

                    data = git.getURIResponseBody(gitindexuri, false, originalMessage);
                    // get the list of relative file paths and Git SHA1s from the file
                    Map<String, String> gitFiles = git.getIndexSha1s(data);
                    if (gitFiles != null) {
                        if (log.isDebugEnabled())
                            log.debug("We found a Git index file at '" + gitindexpath + "'");

                        Set<Entry<String, String>> entrySet = gitFiles.entrySet();
                        Iterator<Entry<String, String>> entryIterator = entrySet.iterator();
                        while (entryIterator.hasNext()) {
                            Entry<String, String> gitIndexEntry = entryIterator.next();

                            // the URIs from the Git index file do not have a query or fragment
                            // component, so no need to strip those off here
                            URI gitIndexEntryUri = new URI(originalURI.getScheme(), originalURI.getAuthority(),
                                    modifiedpath + gitIndexEntry.getKey(), null, null);
                            String gitSHA1Temp = gitIndexEntry.getValue();

                            // cache the entry..
                            if (log.isDebugEnabled())
                                log.debug("Caching Git Index file " + gitindexuri.getURI() + ", Index Entry "
                                        + gitIndexEntryUri.getURI() + ", SHA1 " + gitSHA1Temp);
                            gitindexentrycache.putIndexEntry(gitindexuri, gitIndexEntryUri, gitSHA1Temp);
                        }
                    }
                }
                // at this point, we know the Git index file is cached, one way or another.
                // did we get the Git SHA1 of the file we were interested in, after all that?
                if (gitindexentrycache.isIndexEntryCached(gitindexuri, originalURIWithoutQuery)) {
                    // no need to keep on looping back up, if we found our entry
                    gitSHA1located = true;
                    gitsha1 = gitindexentrycache.getIndexEntry(gitindexuri, originalURIWithoutQuery);
                    log.debug("Git SHA1 '" + gitsha1 + "' was found for Git index file '" + gitindexuri
                            + ", Git index entry file '" + originalURIWithoutQuery + "'");
                    break;
                } else {
                    log.debug("A cache entry was not found for Git index file '" + gitindexuri
                            + ", Git index entry file '" + originalURIWithoutQuery + "'");
                }

            } catch (Exception e) {
                if (log.isDebugEnabled())
                    log.debug("Ignoring an error getting/parsing '" + gitindexpath
                            + "', while trying to find the Git SHA1 value for '" + path + "': " + e);
            } finally {
                // move to the next parent directory, by first stripping off the trailing index,
                // and grabbing up to and including the last index
                modifiedpath = modifiedpath.substring(0, modifiedpath.length() - 1);
                modifiedpath = modifiedpath.substring(0, modifiedpath.lastIndexOf("/") + 1); // leave the trailing slash on, if there was one
            }

            if (isStop()) {
                if (log.isDebugEnabled())
                    log.debug(
                            "Stopped scanner (while trying to find the Git index file), due to a user request");
                return false;
            }
        }

        // do we have a shot at getting the source code using Git?
        if (gitsha1 == null || gitsha1.equals("") || gitindexpath == null || gitindexpath.equals("")) {
            if (log.isDebugEnabled())
                log.debug("A Git SHA1 value or Git index path for '" + path + "' was not found.");
            return false;
        }
        if (!git.validateSHA1(gitsha1)) {
            if (log.isDebugEnabled())
                log.debug("The 'gitsha1' parameter '" + gitsha1
                        + "' does not appear to be a valid format for a Git SHA1 value");
            return false;
        }
        String gitbasepath = git.getBaseFolder(gitindexpath);
        if (gitbasepath == null || gitbasepath.equals("")) {
            if (log.isDebugEnabled())
                log.debug("The 'gitindexpath' parameter '" + gitbasepath + "' does not appear to be valid.");
            return false;
        }
        // get the data from Git, using its SHA1 value.
        disclosedData = git.getObjectData(this.getBaseMsg(), gitbasepath, gitsha1); // look for data for the file's Git SHA1, and inflate it
        String gitURIs = git.getGitURIs();

        // so we have the data from Git for the sha1/file in questions.. does it match the
        // original data?
        // if not (but if it still looks valid), then throw a "source code disclosure" alert
        if (!Arrays.equals(disclosedData, originalMessage.getResponseBody().getBytes())) {

            // check the contents of the output to some degree, if we have a file extension.
            // if not, just try it (could be a false positive, but hey)
            if (dataMatchesExtension(disclosedData, fileExtension)) {
                if (log.isDebugEnabled()) {
                    log.debug("Source code disclosure, using Git metadata leakage!");
                }

                // source file inclusion attack. alert it.
                // Note that, unlike with SVN, the Git data is extracted not from one file, but
                // by parsing a series of files.
                // we cannot meaningfully raise an alert on any one file, except perhaps the
                // file on which the attack was launched.
                // it's the least worst way of doing it, IMHO.
                bingo(Alert.RISK_HIGH, Alert.CONFIDENCE_MEDIUM, getName(), getDescription(),
                        getBaseMsg().getRequestHeader().getURI().getURI(), null, // parameter being attacked: none.
                        null, // attack
                        new String(disclosedData), // Constant.messages.getString("ascanalpha.sourcecodedisclosure.gitbased.extrainfo", filename, StringUtils.join(gitURIs,", ")),     //extraInfo
                        getSolution(), getEvidence(filename, gitURIs), originalMessage);
                return true;
            }
            // does not match the extension
            return false;
        } else {
            if (log.isDebugEnabled())
                log.debug(
                        "The data disclosed via Git meta-data is not source code, since it matches the data served when we requested the file in the normal manner (source code is not served by web apps, and if it is, then you have bigger problems)");
            return false;
        }
    } catch (FileNotFoundException e) {
        if (log.isDebugEnabled())
            log.debug("A file was not found for SHA1 '" + gitsha1 + "'");
        return false;
    } catch (Exception e) {
        log.error("Some other error occurred when reading data for Git SHA1 '" + gitsha1 + "': " + e);
        return false;
    }
}

From source file:org.zaproxy.zap.extension.ascanrulesAlpha.SourceCodeDisclosureSVN.java

@Override
public void scan() {
    //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;/* ww  w .ja  v a2s.  co  m*/

    // scan the node itself (ie, at URL level, rather than at parameter level)
    if (log.isDebugEnabled()) {
        log.debug("Attacking at Attack Strength: " + this.getAttackStrength());
        log.debug("Checking [" + getBaseMsg().getRequestHeader().getMethod() + "] ["
                + getBaseMsg().getRequestHeader().getURI()
                + "], for Source Code Disclosure using SVN meta-data");
    }

    try {
        URI uri = this.getBaseMsg().getRequestHeader().getURI();
        String filename = uri.getName();

        if (filename != null && filename.length() > 0) {
            //there is a file name at the end of the path.

            //Look for SVN metadata that can be exploited to give us the source code.
            if (findSourceCodeSVN(this.getBaseMsg())) {
                //found one. no need to try other methods, so bale out.
                return;
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug(
                        "The URI has no filename component, so there is not much point in looking for corresponding source code!");
            }
        }
    } catch (Exception e) {
        log.error("Error scanning a request for SVN based Source Code Disclosure: " + e.getMessage(), e);
    }
}

From source file:org.zaproxy.zap.extension.ascanrulesAlpha.SourceCodeDisclosureSVN.java

/**
 * finds the source code for the given file, using SVN metadata on the server (if this is available)
 * @param uri the URI of a file, whose source code we want to find
 * @return Did we find the source code?/*from ww  w  . j  a  v  a2 s  . com*/
 */
private boolean findSourceCodeSVN(HttpMessage originalMessage) throws Exception {

    URI uri = originalMessage.getRequestHeader().getURI();
    String path = uri.getPath();
    if (path == null)
        path = "";
    //String filename = path.substring( path.lastIndexOf('/')+1, path.length() );
    String filename = uri.getName();

    String fileExtension = null;
    if (filename.contains(".")) {
        fileExtension = filename.substring(filename.lastIndexOf(".") + 1);
        fileExtension = fileExtension.toUpperCase();
    }

    //Look for SVN metadata containing source code
    String pathminusfilename = path.substring(0, path.lastIndexOf(filename));

    HttpMessage svnsourcefileattackmsg = new HttpMessage(new URI(uri.getScheme(), uri.getAuthority(),
            pathminusfilename + ".svn/text-base/" + filename + ".svn-base", null, null));
    svnsourcefileattackmsg.setCookieParams(this.getBaseMsg().getCookieParams());
    //svnsourcefileattackmsg.setRequestHeader(this.getBaseMsg().getRequestHeader());
    sendAndReceive(svnsourcefileattackmsg);

    //if we got a 404 specifically, then this is NOT a match
    //note that since we are simply relying on the file existing or not, we 
    //will not attempt any fuzzy matching. Old school.
    //this check is necessary, otherwise a recursive scan on nodes in the url path cause lots of false positives.
    if (svnsourcefileattackmsg.getResponseHeader().getStatusCode() != HttpStatusCode.NOT_FOUND) {

        if (!Arrays.equals(svnsourcefileattackmsg.getResponseBody().getBytes(),
                originalMessage.getResponseBody().getBytes())) {

            String attackFilename = uri.getScheme() + "://" + uri.getAuthority() + pathminusfilename
                    + ".svn/text-base/" + filename + ".svn-base";

            //check the contents of the output to some degree, if we have a file extension.
            //if not, just try it (could be a false positive, but hey)             
            if (dataMatchesExtension(svnsourcefileattackmsg.getResponseBody().getBytes(), fileExtension)) {
                log.info("Source code disclosure, using SVN metadata leakage!");

                //if we get to here, is is very likely that we have source file inclusion attack. alert it.
                bingo(Alert.RISK_HIGH, Alert.WARNING,
                        Constant.messages.getString("ascanalpha.sourcecodedisclosure.svnbased.name"),
                        Constant.messages.getString("ascanalpha.sourcecodedisclosure.desc"),
                        getBaseMsg().getRequestHeader().getURI().getURI(), null, attackFilename,
                        Constant.messages.getString("ascanalpha.sourcecodedisclosure.svnbased.extrainfo",
                                filename, attackFilename),
                        Constant.messages.getString("ascanalpha.sourcecodedisclosure.svnbased.soln"),
                        Constant.messages.getString("ascanalpha.sourcecodedisclosure.svnbased.evidence"),
                        svnsourcefileattackmsg);
                //if we found one, do not even try the "super" method, which tries each of the parameters,
                //since this is slow, and we already found an instance
                return true;
            } else {
                if (log.isDebugEnabled())
                    log.debug("The HTML output does not look like source code of type " + fileExtension);
            }
        } else {
            if (log.isDebugEnabled())
                log.debug(
                        "The data disclosed via SVN meta-data is not source code, since it matches the data served when we requested the file in the normal manner (source code is not served by web apps, and if it is, then you have bigger problems)");
            return false;
        }
    } else {
        if (log.isDebugEnabled()) {
            log.debug("Got a 404, so the SVN source code file was not found");
        }
    }
    return false;
}

From source file:org.zaproxy.zap.extension.ascanrulesBeta.BackupFileDisclosure.java

@Override
public void scan() {
    if (log.isDebugEnabled()) {
        log.debug("Attacking at Attack Strength: " + this.getAttackStrength());
        log.debug("Checking [" + getBaseMsg().getRequestHeader().getMethod() + "] ["
                + getBaseMsg().getRequestHeader().getURI() + "], for Backup File Disclosure");
    }//from  ww w  .j  a v a  2  s  .  c  om

    try {
        URI uri = this.getBaseMsg().getRequestHeader().getURI();
        String filename = uri.getName();

        int statusCode = this.getBaseMsg().getResponseHeader().getStatusCode();
        if (log.isDebugEnabled())
            log.debug("About to look for a backup for '" + uri.getURI() + "', which returned " + statusCode);

        // is it worth looking for a copy of the file?
        if (statusCode == HttpStatus.SC_NOT_FOUND) {
            if (log.isDebugEnabled())
                log.debug("The original file request was not successfuly retrieved (status = " + statusCode
                        + "), so there is not much point in looking for a backup of a non-existent file!");
            return;
        }
        if (filename != null && filename.length() > 0) {
            // there is a file name at the end of the path, so look for a backup file for the
            // file
            findBackupFile(this.getBaseMsg());
        } else {
            if (log.isDebugEnabled()) {
                log.debug(
                        "The URI has no filename component, so there is not much point in looking for a corresponding backup file!");
            }
        }
    } catch (Exception e) {
        log.error("Error scanning a request for Backup File Disclosure: " + e.getMessage(), e);
    }
}