示例#1
0
    def _is_exif_in_logs(self, result, basedir, logfiles):
        """Checks to see if there is evidence of the exiftool exploit in the logs.

    Args:
      result (TurbiniaTaskResult): The object to place task results into.
      basedir (str): the root of the evidence.
      logfiles (str): The file(s) to check

    Returns:
      Tuple(
        report_text(str): The report data
        report_priority(int): The priority of the report (0 - 100)
        summary(str): A summary of the report (used for task status)
      )
    """

        check = " ".join(glob.glob(os.path.join(basedir, logfiles)))
        if not len(check):
            return ('', Priority.LOW, '')

        cmd = ['zgrep', '"exiftool command failed"', check]
        ret, result = self.execute(cmd, result, success_codes=[0, 1])
        if ret == 0:
            summary = 'exif exploit detected in {0:s}'.format(logfiles)
            report = fmt.heading4(fmt.bold(summary))
            return (report, Priority.HIGH, summary)

        return ('', Priority.LOW, '')
示例#2
0
    def analyze_jenkins(version, credentials):
        """Analyses a Jenkins configuration.

    Args:
      version (str): Version of Jenkins.
      credentials (list): of tuples with username and password hash.

    Returns:
      Tuple(
        report_text(str): The report data
        report_priority(int): The priority of the report (0 - 100)
        summary(str): A summary of the report (used for task status)
      )
    """
        report = []
        summary = ''
        priority = Priority.LOW
        credentials_registry = {
            hash: username
            for username, hash in credentials
        }
        # TODO: Add timeout parameter when dynamic configuration is ready.
        # Ref: https://github.com/google/turbinia/issues/244
        weak_passwords = bruteforce_password_hashes(
            credentials_registry.keys())

        if not version:
            version = 'Unknown'
        report.append(fmt.bullet('Jenkins version: {0:s}'.format(version)))

        if weak_passwords:
            priority = Priority.CRITICAL
            summary = 'Jenkins analysis found potential issues'
            report.insert(0, fmt.heading4(fmt.bold(summary)))
            line = '{0:n} weak password(s) found:'.format(len(weak_passwords))
            report.append(fmt.bullet(fmt.bold(line)))
            for password_hash, plaintext in weak_passwords:
                line = 'User "{0:s}" with password "{1:s}"'.format(
                    credentials_registry.get(password_hash), plaintext)
                report.append(fmt.bullet(line, level=2))
        else:
            summary = 'Jenkins analysis found no issues'
            priority = Priority.LOW
            report.insert(0, fmt.heading4(summary))

        report = '\n'.join(report)
        return (report, priority, summary)
示例#3
0
    def analyse_config(self, jupyter_config):
        """Extract security related configs from Jupyter configuration files.

    Args:
      config (str): configuration file content.

    Returns:
      Tuple(
        report_text(str): The report data
        report_priority(int): The priority of the report (0 - 100)
        summary(str): A summary of the report (used for task status)
      )
    """
        findings = []
        num_misconfigs = 0
        for line in jupyter_config.split('\n'):

            if all(x in line for x in ['disable_check_xsrf', 'True']):
                findings.append(fmt.bullet('XSRF protection is disabled.'))
                num_misconfigs += 1
                continue
            if all(x in line for x in ['allow_root', 'True']):
                findings.append(
                    fmt.bullet('Juypter Notebook allowed to run as root.'))
                num_misconfigs += 1
                continue
            if 'NotebookApp.password' in line:
                if all(x in line for x in ['required', 'False']):
                    findings.append(
                        fmt.bullet(
                            'Password is not required to access this Jupyter Notebook.'
                        ))
                    num_misconfigs += 1
                    continue
                if 'required' not in line:
                    password_hash = line.split('=')
                    if len(password_hash) > 1:
                        if password_hash[1].strip() == "''":
                            findings.append(
                                fmt.bullet(
                                    'There is no password set for this Jupyter Notebook.'
                                ))
                            num_misconfigs += 1
            if all(x in line for x in ['allow_remote_access', 'True']):
                findings.append(
                    fmt.bullet(
                        'Remote access is enabled on this Jupyter Notebook.'))
                num_misconfigs += 1
                continue

        if findings:
            summary = 'Insecure Jupyter Notebook configuration found. Total misconfigs: {}'.format(
                num_misconfigs)
            findings.insert(0, fmt.heading4(fmt.bold(summary)))
            report = '\n'.join(findings)
            return (report, Priority.HIGH, summary)

        report = 'No issues found in Jupyter Notebook  configuration.'
        return (report, Priority.LOW, report)
示例#4
0
文件: loki.py 项目: jaegeral/turbinia
  def runLoki(self, result, evidence):
    log_file = os.path.join(self.output_dir, 'loki.log')
    stdout_file = os.path.join(self.output_dir, 'loki_stdout.log')
    stderr_file = os.path.join(self.output_dir, 'loki_stderr.log')

    cmd = [
        'python', '/opt/loki/loki.py', '-w', '0', '--csv', '--intense',
        '--noprocscan', '--dontwait', '--noindicator', '-l', log_file, '-p',
        evidence.local_path
    ]

    (ret, result) = self.execute(
        cmd, result, log_files=[log_file], stdout_file=stdout_file,
        stderr_file=stderr_file, cwd='/opt/loki/')

    if ret != 0:
      raise TurbiniaException('Return code: {0:d}'.format(ret))

    report = []
    summary = 'No Loki threats found'
    priority = Priority.LOW

    report_lines = []
    with open(stdout_file, 'r') as loki_report_csv:
      lokireader = csv.DictReader(
          loki_report_csv, fieldnames=['Time', 'Hostname', 'Level', 'Log'])
      for row in lokireader:
        if row['Level'] == 'ALERT':
          report_lines.append(row['Log'])

    if report_lines:
      priority = Priority.HIGH
      summary = 'Loki analysis found {0:d} alert(s)'.format(len(report_lines))
      report.insert(0, fmt.heading4(fmt.bold(summary)))
      line = '{0:n} alerts(s) found:'.format(len(report_lines))
      report.append(fmt.bullet(fmt.bold(line)))
      for line in report_lines:
        report.append(fmt.bullet(line, level=2))

    report = '\n'.join(report)
    return (report, priority, summary)
示例#5
0
 def testFormatting(self):
     """Test text formatting."""
     self.assertEqual('**testing**', fmt.bold(self.test_string))
     self.assertEqual('# testing', fmt.heading1(self.test_string))
     self.assertEqual('## testing', fmt.heading2(self.test_string))
     self.assertEqual('### testing', fmt.heading3(self.test_string))
     self.assertEqual('#### testing', fmt.heading4(self.test_string))
     self.assertEqual('##### testing', fmt.heading5(self.test_string))
     self.assertEqual('* testing', fmt.bullet(self.test_string))
     self.assertEqual('        * testing',
                      fmt.bullet(self.test_string, level=3))
     self.assertEqual('`testing`', fmt.code(self.test_string))
示例#6
0
    def _analyse_wordpress_creds(self, creds, hashnames, timeout=300):
        """Attempt to brute force extracted Wordpress credentials.

    Args:
        creds (list): List of strings containing raw extracted credentials
        hashnames (dict): Dict mapping hash back to username for convenience.
        timeout (int): How long to spend cracking.

    Returns:
      Tuple(
        report_text(str): The report data
        report_priority(int): The priority of the report (0 - 100)
        summary(str): A summary of the report (used for task status)
      )
    """
        report = []
        summary = 'No weak passwords found'
        priority = Priority.LOW

        # 1000 is "phpass"
        weak_passwords = bruteforce_password_hashes(
            creds,
            tmp_dir=self.tmp_dir,
            timeout=timeout,
            extra_args='--username -m 400')

        if weak_passwords:
            priority = Priority.CRITICAL
            summary = 'Wordpress analysis found {0:d} weak password(s)'.format(
                len(weak_passwords))
            report.insert(0, fmt.heading4(fmt.bold(summary)))
            line = '{0:n} weak password(s) found:'.format(len(weak_passwords))
            report.append(fmt.bullet(fmt.bold(line)))
            for password_hash, plaintext in weak_passwords:
                if password_hash in hashnames:
                    line = """User '{0:s}' with password '{1:s}'""".format(
                        hashnames[password_hash], plaintext)
                    report.append(fmt.bullet(line, level=2))
        report = '\n'.join(report)
        return (report, priority, summary)
示例#7
0
    def analyse_shadow_file(self, shadow, hashes, timeout=300):
        """Analyses a Linux shadow file.

    Args:
      shadow (list): shadow file content (list of str).
      hashes (dict): dict of hashes to usernames
      timeout (int): Time in seconds to run password bruteforcing.

    Returns:
      Tuple(
        report_text(str): The report data
        report_priority(int): The priority of the report (0 - 100)
        summary(str): A summary of the report (used for task status)
      )
    """
        report = []
        summary = 'No weak passwords found'
        priority = Priority.LOW

        # 1800 is "sha512crypt $6$, SHA512 (Unix)"
        weak_passwords = bruteforce_password_hashes(shadow,
                                                    tmp_dir=self.tmp_dir,
                                                    timeout=timeout,
                                                    extra_args='-m 1800')

        if weak_passwords:
            priority = Priority.CRITICAL
            summary = 'Shadow file analysis found {0:n} weak password(s)'.format(
                len(weak_passwords))
            report.insert(0, fmt.heading4(fmt.bold(summary)))
            line = '{0:n} weak password(s) found:'.format(len(weak_passwords))
            report.append(fmt.bullet(fmt.bold(line)))
            for password_hash, plaintext in weak_passwords:
                line = """User '{0:s}' with password '{1:s}'""".format(
                    hashes[password_hash], plaintext)
                report.append(fmt.bullet(line, level=2))
        report = '\n'.join(report)
        return (report, priority, summary)
示例#8
0
    def analyse_tomcat_file(self, tomcat_file):
        """Analyse a Tomcat file.

    - Search for clear text password entries in user configuration file
    - Search for .war deployment
    - Search for management control panel activity

    Args:
      tomcat_file (str): Tomcat file content.
    Returns:
      Tuple(
        report_text(str): The report data
        report_priority(int): The priority of the report (0 - 100)
        summary(str): A summary of the report (used for task status)
      )
    """
        findings = []

        tomcat_user_passwords_re = re.compile('(^.*password.*)', re.MULTILINE)
        tomcat_deploy_re = re.compile(
            '(^.*Deploying web application archive.*)', re.MULTILINE)
        tomcat_manager_activity_re = re.compile(
            '(^.*POST /manager/html/upload.*)', re.MULTILINE)

        count = 0
        for password_entry in re.findall(tomcat_user_passwords_re,
                                         tomcat_file):
            findings.append(
                fmt.bullet('Tomcat user: '******'Tomcat App Deployed: ' + deployment_entry.strip()))
            count += 1

        for mgmt_entry in re.findall(tomcat_manager_activity_re, tomcat_file):
            findings.append(
                fmt.bullet('Tomcat Management: ' + mgmt_entry.strip()))
            count += 1

        if findings:
            msg = 'Tomcat analysis found {0:d} results'.format(count)
            findings.insert(0, fmt.heading4(fmt.bold(msg)))
            report = '\n'.join(findings)
            return (report, Priority.HIGH, msg)

        report = 'No Tomcat findings to report'
        return (report, Priority.LOW, report)
示例#9
0
    def analyze_wp_access_logs(self, config):
        """Analyses access logs containing Wordpress traffic.

    Args:
      config (str): access log file content.

    Returns:
      Tuple(
        report_text(str): The report data
        report_priority(int): The priority of the report (0 - 100)
        summary(str): A summary of the report (used for task status)
      )
    """
        report = []
        findings_summary = set()

        for log_line in config.split('\n'):

            if self.install_step_regex.search(log_line):
                line = '{0:s}: Wordpress installation successful'.format(
                    self._get_timestamp(log_line))
                report.append(fmt.bullet(line))
                findings_summary.add('install')

            match = self.theme_editor_regex.search(log_line)
            if match:
                line = '{0:s}: Wordpress theme editor edited file ({1:s})'.format(
                    self._get_timestamp(log_line), match.group('edited_file'))
                report.append(fmt.bullet(line))
                findings_summary.add('theme_edit')

        if report:
            findings_summary = ', '.join(sorted(list(findings_summary)))
            summary = 'Wordpress access logs found ({0:s})'.format(
                findings_summary)

            report.insert(0, fmt.heading4(fmt.bold(summary)))
            report_text = '\n'.join(report)
            return (report_text, Priority.HIGH, summary)

        report_text = 'No Wordpress install or theme editing found in access logs'
        return (fmt.heading4(report_text), Priority.LOW, report_text)
示例#10
0
    def analyse_sshd_config(self, config):
        """Analyses an SSH configuration.

    Args:
      config (str): configuration file content.

    Returns:
      Tuple(
        report_text(str): The report data
        report_priority(int): The priority of the report (0 - 100)
        summary(str): A summary of the report (used for task status)
      )
    """
        findings = []
        permit_root_login_re = re.compile(
            r'^\s*PermitRootLogin\s*(yes|prohibit-password|without-password)',
            re.IGNORECASE | re.MULTILINE)
        password_authentication_re = re.compile(
            r'^\s*PasswordAuthentication[\s"]*No',
            re.IGNORECASE | re.MULTILINE)
        permit_empty_passwords_re = re.compile(
            r'^\s*PermitEmptyPasswords[\s"]*Yes', re.IGNORECASE | re.MULTILINE)

        if re.search(permit_root_login_re, config):
            findings.append(fmt.bullet('Root login enabled.'))

        if not re.search(password_authentication_re, config):
            findings.append(fmt.bullet('Password authentication enabled.'))

        if re.search(permit_empty_passwords_re, config):
            findings.append(fmt.bullet('Empty passwords permitted.'))

        if findings:
            summary = 'Insecure SSH configuration found.'
            findings.insert(0, fmt.heading4(fmt.bold(summary)))
            report = '\n'.join(findings)
            return (report, 20, summary)

        report = 'No issues found in SSH configuration'
        return (report, 60, report)
示例#11
0
    def _AnalyzeHadoopAppRoot(self, collected_artifacts, output_dir):
        """Runs a naive AppRoot files parsing method.

    This extracts strings from the saved task file, and searches for usual
    post-compromise suspicious patterns.

    TODO: properly parse the Proto. Some documentation can be found over there:
    https://svn.apache.org/repos/asf/hadoop/common/branches/branch-0.23.7/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_protos.proto

    Args:
      collected_artifacts(list(str)): a list of paths to extracted files
      output_dir(str): The base directory the artfacts are in.

    Returns:
      Tuple(
        list(str): The report data as a list of lines
        report_priority(int): The priority of the report (0 - 100)
        summary(str): A summary of the report (used for task status)
      )
    """
        report = []
        evil_commands = []
        strings_count = 0
        priority = Priority.MEDIUM
        summary = ''
        for filepath in collected_artifacts:
            relpath = os.path.relpath(filepath, output_dir)
            command = 'strings -a "{0:s}"'.format(filepath)
            log.debug('Running command [{0:s}]'.format(command))
            proc = subprocess.Popen(command,
                                    shell=True,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.STDOUT)
            strings_output, _ = proc.communicate()
            strings_output = codecs.decode(strings_output, 'utf-8')
            for line in strings_output.splitlines():
                strings_count += 1
                if (line.find('curl') >= 0) or (line.find('wget') >= 0):
                    evil_commands.append((relpath, line))

        if evil_commands:
            msg = 'Found suspicious commands!'
            report.append(fmt.heading4(fmt.bold(msg)))
            summary = msg
            priority = Priority.CRITICAL
        else:
            msg = 'Did not find any suspicious commands.'
            report.append(fmt.heading4(msg))
            summary = msg

        for filepath, command in evil_commands:
            report.append(fmt.bullet(fmt.bold('Command:')))
            report.append(fmt.code(command))
            report.append('Found in file:')
            report.append(fmt.code(filepath))

        msg = 'Extracted {0:d} strings from {1:d} file(s)'.format(
            strings_count, len(collected_artifacts))
        report.append(fmt.bullet(msg))

        return (report, priority, summary)