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)
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
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))
"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"), ], }
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)