Example #1
0
    def _build_cache(self, report_filename):
        """
        Reads in the results of a past report, parses them, and builds a dict
        such as:

        {
            "192.168.1.50": {'port': 22, 'authname': 'myauthname'},
        }
        """
        cache = {}
        f = open(report_filename)
        reader = csv.DictReader(f)
        for row in reader:
            if row['ip'] == '' or row['auth.name'] == '':
                # Looks like we couldn't login to this machine last time.
                continue

            cache[row['ip']] = {
                'port': int(row['port']),
                'auth': row['auth.name']
            }
            log.debug("Found cached results for: %s" % row['ip'])

        f.close()
        return cache
Example #2
0
    def main(self):

        (self.options, self.args) = self.parser.parse_args()
        # we dont need argv[0] in this list...
        self.args = self.args[1:]

        # Setup logging, this must happen early!
        setup_logging(self.options.log_file, self.options.log_level)
        log.debug("Running cli command: %s" % self.name)

        # Translate path to config file to something absolute and expanded:
        self.options.config = os.path.abspath(
            os.path.expanduser(self.options.config))
        log.debug("Absolute config file: %s" % self.options.config)

        self._validate_options()

        if len(sys.argv) < 2:
            print(self.parser.error(_("Please enter at least 2 args")))

        if RHO_PASSWORD in os.environ:
            log.info("Using passphrase from %s environment variable." %
                     RHO_PASSWORD)
            self.passphrase = os.environ[RHO_PASSWORD]
        else:
            self.passphrase = getpass(_("Config Encryption Password:"******"ERROR: Name already exists: %s") % e.dupe_name
            sys.exit(1)
Example #3
0
    def main(self):

        (self.options, self.args) = self.parser.parse_args()
        # we dont need argv[0] in this list...
        self.args = self.args[1:]

        # Setup logging, this must happen early!
        setup_logging(self.options.log_file, self.options.log_level)
        log.debug("Running cli command: %s" % self.name)

        # Translate path to config file to something absolute and expanded:
        self.options.config = os.path.abspath(os.path.expanduser(
            self.options.config))
        log.debug("Absolute config file: %s" % self.options.config)

        self._validate_options()

        if len(sys.argv) < 2:
            print(self.parser.error(_("Please enter at least 2 args")))

        if RHO_PASSWORD in os.environ:
            log.info("Using passphrase from %s environment variable." %
                    RHO_PASSWORD)
            self.passphrase = os.environ[RHO_PASSWORD]
        else:
            self.passphrase = getpass(_("Config Encryption Password:"******"ERROR: Name already exists: %s") % e.dupe_name
            sys.exit(1)
Example #4
0
def read_file(filename, password):
    """
    Decrypt contents of file with the given key, and return as a string.

    Assume that we're reading files that we encrypted. (i.e. we're not trying
    to read files encrypted manually with gpg)

    Also note that the password here is the user password, not the actual
    AES key. To get that we must read the first 8 bytes of the file to get
    the correct salt to use to convert the password to the key.

    Returns a tuple of (salt, json)
    """
    if not os.path.exists(filename):
        raise NoSuchFileException()

    f = open(filename, 'r')
    # 2 byte version in hex
    ver = f.read(2)
    # 8 byte salt
    salt = f.read(8)
    # 16 byte initialization vector
    iv = f.read(16)
    log.debug("Read version: %s salt: %s  iv: %s" % (ver, salt, iv))

    cont = f.read()
    try:
        return_me = decrypt(cont, password, salt, iv)
    except Exception, e:
        log.warn("Exception while decrypting the configuration file: %s" % e)
        #        raise
        raise DecryptionException
Example #5
0
File: crypto.py Project: idmf/rho
def read_file(filename, password):
    """
    Decrypt contents of file with the given key, and return as a string.

    Assume that we're reading files that we encrypted. (i.e. we're not trying
    to read files encrypted manually with gpg)

    Also note that the password here is the user password, not the actual
    AES key. To get that we must read the first 8 bytes of the file to get
    the correct salt to use to convert the password to the key.

    Returns a tuple of (salt, json)
    """
    if not os.path.exists(filename):
        raise NoSuchFileException()

    f = open(filename, 'r')
    # 2 byte version in hex
    ver = f.read(2)
    # 8 byte salt
    salt = f.read(8)
    # 16 byte initialization vector
    iv = f.read(16)
    log.debug("Read version: %s salt: %s  iv: %s" % (ver, salt, iv))

    cont = f.read()
    try:
        return_me = decrypt(cont, password, salt, iv)
    except Exception, e:
        log.warn("Exception while decrypting the configuration file: %s" % e)
#        raise
        raise DecryptionException
Example #6
0
    def _validate_options(self):
        CliCommand._validate_options(self)

        # We support two ways to specify profiles, with --profile=blah, or
        # without --profile= and just list profiles in the command. Hack here
        # to treat those raw args as --profiles so the subsequent code has just
        # one path.
        self.options.profiles.extend(self.args)

        hasRanges = len(self.options.ranges) > 0
        hasProfiles = len(self.options.profiles) > 0
        hasAuths = len(self.options.auth) > 0
        hasHosts = len(self.options.hosts) > 0
        hasReportFormat = len(self.options.reportformat) > 0
        hasReport = len(self.options.report) > 0
        hasReportFile = len(self.options.reportfile) > 0

        if self.options.cachefile:
            self.options.cachefile = os.path.abspath(os.path.expanduser(
                self.options.cachefile))
            log.debug("Using cached output: %s" % self.options.cachefile)
            if not os.path.exists(self.options.cachefile):
                self.parser.error(_("No such file: %s" % self.options.cachefile))

        if hasRanges:
            self._validate_ranges(self.options.ranges)

        if not hasRanges and not hasProfiles and not self.options.showfields and not hasHosts:
            self.parser.print_help()
            sys.exit(1)

        if hasRanges and hasProfiles:
            self.parser.error(_("Cannot scan ranges and profiles at the same time."))

        if self.options.username and hasAuths:
            self.parser.error(_("Cannot specify both --username and --auth"))

        if hasProfiles and hasAuths:
            self.parser.error(_("Cannot specify both auths and ranges."))

        if hasRanges and not (self.options.username or hasAuths):
            self.parser.error(_(
                "--username or --auth required to scan a range."))
        if hasReport:
            if hasReportFormat:
                self.parser.error(_(
                    "Cannot specify both report-format and report."))
            if hasReportFile:
                self.parser.error(_(
                    "Cannot specify both report and output filename."))
Example #7
0
def write_file(filename, plaintext, key):
    """ 
    Encrypt plaintext with the given key and write to file. 
    
    Existing file will be overwritten so be careful. 
    """
    f = open(filename, 'w')
    salt = os.urandom(8)
    iv = os.urandom(16)
    # a hex version string
    f.write("%2X" % CONFIG_VERSION)
    f.write(salt)
    f.write(iv)
    log.debug("version: %s salt: %s iv: %s" % (CONFIG_VERSION, salt, iv))
    f.write(encrypt(plaintext, key, salt, iv))
    f.close()
Example #8
0
File: crypto.py Project: idmf/rho
def write_file(filename, plaintext, key):
    """ 
    Encrypt plaintext with the given key and write to file. 
    
    Existing file will be overwritten so be careful. 
    """
    f = open(filename, 'w')
    salt = os.urandom(8)
    iv = os.urandom(16)
    # a hex version string
    f.write("%2X" % CONFIG_VERSION)
    f.write(salt)
    f.write(iv)
    log.debug("version: %s salt: %s iv: %s" % (CONFIG_VERSION, salt, iv))
    f.write(encrypt(plaintext, key, salt, iv))
    f.close()
Example #9
0
    def _validate_options(self):
        CliCommand._validate_options(self)

        # We support two ways to specify profiles, with --profile=blah, or
        # without --profile= and just list profiles in the command. Hack here
        # to treat those raw args as --profiles so the subsequent code has just
        # one path.
        self.options.profiles.extend(self.args)

        hasRanges = len(self.options.ranges) > 0
        hasProfiles = len(self.options.profiles) > 0
        hasAuths = len(self.options.auth) > 0

        if self.options.cachefile:
            self.options.cachefile = os.path.abspath(
                os.path.expanduser(self.options.cachefile))
            log.debug("Using cached output: %s" % self.options.cachefile)
            if not os.path.exists(self.options.cachefile):
                self.parser.error(
                    _("No such file: %s" % self.options.cachefile))

        if hasRanges:
            self._validate_ranges(self.options.ranges)

        if not hasRanges and not hasProfiles and not self.options.showfields:
            self.parser.print_help()
            sys.exit(1)

        if hasRanges and hasProfiles:
            self.parser.error(
                _("Cannot scan ranges and profiles at the same time."))

        if self.options.username and hasAuths:
            self.parser.error(_("Cannot specify both --username and --auth"))

        if hasProfiles and hasAuths:
            self.parser.error(_("Cannot specify both auths and ranges."))

        if hasRanges and not (self.options.username or hasAuths):
            self.parser.error(
                _("--username or --auth required to scan a range."))
Example #10
0
    def _build_cache(self, report_filename):
        """
        Reads in the results of a past report, parses them, and builds a dict
        such as:

        {
            "192.168.1.50": {'port': 22, 'authname': 'myauthname'},
        }
        """
        cache = {}
        f = open(report_filename)
        reader = csv.DictReader(f)
        for row in reader:
            if row['ip'] == '' or row['auth.name'] == '':
                # Looks like we couldn't login to this machine last time.
                continue

            cache[row['ip']] = {'port': int(row['port']), 'auth': row['auth.name']}
            log.debug("Found cached results for: %s" % row['ip'])

        f.close()
        return cache
Example #11
0
File: scanner.py Project: wzzrd/rho
    def scan_profiles(self, profilenames):
        missing_profiles = []
        ssh_job_list = []
        for profilename in profilenames:
            profile = self.config.get_profile(profilename)
            if profile is None:
                missing_profiles.append(profilename)
                continue
            ips = []
            for range_str in profile.ranges:
                ipr = rho_ips.RhoIpRange(range_str)
                ips.extend(ipr.list_ips())

            for ip in ips:

                # Create a copy of the list of ports and authnames,
                # we're going to modify them if we have a cache hit:
                ports = list(profile.ports)
                authnames = list(profile.auth_names)

                # If a cache hit, move the port/auth to the start of the list:
                if ip in self.cache:
                    log.debug("Cache hit for: %s" % ip)
                    cached_port = self.cache[ip]['port']
                    log.debug("Cached port: %s %s" %
                              (cached_port, type(cached_port)))
                    cached_authname = self.cache[ip]['auth']
                    if cached_port in ports:
                        ports.remove(cached_port)
                        ports.insert(0, cached_port)
                        log.debug("trying port %s first" % cached_port)
                    if cached_authname in authnames:
                        authnames.remove(cached_authname)
                        authnames.insert(0, cached_authname)
                        log.debug("trying auth %s first" % cached_authname)

                sshj = ssh_jobs.SshJob(ip=ip,
                                       ports=ports,
                                       auths=self._find_auths(authnames),
                                       rho_cmds=self.get_rho_cmds(),
                                       allow_agent=self.allow_agent)
                ssh_job_list.append(sshj)

        self.ssh_jobs.ssh_jobs = ssh_job_list
        self._run_scan()

        return missing_profiles
Example #12
0
File: scanner.py Project: idmf/rho
    def scan_profiles(self, profilenames):
        missing_profiles = []
        ssh_job_list = []
        for profilename in profilenames:
            profile = self.config.get_profile(profilename)
            if profile is None:
                missing_profiles.append(profilename)
                continue
            ips = []
            for range_str in profile.ranges:
                ipr = rho_ips.RhoIpRange(range_str)
                ips.extend(ipr.list_ips())

            for ip in ips:

                # Create a copy of the list of ports and authnames,
                # we're going to modify them if we have a cache hit:
                ports = list(profile.ports)
                authnames = list(profile.auth_names)

                # If a cache hit, move the port/auth to the start of the list:
                if ip in self.cache:
                    log.debug("Cache hit for: %s" % ip)
                    cached_port = self.cache[ip]['port']
                    log.debug("Cached port: %s %s" % (cached_port,
                        type(cached_port)))
                    cached_authname = self.cache[ip]['auth']
                    if cached_port in ports:
                        ports.remove(cached_port)
                        ports.insert(0, cached_port)
                        log.debug("trying port %s first" % cached_port)
                    if cached_authname in authnames:
                        authnames.remove(cached_authname)
                        authnames.insert(0, cached_authname)
                        log.debug("trying auth %s first" % cached_authname)

                sshj = ssh_jobs.SshJob(ip=ip, ports=ports,
                                       auths=self._find_auths(authnames),
                                       rho_cmds=self.get_rho_cmds(),
                                       allow_agent=self.allow_agent)
                ssh_job_list.append(sshj)

        self.ssh_jobs.ssh_jobs = ssh_job_list
        self._run_scan()

        return missing_profiles
Example #13
0
File: ssh_jobs.py Project: idmf/rho
    def connect(self, ssh_job):
        # do the actual paramiko ssh connection

        # Copy the list of ports, we'll modify it as we go:
        ports_to_try = list(ssh_job.ports)

        found_port = None # we'll set this once we identify a port that works
        found_auth = False

        while True:
            if found_auth:
                break

            if found_port != None:
                log.warn("Found ssh on %s:%s, but no auths worked." %
                        (ssh_job.ip, found_port))
                break

            if len(ports_to_try) == 0:
                log.debug("Could not find/connect to ssh on: %s" % ssh_job.ip)
                err = _("unable to connect")
                ssh_job.error = err
                break

            port = ports_to_try.pop(0)

            for auth in ssh_job.auths:
                ssh_job.error = None

                debug_str = "%s:%s/%s" % (ssh_job.ip, port, auth.name)
                # this checks the case of a passphrase we can't decrypt
                try:
                    pkey = get_pkey(auth)
                except paramiko.SSHException, e:
                    # paramiko throws an SSHException for pretty much everything... ;-<
                    log.error("ssh key error for %s: %s" % (debug_str, str(e)))
                    ssh_job.error = str(e)
                    continue

                self.ssh = paramiko.SSHClient()
                self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

                try:
                    log.info("trying: %s" % debug_str)

                    self.show_connect(ssh_job, port, auth)
                    self.ssh.connect(ssh_job.ip, port=int(port), 
                                     username=auth.username,
                                     password=auth.password,
                                     pkey=pkey,
                                     allow_agent=ssh_job.allow_agent,
                                     look_for_keys=ssh_job.look_for_keys,
                                     timeout=ssh_job.timeout)
                    ssh_job.port = port
                    ssh_job.auth = auth
                    found_port = port
                    found_auth = True
                    log.info("success: %s" % debug_str)
                    break

                # Implies we've found an SSH server listening:
                except paramiko.AuthenticationException, e:
                    # Because we stop checking ports once we find one where ssh
                    # is listening, we can report the error message here and it
                    # will end up in the final report correctly:
                    err = _("login failed")
                    log.error(err)
                    ssh_job.error = err
                    found_port = port
                    continue

                # No route to host:
                except socket.error, e:
                    log.warn("No route to host, skipping port: %s" % debug_str)
                    ssh_job.error = str(e)
                    break
Example #14
0
    def connect(self, ssh_job):
        # do the actual paramiko ssh connection

        # Copy the list of ports, we'll modify it as we go:
        ports_to_try = list(ssh_job.ports)

        found_port = None  # we'll set this once we identify a port that works
        found_auth = False

        while True:
            if found_auth:
                break

            if found_port is not None:
                log.warn("Found ssh on %s:%s, but no auths worked." %
                         (ssh_job.ip, found_port))
                break

            if len(ports_to_try) == 0:
                log.debug("Could not find/connect to ssh on: %s" % ssh_job.ip)
                err = _("unable to connect")
                ssh_job.error = err
                break

            port = ports_to_try.pop(0)

            for auth in ssh_job.auths:
                ssh_job.error = None

                debug_str = "%s:%s/%s" % (ssh_job.ip, port, auth.name)
                # this checks the case of a passphrase we can't decrypt
                try:
                    pkey = get_pkey(auth)
                except paramiko.SSHException as e:
                    # paramiko throws an SSHException for pretty much everything... ;-<
                    log.error("ssh key error for %s: %s" % (debug_str, str(e)))
                    ssh_job.error = str(e)
                    continue

                self.ssh = paramiko.SSHClient()
                self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

                try:
                    log.info("trying: %s" % debug_str)

                    self.show_connect(ssh_job, port, auth)
                    self.ssh.connect(ssh_job.ip, port=int(port),
                                     username=auth.username,
                                     password=auth.password,
                                     pkey=pkey,
                                     allow_agent=ssh_job.allow_agent,
                                     look_for_keys=ssh_job.look_for_keys,
                                     timeout=ssh_job.timeout)
                    ssh_job.port = port
                    ssh_job.auth = auth
                    found_port = port
                    found_auth = True
                    log.info("success: %s" % debug_str)
                    break

                # Implies we've found an SSH server listening:
                except paramiko.AuthenticationException as e:
                    # Because we stop checking ports once we find one where ssh
                    # is listening, we can report the error message here and it
                    # will end up in the final report correctly:
                    err = _("login failed")
                    log.error(err)
                    ssh_job.error = err
                    found_port = port
                    continue

                # No route to host:
                except socket.error as e:
                    log.warn("No route to host, skipping port: %s" % debug_str)
                    ssh_job.error = str(e)
                    break

                # TODO: Hitting a live port that isn't ssh will result in
                # paramiko.SSHException, do we need to handle this explicitly?

                # Something else happened:
                except Exception as detail:
                    log.warn("Connection error: %s - %s" % (debug_str,
                                                            str(detail)))
                    ssh_job.error = str(detail)
                    continue