Example #1
0
    def __init__(self, hostname):
        super(CLIHost, self).__init__(hostname)

        inventory = Inventory()

        if inventory.has_option(self.hostname, 'sudo_password'):
            self.sudo_password = inventory.get(self.hostname, 'sudo_password')
        else:
            self.sudo_password = None

        if inventory.has_option(self.hostname, 'enable_password'):
            self.enable_password = inventory.get(self.hostname, 'enable_password')
        else:
            self.enable_password = None

        self._cmd_out_buf = ''
        self._cmd_err_buf = ''
Example #2
0
    def connect(self):
        inventory = Inventory()
        address = self.hostname
        if inventory.has_option(self.hostname, 'address'):
            address = inventory.get(self.hostname, 'address')

        ip = None
        nb_name = None
        try:
            socket.inet_aton(address)
            ip = address
        except OSError as e:
            nb_name = address

        nb = NetBIOS()
        if ip is not None and nb_name is None:
            # need to look up the hostname
            logger.debug('Looking up NetBIOS name from IP ' + ip)
            nb_names = nb.queryIPForName(ip)
            if nb_names is None or len(nb_names) < 1:
                raise RuntimeError('Cannot connect to host ' + self.hostname +
                                   '; looking up NetBIOS name failed')
            nb_name = nb_names[0]
        elif ip is None and nb_name is not None:
            # not a IPv4 address, need to look up the ip
            nb_name = address
            logger.debug('Looking up NetBIOS IP from name ' + nb_name)
            ips = nb.queryName(nb_name)
            if ips is None or len(ips) < 1:
                raise RuntimeError('Cannot connect to host ' + self.hostname +
                                   '; looking up NetBIOS IP failed')
            ip = ips[0]
        nb.close()

        if inventory.has_option(self.hostname,
                                'username') and inventory.has_option(
                                    self.hostname, 'password'):
            username = inventory.get(self.hostname, 'username')
            password = inventory.get(self.hostname, 'password')
            client_machine_name = ''.join(
                random.choice(string.ascii_letters + string.digits)
                for _ in range(15))
            logger.debug('Using client name of ' + client_machine_name)
            logger.info('Connecting to ' + nb_name + ' as ' + username +
                        ' for host ' + self.hostname)
            self.connection = SMBHost(username,
                                      password,
                                      client_machine_name,
                                      nb_name,
                                      use_ntlm_v2=True,
                                      sign_options=SMBHost.SIGN_WHEN_SUPPORTED
                                      )  #, is_direct_tcp=True)
            if not self.connection.connect(ip):
                raise RuntimeError('Cannot connect to host ' + self.hostname +
                                   '; connecting via SMB failed')
        else:
            raise RuntimeError('No method of authenticating with host ' +
                               self.hostname + ' found')

        print(str(self.connection.listPath('ADMIN$', '\\')))
Example #3
0
    def load(hostname):
        inventory = Inventory()

        # TODO better connection detection
        if not inventory.has_section(hostname) or not inventory.has_option(
                hostname, 'connection'):
            if hostname == 'localhost':
                connection_type = 'local'
            else:
                connection_type = 'ssh'
        else:
            connection_type = inventory.get(hostname, 'connection')

        # TODO impacket
        # TODO SMB?
        # TODO PSExec?
        if connection_type == 'ssh':
            from scap.host.cli.SSHHost import SSHHost
            return SSHHost(hostname)
        elif connection_type == 'winrm':
            if not inventory.has_option(hostname, 'winrm_auth_method'):
                raise RuntimeError(
                    'Host ' + hostname +
                    ' has not specified option: winrm_auth_method')
            auth_method = inventory.get(hostname, 'winrm_auth_method')
            logger.debug('Using winrm_auth_method ' + auth_method)
            if auth_method == 'ssl':
                from scap.host.cli.winrm.WinRMHostSSL import WinRMHostSSL
                return WinRMHostSSL(hostname)
            elif auth_method == 'ntlm':
                from scap.host.cli.winrm.WinRMHostNTLM import WinRMHostNTLM
                return WinRMHostNTLM(hostname)
            elif auth_method == 'kerberos':
                from scap.host.cli.winrm.WinRMHostKerberos import WinRMHostKerberos
                return WinRMHostKerberos(hostname)
            elif auth_method == 'plaintext':
                from scap.host.cli.winrm.WinRMHostPlaintext import WinRMHostPlaintext
                return WinRMHostPlaintext(hostname)
            else:
                raise RuntimeError(
                    'Host ' + hostname +
                    ' specified an invalid winrm_auth_method option')
        elif connection_type == 'local':
            if sys.platform.startswith('linux'):
                from scap.host.cli.local.LinuxLocalHost import LinuxLocalHost
                return LinuxLocalHost(hostname)
            elif sys.platform == 'win32':
                from scap.host.cli.local.WindowsLocalHost import WindowsLocalHost
                return WindowsLocalHost(hostname)
            else:
                raise NotImplementedError('Local connection on ' +
                                          sys.platform +
                                          ' is not yet supported')
        else:
            raise RuntimeError('Unsupported host connection type: ' +
                               connection_type)
Example #4
0
    def exec_command(self, cmd, sudo=False, enable=False):
        inventory = Inventory()
        if sudo:
            if not self.sudo_password:
                if not inventory.has_option(self.hostname, 'sudo_password'):
                    self.sudo_password = getpass.getpass('Sudo password for host ' + self.hostname + ': ')
                else:
                    self.sudo_password = inventory.get(self.hostname, 'sudo_password')
            cmd = 'sudo -S -- sh -c "' + cmd.replace('"', r'\"') + '"'

            # TODO need to do platform detection for sudo prompt
            #if sys.platform.startswith('linux'):
            self.sudo_prompt = '[sudo]'
            #elif sys.platform.startswith('darwin'):
            #    self.sudo_prompt = 'Password:'******'sudo prompt unknown for platform ' + sys.platform)
        elif enable:
            if not self.enable_password:
                if not inventory.has_option(self.hostname, 'enable_password'):
                    self.enable_password = getpass.getpass('Enable password for host ' + self.hostname + ': ')
                else:
                    self.enable_password = inventory.get(self.hostname, 'enable_password')

        else:
            cmd = 'sh -c "' + cmd.replace('"', r'\"') + '"'

        logger.debug("Sending command: " + cmd)
        chan = self.client.get_transport().open_session()
        chan.exec_command(cmd)
        chan.settimeout(self.SSH_TIMEOUT)

        self.out_buf = ''
        self.err_buf = ''
        while True:
            if chan.recv_ready():
                self._recv(chan)

            if chan.recv_stderr_ready():
                self._recv_stderr(chan, sudo)

            if chan.exit_status_ready():
                self._recv(chan)
                self._recv_stderr(chan, sudo)
                break

        chan.close()

        lines = str.splitlines(self.out_buf)
        for i in range(len(lines)):
            lines[i] = lines[i].strip()
        err_lines = str.splitlines(self.err_buf)
        for i in range(len(err_lines)):
            err_lines[i] = err_lines[i].strip()

        if len(err_lines) > 0:
            raise RuntimeError(str(err_lines))
        return lines
Example #5
0
    def exec_command(self, cmd):
        inventory = Inventory()
        cmd = 'sh -c "' + cmd.replace('"', r'\"') + '"'

        logger.debug("Sending command: " + cmd)
        chan = self.client.get_transport().open_session()
        chan.exec_command(cmd)
        chan.settimeout(self.SSH_TIMEOUT)

        self._cmd_out_buf = ''
        self._cmd_err_buf = ''
        while True:
            if chan.recv_ready():
                try:
                    self._recv_stdout(chan.recv(1024).decode())
                except socket.timeout:
                    pass

            if chan.recv_stderr_ready():
                try:
                    self._recv_stderr(chan.recv_stderr(1024).decode())
                except socket.timeout:
                    pass

            if chan.exit_status_ready():
                try:
                    self._recv_stdout(chan.recv(1024).decode())
                except socket.timeout:
                    pass
                try:
                    self._recv_stderr(chan.recv_stderr(1024).decode())
                except socket.timeout:
                    pass
                break

        status = chan.recv_exit_status()

        chan.close()

        out_lines = str.splitlines(self._cmd_out_buf)
        out_lines = [line.strip('\x0A\x0D') for line in out_lines]

        err_lines = [
            line.strip('\x0A\x0D')
            for line in str.splitlines(self._cmd_err_buf)
        ]
        err_lines = [line.strip('\x0A\x0D') for line in err_lines]

        return (status, out_lines, err_lines)
Example #6
0
    def load(hostname):
        inventory = Inventory()

        # TODO better connection detection
        if not inventory.has_section(hostname) or not inventory.has_option(hostname, 'connection'):
            if hostname == 'localhost':
                connection_type = 'local'
            else:
                connection_type = 'ssh'
        else:
            connection_type = inventory.get(hostname, 'connection')

        # TODO impacket
        # TODO SMB?
        # TODO PSExec?
        if connection_type == 'ssh':
            from scap.host.cli.SSHHost import SSHHost
            return SSHHost(hostname)
        elif connection_type == 'winrm':
            if not inventory.has_option(hostname, 'winrm_auth_method'):
                raise RuntimeError('Host ' + hostname + ' has not specified option: winrm_auth_method')
            auth_method = inventory.get(hostname, 'winrm_auth_method')
            logger.debug('Using winrm_auth_method ' + auth_method)
            if auth_method == 'ssl':
                from scap.host.cli.winrm.WinRMHostSSL import WinRMHostSSL
                return WinRMHostSSL(hostname)
            elif auth_method == 'ntlm':
                from scap.host.cli.winrm.WinRMHostNTLM import WinRMHostNTLM
                return WinRMHostNTLM(hostname)
            elif auth_method == 'kerberos':
                from scap.host.cli.winrm.WinRMHostKerberos import WinRMHostKerberos
                return WinRMHostKerberos(hostname)
            elif auth_method == 'plaintext':
                from scap.host.cli.winrm.WinRMHostPlaintext import WinRMHostPlaintext
                return WinRMHostPlaintext(hostname)
            else:
                raise RuntimeError('Host ' + hostname + ' specified an invalid winrm_auth_method option')
        elif connection_type == 'local':
            if sys.platform.startswith('linux'):
                from scap.host.cli.local.LinuxLocalHost import LinuxLocalHost
                return LinuxLocalHost(hostname)
            elif sys.platform == 'win32':
                from scap.host.cli.local.WindowsLocalHost import WindowsLocalHost
                return WindowsLocalHost(hostname)
            else:
                raise NotImplementedError('Local connection on ' + sys.platform + ' is not yet supported')
        else:
            raise RuntimeError('Unsupported host connection type: ' + connection_type)
    def exec_command(self, cmd, elevate=False, encoding='cp437'):
        inventory = Inventory()

        logger.debug("Sending command: " + cmd)
        if elevate:
            ctypes.windll.shell32.ShellExecuteW(None, "runas", 'cmd', '/c "' + cmd.replace('"', r'\"') + '"', None, 1)
        else:
            p = subprocess.run(cmd,
                stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE,
                shell=True)

        #logger.debug('Got stdout: ' + str(p.stdout))
        #logger.debug('Got stderr: ' + str(p.stderr))

        lines = str.splitlines(p.stdout.replace(b'\r\r', b'\r').decode(encoding))
        err_lines = str.splitlines(p.stderr.replace(b'\r\r', b'\r').decode(encoding))

        #logger.debug('stdout lines: ' + str(lines))
        #logger.debug('stderr lines: ' + str(err_lines))

        if len(err_lines) > 0:
            raise RuntimeError(str(err_lines))
        return lines
Example #8
0
    def __init__(self, hostname):
        super(CLIHost, self).__init__(hostname)

        inventory = Inventory()

        if inventory.has_option(self.hostname, 'sudo_password'):
            self.sudo_password = inventory.get(self.hostname, 'sudo_password')
        else:
            self.sudo_password = None

        if inventory.has_option(self.hostname, 'enable_password'):
            self.enable_password = inventory.get(self.hostname,
                                                 'enable_password')
        else:
            self.enable_password = None

        self._cmd_out_buf = ''
        self._cmd_err_buf = ''
    def exec_command(self, cmd, encoding='cp437'):
        inventory = Inventory()

        logger.debug("Sending command: " + cmd)
        p = subprocess.run(cmd,
                           stdout=subprocess.PIPE,
                           stdin=subprocess.PIPE,
                           stderr=subprocess.PIPE,
                           shell=True)

        #logger.debug('Got stdout: ' + str(p.stdout))
        #logger.debug('Got stderr: ' + str(p.stderr))

        out_lines = str.splitlines(
            p.stdout.replace(b'\r\r', b'\r').decode(encoding))
        out_lines = [line.strip('\x0A\x0D') for line in out_lines]
        err_lines = str.splitlines(
            p.stderr.replace(b'\r\r', b'\r').decode(encoding))
        err_lines = [line.strip('\x0A\x0D') for line in err_lines]

        #logger.debug('stdout lines: ' + str(out_lines))
        #logger.debug('stderr lines: ' + str(err_lines))

        return (p.returncode, out_lines, err_lines)
Example #10
0
import pytest
import uuid

from scap.Collector import ArgumentException
from scap.Host import Host
from scap.model.cpe_matching_2_3.CPE import CPE
from scap.Inventory import Inventory

logger = logging.getLogger(__name__)

filename = str(
    pathlib.Path(os.path.expanduser('~')) / '.pyscap' / 'inventory.ini')
try:
    with open(filename, 'r') as fp:
        logger.debug('Loading inventory from ' + filename)
        Inventory().readfp(fp)
except IOError:
    logger.error('Could not read from inventory file ' + filename)

host = Host.load('localhost')


@pytest.mark.parametrize("oval_family, env_var", (
    ('linux', 'HOME'),
    ('windows', 'USERNAME'),
))
def test_exists(oval_family, env_var):
    if host.facts['oval_family'] != oval_family:
        pytest.skip('Does not apply to platform')

    c = host.load_collector('EnvironmentCollector', {})
    def connect(self):
        inventory = Inventory()

        if inventory.has_option(self.hostname, 'address'):
            address = inventory.get(self.hostname, 'address')
        else:
            address = self.hostname
        logger.debug('Using address ' + address)

        if inventory.has_option(self.hostname, 'scheme'):
            scheme = inventory.get(self.hostname, 'scheme')
        else:
            scheme = 'http'
        logger.debug('Using url scheme ' + scheme)

        if inventory.has_option(self.hostname, 'port'):
            port = inventory.get(self.hostname, 'port')
        else:
            if scheme == 'http':
                port = '5985'
            elif scheme == 'https':
                port = '5986'
            else:
                raise('Invalid WinRM scheme: ' + scheme)
        logger.debug('Using port ' + port)

        if not inventory.has_option(self.hostname, 'username'):
            raise RuntimeError('Host ' + self.hostname + ' has not specified option: username')
        username = inventory.get(self.hostname, 'username')

        if inventory.has_option(self.hostname, 'kerberos_realm'):
            username = username + '@' + inventory.get(self.hostname, 'kerberos_realm')
        logger.debug('Using username ' + username)

        if inventory.has_option(self.hostname, 'kerberos_delegation'):
            kerberos_delegation = inventory.get(self.hostname, 'kerberos_delegation')
        else:
            kerberos_delegation = False

        if inventory.has_option(self.hostname, 'kerberos_hostname_override'):
            kerberos_hostname_override = inventory.get(self.hostname, 'kerberos_hostname_override')
        else:
            kerberos_hostname_override = None
        self.protocol = Protocol(
            endpoint=scheme + '://' + address + ':' + port + '/wsman',
            transport='kerberos',
            username=username,
            kerberos_delegation=kerberos_delegation,
            kerberos_hostname_override=kerberos_hostname_override)

        try:
            self.shell_id = self.protocol.open_shell()
        except Exception as e:
            logger.warning(str(e))
Example #12
0
    def connect(self):
        self.client = paramiko.client.SSHClient()
        self.client.load_system_host_keys()
        try:
            # TODO windows/linux home instead of ~
            logger.debug('Read ssh host keys from ~/.pyscap/ssh_host_keys')
            self.client.load_host_keys(os.path.expanduser('~/.pyscap/ssh_host_keys'))
        except:
            logger.warning("Couldn't read ssh host keys")
        self.client.set_missing_host_key_policy(self.AskHostKeyPolicy())

        inventory = Inventory()

        if inventory.has_option(self.hostname, 'ssh_port'):
            port = inventory.get(self.hostname, 'ssh_port')
        else:
            port = 22

        self.sudo_password = None

        if inventory.has_option(self.hostname, 'ssh_username') and inventory.has_option(self.hostname, 'ssh_password'):
            self.client.connect(self.hostname, port=port,
                username=inventory.get(self.hostname, 'ssh_username'),
                password=inventory.get(self.hostname, 'ssh_password'))
            if inventory.has_option(self.hostname, 'sudo_password'):
                self.sudo_password = inventory.get(self.hostname, 'sudo_password')
            else:
                self.sudo_password = inventory.get(self.hostname, 'ssh_password')
        elif inventory.has_option(self.hostname, 'ssh_private_key_filename'):
            if inventory.has_option(self.hostname, 'ssh_private_key_file_password'):
                self.client.connect(self.hostname, port=port,
                    key_filename=inventory.get(self.hostname, 'ssh_private_key_filename'),
                    password=inventory.get(self.hostname, 'ssh_private_key_file_password'))
            else:
                try:
                    self.client.connect(self.hostname, port=port,
                        key_filename=inventory.get(self.hostname, 'ssh_private_key_filename'))
                except PasswordRequiredException:
                    # retry with password
                    ssh_private_key_file_password = getpass.getpass('Password for private key file ' +
                        inventory.get(self.hostname, 'ssh_private_key_filename') + ': ')
                    self.client.connect(self.hostname, port=port,
                        key_filename=inventory.get(self.hostname, 'ssh_private_key_filename'),
                        password=ssh_private_key_file_password)
        else:
            ssh_username = input('Username for host ' + self.hostname + ': ')
            if ssh_username.strip() == '':
                raise RuntimeError('No method of authenticating with host ' + self.hostname + ' found')
            ssh_password = getpass.getpass('Password for host ' + self.hostname + ': ')
            if inventory.has_option(self.hostname, 'sudo_password'):
                self.sudo_password = inventory.get(self.hostname, 'sudo_password')
            else:
                self.sudo_password = ssh_password
            self.client.connect(self.hostname, port=port, username=ssh_username, password=ssh_password)
Example #13
0
def main():
    import argparse
    import atexit
    from io import StringIO
    import locale
    import logging
    import os
    import pathlib
    import pprint
    import sys
    import time
    import xml.dom.minidom
    import xml.etree.ElementTree as ET

    from scap import register_namespaces
    from scap.ColorFormatter import ColorFormatter
    from scap.Model import Model
    from scap.Host import Host
    from scap.Inventory import Inventory
    from scap.Reporter import Reporter

    # set up logging
    rootLogger = logging.getLogger()
    ch = logging.StreamHandler()
    fh = logging.FileHandler(filename="pyscap.log", mode='w')
    fh_formatter = logging.Formatter(
        "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    fh.setFormatter(fh_formatter)
    ch_formatter = ColorFormatter(
        "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    ch.setFormatter(ch_formatter)
    rootLogger.addHandler(ch)
    rootLogger.addHandler(fh)

    rootLogger.setLevel(logging.DEBUG)
    ch.setLevel(logging.WARNING)

    # report start time & end time
    logger = logging.getLogger(__name__)
    logger.debug('Start: ' + time.asctime(time.localtime()))

    register_namespaces()

    output = None

    def end_func():
        if output is not None:
            output.close()
        logger.debug('End: ' + time.asctime(time.localtime()))

    atexit.register(end_func)

    # set up argument parsing
    arg_parser = argparse.ArgumentParser()
    arg_parser.add_argument('--version',
                            '-V',
                            action='version',
                            version='%(prog)s 1.0')
    arg_parser.add_argument('--verbose', '-v', action='count')
    arg_parser.add_argument('--output', '-o', nargs='?', default='-')
    arg_parser.add_argument('--inventory', nargs='+')
    arg_parser.add_argument('--host', nargs='+')

    group = arg_parser.add_mutually_exclusive_group()
    group.add_argument('--list-hosts',
                       help='outputs a list of the hosts',
                       action='store_true')
    group.add_argument('--parse',
                       help='parse the supplied files',
                       nargs='+',
                       type=argparse.FileType('r'))
    group.add_argument('--detect',
                       help='detect facts about the host',
                       action='store_true')
    group.add_argument('--collect',
                       help='collect system characteristics about the host',
                       action='store_true')
    group.add_argument('--benchmark',
                       help='benchmark hosts and produce a report',
                       action='store_true')
    # group.add_argument('--test', help='perform a test on the selected hosts', nargs='+')

    # pre-parse arguments
    args = arg_parser.parse_known_args()
    if len(args) <= 0:
        arg_parser.error('No valid operation was given')

    # change verbosity
    if args[0].verbose:
        if (args[0].verbose == 1):
            ch.setLevel(logging.INFO)
            logger.debug('Set console logging level to INFO')
        elif (args[0].verbose == 2):
            ch.setLevel(logging.DEBUG)
            logger.debug('Set console logging level to DEBUG')
        elif (args[0].verbose >= 3):
            ch.setLevel(logging.NOTSET)
            logger.debug('Set console logging level to NOTSET')

    # set up the modes
    if args[0].list_hosts:
        logger.info("List hosts operation")
    elif args[0].parse:
        logger.info('File parsing operation')
    elif args[0].detect:
        logger.info("Detect operation")
    elif args[0].collect:
        logger.info("Collect operation")
        arg_parser.add_argument('--content', required=True, nargs='+')
    elif args[0].benchmark:
        logger.info("Benchmark operation")
        arg_parser.add_argument('--content', required=True, nargs='+')
        arg_parser.add_argument('--data_stream', nargs=1)
        arg_parser.add_argument('--checklist', nargs=1)
        arg_parser.add_argument('--profile', nargs=1)
        arg_parser.add_argument('--pretty', action='store_true')
    else:
        arg_parser.error('No valid operation was given')

    # final argument parsing
    args = vars(arg_parser.parse_args())
    for arg in args:
        logger.debug('Argument: ' + arg + ' = ' + str(args[arg]))

    # expand the hosts
    inventory = Inventory()
    if args['inventory'] is not None:
        for filename in args['inventory']:
            try:
                with open(filename, 'r') as fp:
                    logger.debug('Loading inventory from ' + filename)
                    Inventory().readfp(fp)
            except IOError:
                logger.error('Could not read from inventory file ' + filename)
    else:
        filename = str(
            pathlib.Path(os.path.expanduser('~')) / '.pyscap' /
            'inventory.ini')
        try:
            with open(filename, 'r') as fp:
                logger.debug('Loading inventory from ' + filename)
                Inventory().readfp(fp)
        except IOError:
            logger.error('Could not read from inventory file ' + filename)

    if args['host'] is None or len(args['host']) == 0:
        arg_parser.error('No host specified (--host)')

    hosts = []
    for hostname in args['host']:
        host = Host.load(hostname)
        hosts.append(host)

    # open output if it's not stdout
    if args['output'] != '-':
        output = open(args['output'], mode='wb')
    else:
        output = sys.stdout.buffer

    detection_collectors = [
        'UniqueIdCollector',
        'CpeCollector',
        'FqdnCollector',
        'HostnameCollector',
        'NetworkConnectionCollector',
        'NetworkServiceCollector',
        'IdentityCollector',
    ]

    if args['list_hosts']:
        print('Hosts: ')
        for host in hosts:
            print(host.hostname)

    elif args['parse']:
        for uri in args['parse']:
            logger.debug('Loading content file: ' + uri)
            with open(uri, mode='r', encoding='utf_8') as f:
                content = ET.parse(f).getroot()
                model = Model.load(None, content)
                logger.debug('Loaded ' + uri + ' successfully')

    elif args['detect']:
        for host in hosts:
            host.connect()

            # run detection collectors
            for col_name in detection_collectors:
                col = host.load_collector(col_name, {})
                col.collect()

            host.disconnect()

            logger.info('Host detection dump:')
            pp = pprint.PrettyPrinter(width=132)
            pp.pprint(host.facts)

    elif args['collect']:
        if args['content'] is None or len(args['content']) == 0:
            arg_parser.error('No content specified (--content)')

        # this mode will collect oval system characteristics
        for host in hosts:
            host.connect()

            # run detection collectors
            for col_name in detection_collectors:
                col = host.load_collector(col_name, {})
                col.collect()

            raise NotImplementedError(
                'System characteristic collection is not implemented')

            host.disconnect()

    elif args['benchmark']:
        ### Loading.Import
        # Import the XCCDF document into the program and build an initial internal
        # representation of the Benchmark object, Groups, Rules, and other objects.
        # If the file cannot be read or parsed, then Loading fails. (At the
        # beginning of this step, any inclusion processing specified with XInclude
        # elements should be performed. The resulting XML information set should be
        # validated against the XCCDF schema given in Appendix A.) Go to the next
        # step: Loading.Noticing.

        if args['content'] is None or len(args['content']) == 0:
            arg_parser.error('No content specified (--content)')

        from scap.model.xccdf_1_1.BenchmarkType import BenchmarkType as xccdf_1_1_BenchmarkType
        from scap.model.xccdf_1_2.BenchmarkType import BenchmarkType as xccdf_1_2_BenchmarkType
        benchmark_model = None
        for uri in args['content']:
            logger.debug('Loading content file: ' + uri)
            with open(uri, mode='r', encoding='utf_8') as f:
                content = ET.parse(f).getroot()
                model = Model.load(None, content)

                if isinstance(model, xccdf_1_1_BenchmarkType) \
                or isinstance(model, xccdf_1_2_BenchmarkType):
                    benchmark_model = model

        for host in hosts:
            host.connect()

            # run detection collectors
            for col_name in detection_collectors:
                col = host.load_collector(col_name, {})
                col.collect()

            benchmark_model.noticing()

            benchmark_model.selected_profiles = []
            if args['profile'] is None or len(args['profile']) == 0:
                # check them all
                benchmark_model.selected_profiles.extend(
                    benchmark_model.profiles.keys())
            else:
                for profile in args['profile']:
                    if profile not in list(benchmark_model.profiles.keys()):
                        raise ValueError(
                            'Unable to select non-existent profile: ' +
                            profile + ' Available profiles: ' +
                            str(benchmark_model.profiles.keys()))
                    benchmark_model.selected_profiles.append(profile)

            benchmark_model.resolve()

            benchmark_model.process(host)

            host.disconnect()

        rep = Reporter.load(args, model)
        report = ET.ElementTree(element=rep.report(hosts))

        logger.debug('Preferred encoding: ' + locale.getpreferredencoding())
        sio = StringIO()
        report.write(sio, encoding='unicode', xml_declaration=True)
        sio.write("\n")
        if args['pretty']:
            pretty_xml = xml.dom.minidom.parseString(
                sio.getvalue()).toprettyxml(indent='  ')
            output.write(pretty_xml.encode(locale.getpreferredencoding()))
        else:
            output.write(sio.getvalue().encode(locale.getpreferredencoding()))

    else:
        arg_parser.error('No valid operation was given')
Example #14
0
 def connect(self):
     inventory = Inventory()
     address = self.hostname
     if inventory.has_option(self.hostname, 'address'):
         address = inventory.get(self.hostname, 'address')
Example #15
0
    def connect(self):
        inventory = Inventory()

        if inventory.has_option(self.hostname, 'address'):
            address = inventory.get(self.hostname, 'address')
        else:
            address = self.hostname
        logger.debug('Using address ' + address)

        if inventory.has_option(self.hostname, 'scheme'):
            scheme = inventory.get(self.hostname, 'scheme')
        else:
            scheme = 'https'
        logger.debug('Using url scheme ' + scheme)

        if inventory.has_option(self.hostname, 'port'):
            port = inventory.get(self.hostname, 'port')
        else:
            if scheme == 'http':
                port = '5985'
            elif scheme == 'https':
                port = '5986'
            else:
                raise ('Invalid WinRM scheme: ' + scheme)
        logger.debug('Using port ' + port)

        if not inventory.has_option(self.hostname,
                                    'cert_pem') and not inventory.has_option(
                                        self.hostname, 'cert_key_pem'):
            # try basic auth
            if not inventory.has_option(self.hostname, 'username'):
                raise RuntimeError('Host ' + self.hostname +
                                   ' has not specified option: username')
            username = inventory.get(self.hostname, 'username')
            if inventory.has_option(self.hostname, 'domain'):
                username = inventory.get(self.hostname,
                                         'domain') + '\\' + username
            logger.debug('Using username ' + username)

            if not inventory.has_option(self.hostname, 'password'):
                raise RuntimeError('Host ' + self.hostname +
                                   ' has not specified option: password')
            password = inventory.get(self.hostname, 'password')

            self.protocol = Protocol(endpoint='https://' + address + ':' +
                                     port + '/wsman',
                                     transport='ssl',
                                     username=username,
                                     password=password)
        else:
            if not inventory.has_option(self.hostname, 'cert_pem'):
                raise RuntimeError('Host ' + self.hostname +
                                   ' has not specified option: cert_pem')
            cert_pem = inventory.get(self.hostname, 'cert_pem')
            if not inventory.has_option(self.hostname, 'cert_key_pem'):
                raise RuntimeError('Host ' + self.hostname +
                                   ' has not specified option: cert_key_pem')
            cert_key_pem = inventory.get(self.hostname, 'cert_key_pem')
            if inventory.has_option(self.hostname, 'server_cert_validation'):
                server_cert_validation = inventory.get(
                    self.hostname, 'server_cert_validation')
            else:
                server_cert_validation = 'validate'
            cert_key_pem = inventory.get(self.hostname, 'cert_key_pem')
            self.protocol = Protocol(
                endpoint='https://' + address + ':' + port + '/wsman',
                transport='ssl',
                cert_pem=cert_pem,
                cert_key_pem=cert_key_pem,
                server_cert_validation=server_cert_validation)

        try:
            self.shell_id = self.protocol.open_shell()
        except Exception as e:
            logger.warning(str(e))
Example #16
0
    def connect(self):
        self.client = paramiko.client.SSHClient()
        self.client.load_system_host_keys()
        try:
            # TODO windows/linux home instead of ~
            logger.debug('Read ssh host keys from ~/.pyscap/ssh_host_keys')
            self.client.load_host_keys(
                os.path.expanduser('~/.pyscap/ssh_host_keys'))
        except:
            logger.warning("Couldn't read ssh host keys")
        self.client.set_missing_host_key_policy(self.AskHostKeyPolicy())

        inventory = Inventory()

        if inventory.has_option(self.hostname, 'ssh_port'):
            port = inventory.get(self.hostname, 'ssh_port')
        else:
            port = 22

        self.sudo_password = None

        if inventory.has_option(self.hostname,
                                'ssh_username') and inventory.has_option(
                                    self.hostname, 'ssh_password'):
            self.client.connect(self.hostname,
                                port=port,
                                username=inventory.get(self.hostname,
                                                       'ssh_username'),
                                password=inventory.get(self.hostname,
                                                       'ssh_password'))
            if inventory.has_option(self.hostname, 'sudo_password'):
                self.sudo_password = inventory.get(self.hostname,
                                                   'sudo_password')
            else:
                self.sudo_password = inventory.get(self.hostname,
                                                   'ssh_password')
        elif inventory.has_option(self.hostname, 'ssh_private_key_filename'):
            if inventory.has_option(self.hostname,
                                    'ssh_private_key_file_password'):
                self.client.connect(
                    self.hostname,
                    port=port,
                    key_filename=inventory.get(self.hostname,
                                               'ssh_private_key_filename'),
                    password=inventory.get(self.hostname,
                                           'ssh_private_key_file_password'))
            else:
                try:
                    self.client.connect(self.hostname,
                                        port=port,
                                        key_filename=inventory.get(
                                            self.hostname,
                                            'ssh_private_key_filename'))
                except PasswordRequiredException:
                    # retry with password
                    ssh_private_key_file_password = getpass.getpass(
                        'Password for private key file ' + inventory.get(
                            self.hostname, 'ssh_private_key_filename') + ': ')
                    self.client.connect(self.hostname,
                                        port=port,
                                        key_filename=inventory.get(
                                            self.hostname,
                                            'ssh_private_key_filename'),
                                        password=ssh_private_key_file_password)
        else:
            ssh_username = input('Username for host ' + self.hostname + ': ')
            if ssh_username.strip() == '':
                raise RuntimeError('No method of authenticating with host ' +
                                   self.hostname + ' found')
            ssh_password = getpass.getpass('Password for host ' +
                                           self.hostname + ': ')
            if inventory.has_option(self.hostname, 'sudo_password'):
                self.sudo_password = inventory.get(self.hostname,
                                                   'sudo_password')
            else:
                self.sudo_password = ssh_password
            self.client.connect(self.hostname,
                                port=port,
                                username=ssh_username,
                                password=ssh_password)

        try:
            from scap.collector.UNameCollector import UNameCollector
            UNameCollector(self, {}).collect()
        except:
            # uname didn't work
            raise NotImplementedError('Unable to run uname on host: ' +
                                      self.host.hostname)

        if self.facts['uname'].startswith('Linux'):
            self.facts['oval_family'] = 'linux'
        # elif uname.startswith('Darwin'):
        #     pass
        elif self.facts['uname'].startswith('Windows NT'):
            self.facts['oval_family'] = 'windows'
        else:
            raise NotImplementedError(
                'Host detection has not been implemented for uname: ' +
                self.facts['uname'] + ' on ' + self.hostname)
Example #17
0
    def connect(self):
        self.client = paramiko.client.SSHClient()
        self.client.load_system_host_keys()
        try:
            # TODO windows/linux home instead of ~
            logger.debug('Read ssh host keys from ~/.pyscap/ssh_host_keys')
            self.client.load_host_keys(os.path.expanduser('~/.pyscap/ssh_host_keys'))
        except:
            logger.warning("Couldn't read ssh host keys")
        self.client.set_missing_host_key_policy(self.AskHostKeyPolicy())

        inventory = Inventory()

        if inventory.has_option(self.hostname, 'ssh_port'):
            port = inventory.get(self.hostname, 'ssh_port')
        else:
            port = 22

        if inventory.has_option(self.hostname, 'ssh_username') and inventory.has_option(self.hostname, 'ssh_password'):
            self.client.connect(self.hostname, port=port,
                username=inventory.get(self.hostname, 'ssh_username'),
                password=inventory.get(self.hostname, 'ssh_password'))
        elif inventory.has_option(self.hostname, 'ssh_private_key_filename'):
            if inventory.has_option(self.hostname, 'ssh_private_key_file_password'):
                self.client.connect(self.hostname, port=port,
                    key_filename=inventory.get(self.hostname, 'ssh_private_key_filename'),
                    password=inventory.get(self.hostname, 'ssh_private_key_file_password'))
            else:
                try:
                    self.client.connect(self.hostname, port=port,
                        key_filename=inventory.get(self.hostname, 'ssh_private_key_filename'))
                except PasswordRequiredException:
                    # retry with password
                    ssh_private_key_file_password = getpass.getpass('Password for private key file ' +
                        inventory.get(self.hostname, 'ssh_private_key_filename') + ': ')
                    self.client.connect(self.hostname, port=port,
                        key_filename=inventory.get(self.hostname, 'ssh_private_key_filename'),
                        password=ssh_private_key_file_password)
        else:
            ssh_username = input('Username for host ' + self.hostname + ': ')
            if ssh_username.strip() == '':
                raise RuntimeError('No method of authenticating with host ' + self.hostname + ' found')
            ssh_password = getpass.getpass('Password for host ' + self.hostname + ': ')
            self.client.connect(self.hostname, port=port, username=ssh_username, password=ssh_password)

        from scap.collector.UNameCollector import UNameCollector
        UNameCollector(self, {}).collect()

        if self.facts['uname']['kernel_name'] == 'Linux':
            self.facts['oval_family'] = 'linux'
        # elif uname.startswith('Darwin'):
        #     TODO
        elif self.facts['uname']['kernel_name'] == 'Windows NT':
            self.facts['oval_family'] = 'windows'
        else:
            raise NotImplementedError('Host detection has not been implemented for uname: ' + self.facts['uname'] + ' on ' + self.hostname)
Example #18
0
#     # test argument is already defined
#     arg_parser.add_argument('--object', required=True, nargs='+')
#     arg_parser.add_argument('--state', required=True, nargs='+')
else:
    arg_parser.error('No valid operation was given')

# final argument parsing
args = vars(arg_parser.parse_args())

# configure ElementTree
for k, v in list(NAMESPACES.items()):
    ET.register_namespace(v, k)

# expand the hosts
if args['collect'] or args['benchmark'] or args['list_hosts']:
    inventory = Inventory()
    for filename in args['inventory']:
        try:
            with open(filename, 'r') as fp:
                logger.debug('Loading inventory from ' + filename)
                Inventory().readfp(fp)
        except IOError:
            logger.error('Could not read from inventory file ' + filename)

    if len(args['host']) == 0:
        arg_parser.error('No host specified (--host)')

    hosts = []
    for hostname in args['host']:
        host = Host.load(hostname)
        hosts.append(host)
Example #19
0
    def exec_command(self, cmd, sudo=False):
        inventory = Inventory()

        if sudo:
            if hasattr(self, 'sudo_password'):
                pass
            elif inventory.has_option(self.hostname, 'sudo_password'):
                self.sudo_password = inventory.get(self.hostname,
                                                   'sudo_password')
            else:
                self.sudo_password = getpass.getpass(
                    'Sudo password for host ' + self.hostname + ': ')

            cmd = 'sudo -S -- sh -c "' + cmd.replace('"', r'\"') + '"'

            if sys.platform.startswith('linux'):
                sudo_prompt = '[sudo]'
            elif sys.platform.startswith('darwin'):
                sudo_prompt = 'Password:'******'sudo prompt unknown for platform ' +
                                          sys.platform)

        logger.debug("Sending command: " + cmd)
        p = Popen(cmd,
                  stdout=PIPE,
                  stdin=PIPE,
                  stderr=PIPE,
                  shell=True,
                  universal_newlines=True)

        # note; can't use p.communicate; have to figure out if we get a prompt
        # because there isn't if within sudo timeout
        out_buf = ''
        err_buf = ''
        sel = selectors.DefaultSelector()
        sel.register(p.stdout, selectors.EVENT_READ)
        sel.register(p.stderr, selectors.EVENT_READ)
        while True:
            ready_list = sel.select(10)
            if len(ready_list) == 0:
                # timeout
                p.stdin.close()
                break
            for (key, events) in ready_list:
                if key.fileobj is p.stdout and events & selectors.EVENT_READ:
                    outs = p.stdout.buffer.read1(1024).decode()
                    if len(outs) > 0:
                        logger.debug('Got stdout: ' + outs)
                        out_buf += outs
                elif key.fileobj is p.stderr and events & selectors.EVENT_READ:
                    errs = p.stderr.buffer.read1(1024).decode()
                    if len(errs) > 0:
                        logger.debug('Got stderr: ' + errs)
                        err_buf += errs
                    if sudo and err_buf.startswith(sudo_prompt):
                        logger.debug("Sending sudo_password...")
                        p.stdin.write(self.sudo_password + "\n")
                        p.stdin.close()
                        err_buf = ''

            if p.stdout.closed and p.stderr.closed:
                p.stdin.close()
                p.poll()
                break

            if p.poll() is not None:
                p.stdin.close()
                break

        if not p.stdout.closed:
            outs = p.stdout.buffer.read1(1024).decode()
            if len(outs) > 0:
                logger.debug('Got extra-loop stdout: ' + outs)
                out_buf += outs

        if not p.stderr.closed:
            errs = p.stderr.buffer.read1(1024).decode()
            if len(errs) > 0:
                logger.debug('Got extra-loop stderr: ' + errs)
                err_buf += errs
            if sudo and err_buf.startswith(sudo_prompt):
                logger.debug("Sending sudo_password...")
                p.stdin.write(self.sudo_password + "\n")
                p.stdin.close()
                err_buf = ''

        sel.unregister(p.stdout)
        sel.unregister(p.stderr)
        sel.close()

        out_lines = str.splitlines(out_buf)
        out_lines = [line.strip('\x0A\x0D') for line in out_lines]
        err_lines = str.splitlines(err_buf)
        err_lines = [line.strip('\x0A\x0D') for line in err_lines]

        return (p.returncode, out_lines, err_lines)