Пример #1
0
    def getmissing(self):
        """
            Get missing capabilities
            :return:
                True - An error occurred
                [{capability}] - List of capabilities
            :raises Requester.ServerDown: The server could not be reached
        """
        url = Configuration.remote_server + "getmissing"
        Comunicator.info_logger("Getting missing capabilites at '%s'" % url)

        response = None
        try:
            response = requests.post(url,
                                     json={
                                         "apikey": self.apikey,
                                         "capabilities":
                                         Configuration.capabilities
                                     },
                                     timeout=10)
        except requests.exceptions.ConnectionError:
            raise Requester.ServerDown
        except requests.exceptions.Timeout:
            Comunicator.fatal_regular_message("Backend is unresponsive")
        if response.status_code == 502:
            raise Requester.ServerDown

        data, err = Requester._decode_json(response)
        if err != "":
            self.err_printer(
                "Error while retrieving missing capabilites '%s'" % err)
            return True

        return data
Пример #2
0
    def stopwork(self, suppress_stdout=False):
        """
            Stop current job
            :return:
                True - An error occurred
                None - Current job stopped
            :raises Requester.ServerDown: The server could not be reached
        """
        url = Configuration.remote_server + "stopwork"
        Comunicator.info_logger("Stopping work from '%s'" % url)

        response = None
        try:
            response = requests.post(url,
                                     data={"apikey": self.apikey},
                                     timeout=10)
        except requests.exceptions.ConnectionError:
            raise Requester.ServerDown
        except requests.exceptions.Timeout:
            Comunicator.fatal_regular_message("Backend is unresponsive")
        if response.status_code == 502:
            raise Requester.ServerDown

        _, err = Requester._decode_json(response)
        if err != "":
            msg = "Error stopping work '%s'" % err
            if suppress_stdout:
                Comunicator.error_logger(msg)
            else:
                self.err_printer(msg)
            return True

        return None
Пример #3
0
    def getfile(self, filename, path):
        """
            Download capability file
            :param filename: Filename of the capability to download
            :param path: Local relative path where to save the downloaded file
            :return:
                None - File downloaded
            :raises Requester.ServerDown: The server could not be reached
        """

        url = Configuration.remote_server + "getfile"
        Comunicator.info_logger("Getting file '%s' from '%s'" %
                                (filename, url))

        try:
            with requests.post(url,
                               data={
                                   "apikey": self.apikey,
                                   "file": filename
                               },
                               stream=True,
                               timeout=10) as req:
                req.raise_for_status()
                with open(path, "wb+") as fd:
                    for chunk in req.iter_content(chunk_size=8192):
                        if chunk:
                            fd.write(chunk)
        except requests.exceptions.ConnectionError:
            raise Requester.ServerDown
        except requests.exceptions.Timeout:
            Comunicator.fatal_regular_message("Backend is unresponsive")

        return None
Пример #4
0
    def checkfile(self, filename):
        """
            Check if a capability can be downloaded
            :return:
                True - An error occurred
                None - The file can be downloaded
            :raises Requester.ServerDown: The server could not be reached
         """
        url = Configuration.remote_server + "checkfile"
        Comunicator.info_logger("Checking if file '%s' exists at '%s'" %
                                (filename, url))

        response = None
        try:
            response = requests.post(url,
                                     data={
                                         "apikey": self.apikey,
                                         "file": filename
                                     },
                                     timeout=10)
        except requests.exceptions.ConnectionError:
            raise Requester.ServerDown
        except requests.exceptions.Timeout:
            Comunicator.fatal_regular_message("Backend is unresponsive")
        if response.status_code == 502:
            raise Requester.ServerDown

        _, err = Requester._decode_json(response)
        if err != "":
            self.err_printer("Error downloading '%s': '%s'" % (filename, err))
            return True

        return None
Пример #5
0
    def sendeta(self, eta):
        """
            Send eta for current
            :return:
                True - An error occurred
                None - Eta successfully sent
            :raises Requester.ServerDown: The server could not be reached
         """
        url = Configuration.remote_server + "sendeta"
        Comunicator.info_logger("Sending eta to '%s': '%s'" % (url, eta))

        response = None
        try:
            response = requests.post(url,
                                     data={
                                         "apikey": self.apikey,
                                         "eta": eta
                                     },
                                     timeout=10)
        except requests.exceptions.ConnectionError:
            raise Requester.ServerDown
        except requests.exceptions.Timeout:
            Comunicator.fatal_regular_message("Backend is unresponsive")
        if response.status_code == 502:
            raise Requester.ServerDown

        _, err = Requester._decode_json(response)
        if err != "":
            self.err_printer("Error sending eta '%s'" % err)
            return True

        return None
Пример #6
0
    def getwork(self):
        """
            Send a request for work to the server
            :return:
                None - Nothing can be down with capabilities
                False - A sha1 has does not match, capabilities need updating
                True - An error occurred
                {data} - Work data requested
            :raises Requester.ServerDown: The server could not be reached
        """
        url = Configuration.remote_server + "getwork"
        Comunicator.info_logger("Requesting work from '%s'" % url)

        response = None
        try:
            response = requests.post(url,
                                     json={
                                         "apikey": self.apikey,
                                         "capabilities":
                                         Configuration.capabilities
                                     },
                                     timeout=10)
        except requests.exceptions.ConnectionError:
            raise Requester.ServerDown
        except requests.exceptions.Timeout:
            Comunicator.fatal_regular_message("Backend is unresponsive")
        if response.status_code == 502:
            raise Requester.ServerDown

        data, err = Requester._decode_json(response)
        if err != "":
            if err == Configuration.cap_updated:
                return False

            if err == Configuration.no_work_message:
                return None

            self.err_printer("Error retrieving data from server '%s'" % err)
            return True

        return data
Пример #7
0
    def sendresult(self, password):
        """
            Send results for current job
            :param password: password for the current job, can be ""
            :return:
                False - The job expired
                True - An error occurred
                None - Current job stopped
            :raises Requester.ServerDown: The server could not be reached
        """
        url = Configuration.remote_server + "sendresult"
        Comunicator.info_logger("Sending result at '%s'" % url)

        response = None
        try:
            response = requests.post(url,
                                     data={
                                         "apikey": self.apikey,
                                         "password": password
                                     },
                                     timeout=10)
        except requests.exceptions.ConnectionError:
            raise Requester.ServerDown
        except requests.exceptions.Timeout:
            Comunicator.fatal_regular_message("Backend is unresponsive")
        if response.status_code == 502:
            raise Requester.ServerDown

        _, err = Requester._decode_json(response)
        if err != "":
            if err == Configuration.no_job_message:
                return False
            self.err_printer("Error while sending result '%s'" % err)
            return True

        return None
Пример #8
0
    def load_config():
        """
            Loads api key from file defined in variable Configuration.apikey_path.
            Ignores lines prefixed by '#', any leading ' ' and trailing '\n'
            The key is stored in Configuration.apikey
        :return:
            None
        """
        error_string = ""
        try:
            with open(Configuration.config_file) as file:
                config = json.load(file)

                def load_key(lkey):
                    try:
                        return config[lkey], ""
                    except KeyError:
                        return None, "Missing vital information '%s' from config file\n" % lkey

                Configuration.apikey, err = load_key("apikey")
                error_string += err
                Configuration.john_path, err = load_key("john_path")
                error_string += err
                Configuration.remote_server, err = load_key("server_location")
                error_string += err
                Configuration.hashcat_workload, err = load_key(
                    "hashcat_workload")
                error_string += err
        except json.decoder.JSONDecodeError as e:
            Comunicator.fatal_regular_message(
                "Configuration file '%s' is not a valid json with error '%s'. Fix"
                "file or completely remove to restore to default state." %
                (Configuration.config_file, e))
        except FileNotFoundError:
            with open(Configuration.config_file, "w") as fd:
                json.dump(Configuration.empty_config, fd)
            Comunicator.fatal_regular_message(
                "Configuration file '%s' did not exist. Empty file was generated, please"
                "fill in data for the cracker to properly work." %
                Configuration.config_file)
        if len(error_string) > 0:
            if error_string.endswith("\n"):
                error_string = error_string[:-1]
            Comunicator.fatal_regular_message(error_string)

        # Check remote server location
        if Configuration.remote_server is None or len(
                Configuration.remote_server) < 1:
            Comunicator.fatal_regular_message(
                "Invalid or missing remote server location. Please write server location"
                "in configuration file Ex. "
                "'\"server_location\": \"http://127.0.0.1:9645/\"'")
        if not (Configuration.remote_server.startswith("https://")
                or Configuration.remote_server.startswith("http://")):
            Comunicator.fatal_regular_message(
                "Server location should start with either 'https://' or 'http://'"
            )

        if not Configuration.remote_server.endswith("/"):
            Configuration.remote_server += "/"
        Configuration.remote_server += "api/v1/"

        Comunicator.printer("Using remote server '%s'" %
                            Configuration.remote_server)

        # Check hashcat workload
        if type(Configuration.hashcat_workload) is not int:
            Comunicator.fatal_regular_message(
                "Key 'hashcat_workload' from configuration file '%s' has invalid type %s"
                " instead of int" % (Configuration.config_file,
                                     type(Configuration.hashcat_workload)))
        if Configuration.hashcat_workload < 1 or Configuration.hashcat_workload > 4:
            Comunicator.dual_printer(
                Comunicator.logger.warn,
                "Hashcat workload should be 1-4. Value found is %d."
                "Using default 4")
            Configuration.hashcat_workload = 4

        # Check API key
        if Configuration.apikey is None or len(Configuration.apikey) < 10:
            Comunicator.fatal_regular_message(
                "Invalid or missing api key in config file '%s'. Please generate key "
                "and write it on the configuration file." %
                Configuration.config_file)

        # Check john path
        if len(Configuration.john_path) == 0:
            Configuration.john_path = None
        elif not os.path.exists(Configuration.john_path):
            Comunicator.fatal_regular_message(
                "Supplied path for john the ripper '%s' is not valid" %
                Configuration.john_path)
Пример #9
0
    def gather_capabilities():
        """
            Returns a dictionary of the client capabilities.
            The list has two types of items:
                1) Installed programs in the form of 'program': True
                2) Files in the form of 'filename': sha1hash(file)
            The hashes are used server side to check if the files changed in any way

            This function also calls Configuration.check_file() to check if files changed
            in any way
            :return:
                Dictionary as described above
        """
        sha1_file_changed = False

        # Check if local john configuration exists
        if os.path.isfile("john-local.conf") and Configuration.check_file(
                "john-local.conf", "john-local.conf"):
            sha1_file_changed = True

        for directory in Configuration.capab_dirs:
            if not os.path.isdir(directory):
                continue

            all_files = os.listdir(directory)

            for file in all_files:
                path = os.path.join(directory, file)
                if os.path.isfile(path) and not file.startswith("."):
                    if Configuration.check_file(path, file):
                        sha1_file_changed = True

        if sha1_file_changed:
            try:
                with open(Configuration.sha1s_filename, "w+") as fd:
                    json.dump(Configuration.old_sha1s, fd, indent=4)
            except Exception as e:
                Comunicator.fatal_debug_printer(
                    "Error trying to dump data in %s: %s" %
                    (Configuration.sha1s_filename, e))

        one_program = False
        for program in Configuration.programs:
            # John path needs to be hardcoded it seems
            # Only the key is relevant for hashcat/john - we mark them with True
            if program == "john":
                if Configuration.john_path is not None:
                    if not os.path.exists(Configuration.john_path):
                        Comunicator.fatal_debug_printer(
                            "Supplied john path '%s' is invalid. Check config file!"
                            % Configuration.john_path)
                    Configuration.capabilities[program] = True
                    one_program = True
                else:
                    Comunicator.printer(
                        "John the ripper not installed, some rules will not run until it is installed and "
                        "path supplied in config file '%s'" %
                        Configuration.config_file)
                continue

            if which(program) is not None:
                Configuration.capabilities[program] = True
                one_program = True
            else:
                Comunicator.printer(
                    "'%s' not installed, some rules will not run until it is installed"
                    % program)

        if not one_program:
            Comunicator.fatal_regular_message(
                "None of the cracking programs are installed, cracking not possible!"
            )