Exemplo n.º 1
0
def analyseExtensionFromURI(
    uri,
    quiet=False,
    analysisPath=utils.getConfigPath()["appPathDataAnalysis"],
    downloadPath=utils.getConfigPath()["appPathDataFiles"],
    tmpPath=tempfile.gettempdir()):
    """
    Main function for Neto Analyser.

    Performs an analysis of a URI extension provided using the command line.

    Params:
    -------
        uri: The parameter options received from the command line.
        quiet: A boolean that defines whether to print an output.
        analysisPath: The folder where the anbalysis will be stored.
        downloadPath: The folder where the downloaded extension will be stored.
        tmpPath: The folder where unzipped files will be created.

    Returns:
    --------
        An Extension object.
    """
    if validations.isURI(uri):
        try:
            u = HTTPResource(uri)
            data = u.download()
            if data:
                # The name of the extension is formed by:
                #   <source>_<hashed_uri>_<extension_name>
                # Not that the hash is not the hash of the whole extension
                if uri.split("/")[-1] != "":
                    fileName = uri.split("/")[-1]
                else:
                    fileName = "Manual_" + md5.calculateHash(u.uri)
                filePath = os.path.join(downloadPath, fileName)
                if not quiet:
                    print("[*]\tRemote file is being stored as {}…".format(
                        filePath))
                with open(filePath, "wb") as oF:
                    oF.write(data)
        except ConnectionError as e:
            print(
                "[X]\tSomething happened when trying to download the resource. Have we been banned?\n"
                + str(e))
            return
    else:
        # If it is not a URI, assume that is a local path
        filePath = uri

    return analyseExtensionFromFile(filePath,
                                    tmpPath=tmpPath,
                                    analysisPath=outputPath,
                                    quiet=quiet)
Exemplo n.º 2
0
Arquivo: storage.py Projeto: mmg1/neto
def getExtensionList(analysisFolder=None):
    """
    Method that gets the list of working analysis

    This file is a summary of the contents stored in the analysis folder. This
    method is conceived to collect the currently available analysis.

    Args:
    -----
        analysisFolder: the folder where the JSON files generated by neto are
            stored.

    Returns:
    --------
        Returns a list of dictionaries with the list of performed analysis.
        [
            {
                "name": "sample.xpi",
                "analysis_path": "/…/0a0b0c….json",
                "sha256": "/…/sample.xpi",
            }
        ]
    """
    if not analysisFolder:
        analysisFolder = utils.getConfigPath()["appPathDataAnalysis"]

    extensions = []
    # List files inside the folder
    filenames = [f for f in os.listdir(analysisFolder) if os.path.isfile(os.path.join(analysisFolder, f))]

    for f in os.listdir(analysisFolder):
        filePath =  os.path.join(analysisFolder, f)
        if os.path.isfile(filePath):
            try:
                with open(filePath) as iF:
                    data = json.loads(iF.read())

                aux = {
                    "name": data["_filename"],
                    "analysis_path": filePath,
                    "sha256": filePath,
                }
                extensions.append(aux)
            except:
                pass
    return extensions
Exemplo n.º 3
0
def analyseExtensionFromFile(
    filePath,
    quiet=False,
    analysisPath=utils.getConfigPath()["appPathDataAnalysis"],
    tmpPath=tempfile.gettempdir()):
    """
    Main function for Neto Analyser.

    Performs an analysis of a locally stored file.

    Params:
    -------
        filePath: The local path to an extension.
        quiet: A boolean that defines whether to print an output.
        analysisPath: The folder where the extension will be stored.
        tmpPath: The folder where unzipped files will be created.

    Returns:
    --------
        An Extension object.

    Raises:
    """
    # Process the filePath
    if os.path.isfile(filePath):
        ext = Extension(filePath, tFolder=tmpPath)

        print("[*]\tData collected:\n" + str(ext))

        # Store the features extracted
        outputFile = os.path.join(analysisPath, ext.digest["md5"] + ".json")
        if not quiet:
            print(
                "[*]\tAdditional information about the extension can be found as a JSON at {}…"
                .format(outputFile))
        with open(outputFile, "w") as oF:
            oF.write(json.dumps(ext.__dict__, indent=2))
        return ext
    else:
        raise FileNotFoundError(
            "The filepath provided ({}) does not match with a file.".format(
                filePath))
Exemplo n.º 4
0
Arquivo: setup.py Projeto: mmg1/neto
        "requests",
        "json-rpc",
        "werkzeug",
        "configparser"
    ]
)


############################
### Creating other files ###
############################

HERE = os.path.abspath(os.path.dirname(__file__))


paths = utils.getConfigPath()


print("[*] Copying relevant files…")
files_to_copy= {
    paths["appPath"] : [
        os.path.join("config", "general.cfg"),
    ],
    paths["appPathDefaults"] : [
        os.path.join("config", "general.cfg"),
    ],
    paths["appPathPlugins"] : [
        os.path.join("config", "template.py.sample"),
    ],
}
Exemplo n.º 5
0
def main():
    """
    Main function for Neto

    It can deal with several tasks as specified in the application's help.

    Returns:
    --------
        An exit value. If 0, successful termination. Whatever else, an error.
    """
    # ===============
    # Add main parser
    # ===============

    parser = argparse.ArgumentParser(add_help=False)
    parser.formatter_class = argparse.RawDescriptionHelpFormatter
    parser.description = textwrap.dedent('''\
Neto | A tool to analyse browser extensions
-------------------------------------------

This package is intended to help security analysts when analysing different
types of browser extensions. Apart from this CLI, the utils in this package can
be used directly from other Python packages or by means of its JSON RPC
interface.

''')
    parser.epilog = textwrap.dedent('''\
  Exit status:
    The CLI will exit with one of the following values:

    0   Successful execution.
    1   Failed executions.
''')

    # ==============
    # Add subparsers
    # ==============

    subparsers = parser.add_subparsers(
        title="Subcommands",
        description=textwrap.dedent(
            '''  Available subcommands are invoked by typing 'neto <SUBCOMMAND>' where '<SUBCOMMAND>' is one of the actions listed below:

    analyser          Performs the analysis of one or several extensions.
    console           Starts an interactive application to conduct the analysis.
    daemon            Starts the JSON RPC daemon.

          ''') +
        textwrap.fill(
            "Appending '--help' to the full command will print the help for each one of them."
        ),
        dest="subcommand")

    # Analyser parser
    # ---------------
    analyserParser = subparsers.add_parser('analyser')
    analyserParser._optionals.title = "Input options (one required)"

    # Defining the mutually exclusive group for the main options
    analyserGroupMainOptions = analyserParser.add_mutually_exclusive_group(
        required=True)

    # Adding the main options
    analyserGroupMainOptions.add_argument(
        '-d',
        '--downloads',
        metavar='<PATH>',
        action='store',
        help='sets the folder that contains the downloaded extensions.')
    analyserGroupMainOptions.add_argument(
        '-e',
        '--extensions',
        metavar='<PATH>',
        nargs='+',
        action='store',
        help='receives one or several local files and performs the analysis.')
    analyserGroupMainOptions.add_argument(
        '-u',
        '--uris',
        metavar='<URI>',
        nargs='+',
        action='store',
        help=
        'receives one or several URIs, downloads them and performs the analysis of the extension found there.'
    )

    # Other options
    analyserGroupOther = analyserParser.add_argument_group(
        'Other arguments',
        textwrap.fill(
            'Advanced configuration of the behaviour of the analyser.'))
    # Adding optional parameters
    analyserGroupOther.add_argument(
        '--analysis_path',
        metavar='<PATH>',
        default=utils.getConfigPath()["appPathDataAnalysis"],
        action='store',
        help='sets a different path to store the analysis as a Json. Default: {}'
        .format(utils.getConfigPath()["appPathDataAnalysis"]))
    analyserGroupOther.add_argument(
        '--download_path',
        metavar='<PATH>',
        default=utils.getConfigPath()["appPathDataFiles"],
        action='store',
        help=
        'sets a different path to store the downloaded extensions. Default: {}'
        .format(utils.getConfigPath()["appPathDataFiles"]))
    analyserGroupOther.add_argument(
        '--temporal_path',
        metavar='<PATH>',
        default=os.path.join(tempfile.gettempdir(), "neto", "temporal"),
        action='store',
        help=
        'sets the path where the extensions will be extracted. It is recommended to use a temporal path. Default: {}'
        .format(os.path.join(tempfile.gettempdir(), "neto", "temporal")))
    analyserGroupOther.add_argument(
        '--clean',
        action='store_true',
        default=False,
        help=
        'removes all temporary generated files created in the unzipping process so as to free space.'
    )
    analyserGroupOther.add_argument(
        '--quiet',
        action='store_true',
        default=False,
        help='avoids printing the results in the terminal.')
    analyserGroupOther.add_argument(
        '--start',
        action='store',
        default=0,
        type=int,
        help=
        'sets the start index in case you analyse several files in a folder. This option can be used to relaunch experiments with a big series of files..'
    )
    analyserParser.set_defaults(func=neto.analyser.main)

    # Console parser
    # -------------
    consoleParser = subparsers.add_parser('console')

    # Other options
    consoleGroupOther = consoleParser.add_argument_group(
        'Other arguments',
        textwrap.fill(
            'Advanced configuration of the behaviour of the console UI, including temporal folders and output folders.'
        ))
    consoleGroupOther.add_argument(
        '--downloads',
        metavar='<PATH>',
        action='store',
        default=utils.getConfigPath()["appPathDataFiles"],
        help='the path where the extensions will be downloaded.')
    consoleGroupOther.add_argument(
        '--analysis',
        action='store',
        default=utils.getConfigPath()["appPathDataAnalysis"],
        help='sets the analysis folder where the JSON files will be stored.')
    consoleGroupOther.add_argument(
        '--working_directory',
        action='store',
        default=utils.getConfigurationFor("console")["working_directory"]
        or utils.getConfigPath()["appPathDataAnalysis"],
        help=
        'sets the path where previous analysis are supposed to be. The loaded analysis will be brought from here.'
    )
    consoleParser.set_defaults(func=neto.console.main)

    # Daemon parser
    # -------------
    daemonParser = subparsers.add_parser('daemon')

    # Add the main configuration options for the JSON RPC server
    daemonGroupOptions = daemonParser.add_argument_group(
        'Daemon Options',
        textwrap.fill('Configuring the behaviour of daemon.'))

    daemonGroupOptions.add_argument(
        "--port",
        type=int,
        help="Port to listen on",
        default=int(utils.getConfigurationFor("daemon")["port"]) or 14041,
        required=False)
    daemonGroupOptions.add_argument(
        "--host",
        type=str,
        help="Host to be listen on",
        default=utils.getConfigurationFor("daemon")["host"] or 'localhost',
    )
    daemonGroupOptions.add_argument('--debug',
                                    action='store_true',
                                    default=False,
                                    help='shows debug information.')

    # Other options
    daemonGroupOther = daemonParser.add_argument_group(
        'Other arguments',
        textwrap.fill(
            'Advanced configuration of the behaviour of the downloader, including temporal folders and output folders.'
        ))
    daemonGroupOther.add_argument(
        '--downloads',
        metavar='<PATH>',
        action='store',
        default=utils.getConfigPath()["appPathDataFiles"],
        help='the path where the extensions will be downloaded.')
    daemonGroupOptions.add_argument(
        '--analysis',
        action='store',
        default=utils.getConfigPath()["appPathDataAnalysis"],
        help='sets the analysis folder where the JSON files will be stored.')
    daemonParser.set_defaults(func=neto.daemon.main)

    # About options
    # -------------
    groupAbout = parser.add_argument_group(
        'About this package', 'Get additional information about this package.')
    groupAbout.add_argument('-h',
                            '--help',
                            action='help',
                            help='shows this help and exits.')
    groupAbout.add_argument('--license',
                            action='store_true',
                            default=False,
                            help='shows the GPLv3+ license and exits.')
    groupAbout.add_argument('--no-banner',
                            action='store_true',
                            help='avoids printing the initial banner.')
    groupAbout.add_argument(
        '--version',
        action='version',
        version='%(prog)s ' + neto.__version__,
        help='shows the version of this package and exits.')

    # =================
    # Process arguments
    # =================
    args = parser.parse_args()

    if not args.no_banner:
        print(extra.banner)

    if args.license:
        utils.showLicense()
    elif args.subcommand:
        args.func(args)
    else:
        parser.print_help()

    sys.exit(0)