Package org.owasp.jbrofuzz.core

Source Code of org.owasp.jbrofuzz.core.Verifier

/**
* JBroFuzz 2.4
*
* JBroFuzz - A stateless network protocol fuzzer for web applications.
*
* Copyright (C) 2007 - 2010 subere@uncon.org
* This file is part of JBroFuzz.
*
* JBroFuzz is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JBroFuzz is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JBroFuzz.  If not, see <http://www.gnu.org/licenses/>.
* Alternatively, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*
* Verbatim copying and distribution of this entire program file is
* permitted in any medium without royalty provided this notice
* is preserved.
*
*/
package org.owasp.jbrofuzz.core;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.CharUtils;
import org.apache.commons.lang.StringUtils;
import org.owasp.jbrofuzz.system.Logger;
import org.owasp.jbrofuzz.util.JBroFuzzFileFilter;

/**
* <p><code>Verifier</code> checks and loads the
* fuzzers from file.</p>
*
* <p>The structure of this code is inspired from
* Elliotte Rusty Harold, XOM nu.xom.Verifier
* class, without the nice optimizations</p>
*
* @author subere@uncon.org
* @version 2.0
* @since 2.0
*
*/
public final class Verifier {

  private Verifier() {}

  // The maximum number of chars to be read from file, regardless
  private static final int MAX_CHARS = Character.MAX_VALUE;
  // The maximum number of lines allowed to be read from the file
  private static final int MAX_LINES = 4096;
  // The maximum length of a line allowed
  private static final int MAX_LINE_LENGTH = 2048;

  // The maximum name length for a prototype
  private static final int MAX_PROTO_NAME_LENGTH = Byte.MAX_VALUE;
  // The maximum number of payloads in a prototype
  private static final int MAX_NO_OF_PAYLOADS = 1024;
  // The maximum number of categories of a prototype
  private static final int MAX_NO_OF_CATEGORIES = Byte.MAX_VALUE;

  private static final String ERROR_MSG = "\n\n\tBroken JBroFuzz Installation:\n\t";


  private static Map<String, Prototype> prototypes, headers = null;


  /**
   * <p>
   * Method called from the Database constructor to load the
   * fuzzers from file.
   * </p>
   *
   * <p>This method calls the internal method
   * parseFile(ClassLoader).</p>
   *
   * @return Map<String, Prototype>
   *
   * @author subere@uncon.org
   * @version 2.0
   * @since 2.0
   */
  public static Map<String, Prototype> loadFile(String fileName){

    // Validate string first of all

    if ("fuzzers.jbrf".equalsIgnoreCase(fileName)) {

      //      if (prototypes == null) {

      // Check for the existence of fuzzers.jbrf within the
      // current user directory
      final boolean extFilePresent = checkExternalFile(fileName);
      String inputContents;

      if(extFilePresent){
        Logger.log("Loading from the external file fuzzers.jbrf found in the current directory", 0);
        inputContents = Verifier.parseExtFile(fileName);

      } else {

        Logger.log("Loading from the internal file fuzzers.jbrf found in the current directory", 0);
        inputContents = Verifier.parseFile(fileName);

      }

      prototypes = new HashMap<String, Prototype>();

      Verifier.parsePrototypes(prototypes, inputContents);
      Logger.log("fuzzers.jbrf file loaded with " + prototypes.size() + " fuzzers", 0);
      return prototypes;

    } else if ("headers.jbrf".equalsIgnoreCase(fileName)) {

      //      if (headers == null) {
      final String headerContents = Verifier.parseFile(fileName);

      headers = new HashMap<String, Prototype>();

      Verifier.parsePrototypes(headers, headerContents);
      return headers;

    } else {

      throw new RuntimeException(ERROR_MSG
          + "is not a valid name to load " + fileName);

    }

  }

  /**
   * <p>Load any .jbrf file, given as input the absolute path of the file,
   * as a String.</p>
   *
   * <p>In the event of an error, load the default build-in fuzzers.jbrf
   * file, using the method loadFile().</p>
   *
   * @param fuzzersFilePath The absolute path of the .jbrf file
   *
   * @return
   */
  public static Map<String, Prototype> loadAnyFile(final String fuzzersFilePath) {

    if(fuzzersFilePath.length() > 512) {
      Logger.log("Cannot open a .jbrf file that has an absolute path greater than 512 characters", 4);
      return loadFile("fuzzers.jbrf");
    }

    if(!fuzzersFilePath.endsWith(".jbrf")) {
      Logger.log("Cannot open file, does not have a .jbrf extension", 4);
      return loadFile("fuzzers.jbrf");
    }

    final boolean extFilePresent = checkExternalFilePath(fuzzersFilePath);
    String inputContents;

    if(extFilePresent){

      inputContents = Verifier.parseExtFilePath(fuzzersFilePath);

    } else {

      inputContents = Verifier.parseFile("fuzzers.jbrf");

    }

    prototypes = new HashMap<String, Prototype>();

    Verifier.parsePrototypes(prototypes, inputContents);
    Logger.log("External file loaded with " + prototypes.size() + " fuzzers", 0);
    return prototypes;
  }

  /**
   * <p>Checks for the presence of an external file within the
   * current directory.</p>
   *
   * @param fileName
   * @return  true if the file is present and can be read, false
   *       otherwise.
   *
   * @author daemonmidi@gmail.com
   * @version 2.4
   * @since 2.4
   *
   * @author subere@uncon.org
   * @version 2.3
   * @since 2.1
   *
   *
   */
  private static boolean checkExternalFile(String fileName) {

    String dirString;
    try {

      dirString = System.getProperty("user.dir");

    } catch (final SecurityException e) {

      return false;

    }
    final File inputFile = new File(dirString + File.separator + fileName);
    JBroFuzzFileFilter jbfff = new JBroFuzzFileFilter();
    if (!jbfff.accept(inputFile)){
      return false;
    }
   
    if (inputFile.exists()) {

      if (inputFile.isDirectory()) {

        return false;
      }
      if (!inputFile.canRead()) {

        return false;

      }

      return true;

    } else {

      return false;

    }

  }

  /**
   * <p>Checks for the presence of an external file within any
   * directory.</p>
   *
   * @param fileNamePath The absolute path of the file
   *
   * @return  true if the file is present and can be read, false
   *       otherwise.
   *
   * @author subere@uncon.org
   * @version 2.1
   * @since 2.1
   */
  private static boolean checkExternalFilePath(String fileNamePath) {

    final File inputFile = new File(fileNamePath);

    if (inputFile.exists()) {

      if (inputFile.isDirectory()) {

        return false;
      }
      if (!inputFile.canRead()) {

        return false;

      }

      return true;

    } else {

      return false;

    }

  }

  /**
   * <p>Return the contents of an internal file a String.</p>
  
   * @param fileName e.g. fuzzers.jbrf; headers.jbrf
   * @return the contents of the file as a String
   *
   * @author subere@uncon.org
   * @version 2.1
   * @since 2.1
   */
  private static String parseExtFile(String fileName) {

    final File inputFile = new File(System.getProperty("user.dir") + File.separator + fileName);

    JBroFuzzFileFilter jbfff = new JBroFuzzFileFilter();
    if (!jbfff.accept(inputFile)){
      return "This file is not accepted";
    }
   
    if (inputFile.exists()) {
      if (inputFile.isDirectory()) {

        return "File is a directory:\n\n" + fileName;
      }
      if (!inputFile.canRead()) {

        return "File cannot be read:\n\n" + fileName;

      }
    } else {

      return "File does not exist:\n\n" + fileName;

    }

    int counter = 0;
    InputStream in = null;
    FileInputStream fis = null;
    final StringBuffer fileContents = new StringBuffer();
    try {
      fis = new FileInputStream(inputFile);
      in = new BufferedInputStream(fis);

      int c;
      // Read, having as upper maximum the int maximum
      while (((c = in.read()) > 0) && (counter <= MAX_CHARS)) {
        // Allow the character only if its printable ascii or \n
        if ((CharUtils.isAsciiPrintable((char) c))
            || (((char) c) == '\n')) {
          fileContents.append((char) c);
        }
        counter++;

      }

      in.close();
      fis.close();

    } catch (final IOException e) {

      return "Attempting to open the file caused an I/O Error:\n\n" + fileName;

    } finally {
      IOUtils.closeQuietly(in);
      IOUtils.closeQuietly(fis);
    }

    if(counter == MAX_CHARS) {
      final String maxMessage = "\n... stopped reading file after " + MAX_CHARS + " characters.\n";
      fileContents.append(maxMessage);
      Logger.log(maxMessage, 3);
    }
    return fileContents.toString();

  }

  /**
   * <p>Return the contents of any .jbrf file, given the
   * file's absolute path.</p>
  
   * @param fuzzersFilePath The absolute path pointing to
   * a .jbrf file
   * @return the contents of the file as a String
   *
   * @author subere@uncon.org
   * @version 2.1
   * @since 2.1
   */
  private static String parseExtFilePath(String fuzzersFilePath) {

    final File inputFile = new File(fuzzersFilePath);

    if (inputFile.exists()) {
      if (inputFile.isDirectory()) {

        return "File is a directory:\n\n" + fuzzersFilePath;
      }
      if (!inputFile.canRead()) {

        return "File cannot be read:\n\n" + fuzzersFilePath;

      }
    } else {

      return "File does not exist:\n\n" + fuzzersFilePath;

    }

    int counter = 0;
    InputStream in = null;
    FileInputStream fis = null;
    final StringBuffer fileContents = new StringBuffer();
    try {
      fis = new FileInputStream(inputFile);
      in = new BufferedInputStream(fis);

      int c;
      // Read, having as upper maximum the int maximum
      while (((c = in.read()) > 0) && (counter <= MAX_CHARS)) {
        // Allow the character only if its printable ascii or \n
        if ((CharUtils.isAsciiPrintable((char) c))
            || (((char) c) == '\n')) {
          fileContents.append((char) c);
        }
        counter++;

      }

      in.close();
      fis.close();

    } catch (final IOException e) {

      return "Attempting to open the file caused an I/O Error:\n\n" + fuzzersFilePath;

    } finally {
      IOUtils.closeQuietly(in);
      IOUtils.closeQuietly(fis);
    }

    if(counter == MAX_CHARS) {
      final String maxMessage = "\n... stopped reading file after " + MAX_CHARS + " characters.\n";
      fileContents.append(maxMessage);
      Logger.log(maxMessage, 3);
    }
    return fileContents.toString();

  }

  /**
   * <p>Return the contents of an internal file a String.</p>
  
   * @param fileName e.g. fuzzers.jbrf; headers.jbrf
   * @return the contents of the file as a String
   *
   * @author subere@uncon.org
   * @version 2.0
   * @since 2.0
   */
  private static String parseFile(String fileName) {

    final StringBuffer fileContents = new StringBuffer();

    // Attempt to read from the jar file
    final URL fileURL = ClassLoader.getSystemClassLoader().getResource(fileName);

    if (fileURL == null) {
      throw new RuntimeException(ERROR_MSG
          + "could not find " + fileName);
    }

    // Read the characters from the file
    BufferedReader in = null;
    try {
      final URLConnection connection = fileURL.openConnection();
      connection.connect();

      in = new BufferedReader(new InputStreamReader(connection
          .getInputStream()));

      int counter = 0;
      int c;
      while (((c = in.read()) > 0) && (counter < MAX_CHARS)) {
        // Allow the character only if its printable ascii or \n
        if ((CharUtils.isAsciiPrintable((char) c))
            || (((char) c) == '\n')) {
          fileContents.append((char) c);
        }
        counter++;
      }
      in.close();

      if(counter == MAX_CHARS) {

        throw new RuntimeException(ERROR_MSG
            + "\n... stopped reading file :" + fileName + "\nafter " + MAX_CHARS + " characters.\n\n");

      }

    } catch (final IOException e1) {
      throw new RuntimeException(ERROR_MSG
          + "could not read " + fileName);
    } finally {
      IOUtils.closeQuietly(in);
    }

    return fileContents.toString();
  }

  /**
   * <p>Method responsible for parsing the printable
   * String contents of the file fuzzers.jbrf to
   * the prototype HashMap.</p>
   *
   * @param input the .jbrf file in String input
   */
  private static void parsePrototypes(Map<String, Prototype> map, String input) {

    // Break down the file contents into lines
    final String[] fileInput = input.split("\n");

    if (fileInput.length > MAX_LINES) {
      throw new RuntimeException(ERROR_MSG +
          "fuzzers.jbrf has more than " + MAX_LINES + " lines.");
    }

    if (fileInput.length < 3) {
      throw new RuntimeException(ERROR_MSG +
      "fuzzers.jbrf does not have enough lines.");
    }

    for (int i = 0; i < fileInput.length; i++) {

      // Ignore comment lines starting with '#'
      if (fileInput[i].startsWith("#")) {
        continue;
      }

      // Ignore lines of length greater than MAX_LINE_LENGTH
      if (fileInput[i].length() > MAX_LINE_LENGTH) {
        continue;
      }

      // Check 1 indicating a likely prototype candidate
      try {
        if (fileInput[i].charAt(1) != ':') {
          continue;
        }
        if (fileInput[i].charAt(13) != ':') {
          continue;
        }

      } catch (final IndexOutOfBoundsException e1) {
        continue;
      }

      // [0] -> P || R || X
      // [1] -> "001-HTT-MTH"
      // [2] -> Uppercase HTTP Methods
      // [3] -> 8
      final String[] _fla = fileInput[i].split(":");

      // Check that there are four fields separated by :
      if (_fla.length != 4) {
        continue;
      }

      final char inputTypeChar = _fla[0].charAt(0);

      // Check [0] -> Fuzzer Type 'Z' or 'P', etc..
      if(!Prototype.isValidFuzzerType(inputTypeChar)) {
        continue;
      }

      // The Id: 009-SQL-INJ cannot be empty
      if (_fla[1].isEmpty()) {
        continue;
      }

      // The name: "SQL Injection" cannot be empty
      if (_fla[2].isEmpty()) {
        continue;
      }

      // Check the prototype name length
      if (_fla[2].length() > MAX_PROTO_NAME_LENGTH) {
        continue;
      }

      int noPayloads = 0;
      try {
        noPayloads = Integer.parseInt(_fla[3]);

      } catch (final NumberFormatException e) {
        continue;
      }

      // Check how many payloads this prototype has
      if (noPayloads > MAX_NO_OF_PAYLOADS) {
        continue;
      }

      // Allow only zero fuzzers to have no payloads
      if (noPayloads == 0) {
        continue;
      }

      // Check we have that many payloads left in file
      if (i + noPayloads > fileInput.length) {
        continue;
      }

      try {
        if (!fileInput[i + 1].startsWith(">")) {
          continue;
        }
        if (!fileInput[i + 2].startsWith(">>")) {
          continue;
        }
      } catch (final IndexOutOfBoundsException e) {
        continue;
      }

      String line2 = "";
      try {
        line2 = fileInput[i + 1].substring(1);
      } catch (final IndexOutOfBoundsException e) {
        continue;
      }

      String comment = "";
      try {
        comment = fileInput[i + 2].substring(2);
      } catch (final IndexOutOfBoundsException e) {
        continue;
      }

      // [0] -> HTTP Methods
      // [1] -> Replacive Fuzzers
      // [2] -> Uppercase Fuzzers
      final String[] _sla = line2.split("\\|");
      if (_sla.length > MAX_NO_OF_CATEGORIES) {
        continue;
      }

      // Alas! Finally create a prototype
      final Prototype proto =
        new Prototype(inputTypeChar, _fla[1], _fla[2]);

      // If categories do exist in the second line
      if (_sla.length > 0) {

        for (String categ_ry : _sla) {
          // add the category to the prototype
          categ_ry = StringUtils.stripEnd(categ_ry, " ");
          categ_ry = StringUtils.stripStart(categ_ry, " ");

          if (!categ_ry.isEmpty()) {
            proto.addCategory(categ_ry);
          }

        }
      }
      // If no categories have been identified,
      // add a default category
      else {

        proto.addCategory("JBroFuzz");

      }

      // Add the comment
      proto.addComment(comment);

      // Add the values of each payload
      for (int j = 1; j <= noPayloads; j++) {
        try {

          proto.addPayload(fileInput[i + 2 + j]);

        } catch (final IndexOutOfBoundsException e) {
          continue;
        }
      }

      // Finally add the prototype to the database
      map.put(_fla[1], proto);

    }

  }



}
TOP

Related Classes of org.owasp.jbrofuzz.core.Verifier

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.