Пример #1
0
def handler(q=False):
    if q is False:
        return False
    request = json.loads(q)
    if not request.get('sigma'):
        misperrors['error'] = 'Sigma rule missing'
        return misperrors
    config = SigmaConfiguration()
    f = io.TextIOWrapper(io.BytesIO(request.get('sigma').encode()),
                         encoding='utf-8')
    parser = SigmaCollectionParser(f, config)
    targets = []
    results = []
    for t in sigma_targets:
        backend = getBackend(t)(config, {'rulecomment': False})
        try:
            parser.generate(backend)
            result = backend.finalize()
            if result:
                results.append(result)
                targets.append(t)
        except Exception:
            continue
    d_result = {t: r.strip() for t, r in zip(targets, results)}
    return {
        'results': [{
            'types': mispattributes['output'],
            'values': d_result
        }]
    }
Пример #2
0
def handler(q=False):
    if q is False:
        return False
    request = json.loads(q)
    if not request.get('sigma'):
        misperrors['error'] = 'Sigma rule missing'
        return misperrors
    config = SigmaConfiguration()
    backend_options = BackendOptions(None)
    f = io.TextIOWrapper(io.BytesIO(request.get('sigma').encode()),
                         encoding='utf-8')
    parser = SigmaCollectionParser(f, config, None)
    targets = []
    old_stdout = sys.stdout
    result = io.StringIO()
    sys.stdout = result
    for t in sigma_targets:
        backend = getBackend(t)(config, backend_options, None)
        try:
            parser.generate(backend)
            backend.finalize()
            print("#NEXT")
            targets.append(t)
        except Exception:
            continue
    sys.stdout = old_stdout
    results = result.getvalue()[:-5].split('#NEXT')
    d_result = {t: r.strip() for t, r in zip(targets, results)}
    return {
        'results': [{
            'types': mispattributes['output'],
            'values': d_result
        }]
    }
Пример #3
0
    def __call__(self, parser, ns, vals, opt):
        backend = backends.getBackend(vals)
        if len(backend.options) > 0:
            helptext = "Backend options for " + backend.identifier + "\n"
            for option, default, help, _ in backend.options:
                helptext += "    {:10}: {} (default: {})".format(option, help, default) + "\n"

        print(helptext)
        exit(0)
Пример #4
0
    def sigma_to_query(self, sigma_file: str):
        """convert a Sigma rule file to query using the backend/config properties"""

        # initialize config manager to retrieve config
        scm = SigmaConfigurationManager()
        sigmaconfigs = SigmaConfigurationChain()
        sigmaconfig = scm.get(self.config)
        sigmaconfigs.append(sigmaconfig)

        # dynamically grab backend and pair to config
        backend_class = backends.getBackend(self.backend)
        backend = backend_class(sigmaconfigs)

        with open(sigma_file) as f:
            parser = SigmaCollectionParser(f, sigmaconfigs)
            parser.generate(backend)

        return json.loads(backend.finalize())
Пример #5
0
def main():
    argparser = set_argparser()
    cmdargs = argparser.parse_args()

    scm = SigmaConfigurationManager()

    logger = logging.getLogger(__name__)
    if cmdargs.debug:   # pragma: no cover
        logger.setLevel(logging.DEBUG)

    if cmdargs.lists:
        print("Backends (Targets):")
        list_backends(cmdargs.debug)

        print()
        print("Configurations (Sources):")
        list_configurations(backend=cmdargs.target, scm=scm)

        print()
        print("Modifiers:")
        list_modifiers(modifiers=modifiers)
        sys.exit(0)
    elif len(cmdargs.inputs) == 0:
        print("Nothing to do!")
        argparser.print_usage()
        sys.exit(0)

    if cmdargs.target is None:
        print("No target selected, select one with -t/--target")
        argparser.print_usage()
        sys.exit(ERR_NO_TARGET)

    rulefilter = None
    if cmdargs.filter:
        try:
            rulefilter = SigmaRuleFilter(cmdargs.filter)
        except SigmaRuleFilterParseException as e:
            print("Parse error in Sigma rule filter expression: %s" % str(e), file=sys.stderr)
            sys.exit(ERR_RULE_FILTER_PARSING)

    sigmaconfigs = SigmaConfigurationChain()
    backend_class = backends.getBackend(cmdargs.target)
    if cmdargs.config is None:
        if backend_class.config_required and not cmdargs.shoot_yourself_in_the_foot:
            print("The backend you want to use usually requires a configuration to generate valid results. Please provide one with --config/-c.", file=sys.stderr)
            print("Available choices for this backend (get complete list with --lists/-l):")
            list_configurations(backend=cmdargs.target, scm=scm)
            sys.exit(ERR_CONFIG_REQUIRED)
    if backend_class.default_config is not None:
        cmdargs.config = backend_class.default_config

    if cmdargs.config:
        order = 0
        for conf_name in cmdargs.config:
            try:
                sigmaconfig = scm.get(conf_name)
                if sigmaconfig.order is not None:
                    if sigmaconfig.order <= order and not cmdargs.shoot_yourself_in_the_foot:
                        print("The configurations were provided in the wrong order (order key check in config file)", file=sys.stderr)
                        sys.exit(ERR_CONFIG_ORDER)
                    order = sigmaconfig.order

                try:
                    if cmdargs.target not in sigmaconfig.config["backends"]:
                        print("The configuration '{}' is not valid for backend '{}'. Valid choices are: {}".format(conf_name, cmdargs.target, ", ".join(sigmaconfig.config["backends"])), file=sys.stderr)
                        sys.exit(ERR_CONFIG_ORDER)
                except KeyError:
                    pass

                sigmaconfigs.append(sigmaconfig)
            except OSError as e:
                print("Failed to open Sigma configuration file %s: %s" % (conf_name, str(e)), file=sys.stderr)
                exit(ERR_OPEN_CONFIG_FILE)
            except (yaml.parser.ParserError, yaml.scanner.ScannerError) as e:
                print("Sigma configuration file %s is no valid YAML: %s" % (conf_name, str(e)), file=sys.stderr)
                exit(ERR_CONFIG_INVALID_YAML)
            except SigmaConfigParseError as e:
                print("Sigma configuration parse error in %s: %s" % (conf_name, str(e)), file=sys.stderr)
                exit(ERR_CONFIG_PARSING)

    backend_options = BackendOptions(cmdargs.backend_option, cmdargs.backend_config)
    backend = backend_class(sigmaconfigs, backend_options)

    filename = cmdargs.output
    if filename:
        try:
            out = open(filename, "w", encoding='utf-8')
        except (IOError, OSError) as e:
            print("Failed to open output file '%s': %s" % (filename, str(e)), file=sys.stderr)
            exit(ERR_OUTPUT)
    else:
        out = sys.stdout

    error = 0
    for sigmafile in get_inputs(cmdargs.inputs, cmdargs.recurse):
        logger.debug("* Processing Sigma input %s" % (sigmafile))
        try:
            if cmdargs.inputs == ['-']:
                f = sigmafile
            else:
                f = sigmafile.open(encoding='utf-8')
            parser = SigmaCollectionParser(f, sigmaconfigs, rulefilter)
            results = parser.generate(backend)
            for result in results:
                print(result, file=out)
        except OSError as e:
            print("Failed to open Sigma file %s: %s" % (sigmafile, str(e)), file=sys.stderr)
            error = ERR_OPEN_SIGMA_RULE
        except (yaml.parser.ParserError, yaml.scanner.ScannerError) as e:
            print("Sigma file %s is no valid YAML: %s" % (sigmafile, str(e)), file=sys.stderr)
            error = ERR_INVALID_YAML
            if not cmdargs.defer_abort:
                sys.exit(error)
        except (SigmaParseError, SigmaCollectionParseError) as e:
            print("Sigma parse error in %s: %s" % (sigmafile, str(e)), file=sys.stderr)
            error = ERR_SIGMA_PARSING
            if not cmdargs.defer_abort:
                sys.exit(error)
        except NotSupportedError as e:
            print("The Sigma rule requires a feature that is not supported by the target system: " + str(e), file=sys.stderr)
            if not cmdargs.ignore_backend_errors:
                error = ERR_NOT_SUPPORTED
                if not cmdargs.defer_abort:
                    sys.exit(error)
        except BackendError as e:
            print("Backend error in %s: %s" % (sigmafile, str(e)), file=sys.stderr)
            if not cmdargs.ignore_backend_errors:
                error = ERR_BACKEND
                if not cmdargs.defer_abort:
                    sys.exit(error)
        except (NotImplementedError, TypeError) as e:
            print("An unsupported feature is required for this Sigma rule (%s): " % (sigmafile) + str(e), file=sys.stderr)
            print("Feel free to contribute for fun and fame, this is open source :) -> https://github.com/Neo23x0/sigma", file=sys.stderr)
            if not cmdargs.ignore_backend_errors:
                error = ERR_NOT_IMPLEMENTED
                if not cmdargs.defer_abort:
                    sys.exit(error)
        except PartialMatchError as e:
            print("Partial field match error: %s" % str(e), file=sys.stderr)
            if not cmdargs.ignore_backend_errors:
                error = ERR_PARTIAL_FIELD_MATCH
                if not cmdargs.defer_abort:
                    sys.exit(error)
        except FullMatchError as e:
            print("Full field match error", file=sys.stderr)
            if not cmdargs.ignore_backend_errors:
                error = ERR_FULL_FIELD_MATCH
                if not cmdargs.defer_abort:
                    sys.exit(error)                
        finally:
            try:
                f.close()
            except:
                pass

    result = backend.finalize()
    if result:
        print(result, file=out)
    out.close()

    sys.exit(error)
Пример #6
0
def main():
    argparser = set_argparser()
    cmdargs = argparser.parse_args()
    scm = SigmaConfigurationManager()

    logger = logging.getLogger(__name__)
    if cmdargs.debug:  # pragma: no cover
        logging.basicConfig(filename='sigmac.log',
                            filemode='w',
                            level=logging.DEBUG)
        logger.setLevel(logging.DEBUG)

    if cmdargs.lists:
        print("Backends (Targets):")
        list_backends(cmdargs.debug)

        print()
        print("Configurations (Sources):")
        list_configurations(backend=cmdargs.target, scm=scm)

        print()
        print("Modifiers:")
        list_modifiers(modifiers=modifiers)
        sys.exit(0)
    elif len(cmdargs.inputs) == 0:
        print("Nothing to do!")
        argparser.print_usage()
        sys.exit(0)

    if cmdargs.target is None:
        print("No target selected, select one with -t/--target")
        argparser.print_usage()
        sys.exit(ERR_NO_TARGET)

    logger.debug("* Target selected %s" % (cmdargs.target))

    rulefilter = None
    if cmdargs.filter:
        try:
            rulefilter = SigmaRuleFilter(cmdargs.filter)
        except SigmaRuleFilterParseException as e:
            print("Parse error in Sigma rule filter expression: %s" % str(e),
                  file=sys.stderr)
            sys.exit(ERR_RULE_FILTER_PARSING)

    sigmaconfigs = SigmaConfigurationChain()
    backend_class = backends.getBackend(cmdargs.target)
    if cmdargs.config is None:
        if backend_class.config_required and not cmdargs.shoot_yourself_in_the_foot:
            print(
                "The backend you want to use usually requires a configuration to generate valid results. Please provide one with --config/-c.",
                file=sys.stderr)
            print(
                "Available choices for this backend (get complete list with --lists/-l):"
            )
            list_configurations(backend=cmdargs.target, scm=scm)
            sys.exit(ERR_CONFIG_REQUIRED)
        if backend_class.default_config is not None:
            cmdargs.config = backend_class.default_config

    if cmdargs.config:
        order = 0
        for conf_name in cmdargs.config:
            try:
                sigmaconfig = scm.get(conf_name)
                if sigmaconfig.order is not None:
                    if sigmaconfig.order <= order and not cmdargs.shoot_yourself_in_the_foot:
                        print(
                            "The configurations were provided in the wrong order (order key check in config file)",
                            file=sys.stderr)
                        sys.exit(ERR_CONFIG_ORDER)
                    order = sigmaconfig.order

                try:
                    if cmdargs.target not in sigmaconfig.config["backends"]:
                        print(
                            "The configuration '{}' is not valid for backend '{}'. Valid choices are: {}"
                            .format(conf_name, cmdargs.target,
                                    ", ".join(sigmaconfig.config["backends"])),
                            file=sys.stderr)
                        sys.exit(ERR_CONFIG_ORDER)
                except KeyError:
                    pass

                sigmaconfigs.append(sigmaconfig)
            except OSError as e:
                print("Failed to open Sigma configuration file %s: %s" %
                      (conf_name, str(e)),
                      file=sys.stderr)
                exit(ERR_OPEN_CONFIG_FILE)
            except (yaml.parser.ParserError, yaml.scanner.ScannerError) as e:
                print("Sigma configuration file %s is no valid YAML: %s" %
                      (conf_name, str(e)),
                      file=sys.stderr)
                exit(ERR_CONFIG_INVALID_YAML)
            except SigmaConfigParseError as e:
                print("Sigma configuration parse error in %s: %s" %
                      (conf_name, str(e)),
                      file=sys.stderr)
                exit(ERR_CONFIG_PARSING)

    if cmdargs.output_fields:
        if cmdargs.output_format:
            output_fields_rejected = [
                field for field in cmdargs.output_fields.split(",")
                if field not in allowed_fields
            ]  # Not allowed fields
            if output_fields_rejected:
                print(
                    "These fields are not allowed (check help for allow field list) : %s"
                    % (", ".join(output_fields_rejected)),
                    file=sys.stderr)
                exit(ERR_OUTPUT_FORMAT)
            else:
                output_fields_filtered = [
                    field for field in cmdargs.output_fields.split(",")
                    if field in allowed_fields
                ]  # Keep only allowed fields
        else:
            print(
                "The '--output-fields' or '-of' arguments must be used with '--output-format' or '-oF' equal to 'json' or 'yaml'",
                file=sys.stderr)
            exit(ERR_OUTPUT_FORMAT)

    backend_options = BackendOptions(cmdargs.backend_option,
                                     cmdargs.backend_config)
    backend = backend_class(sigmaconfigs, backend_options)

    filename_ext = cmdargs.output_extention
    filename = cmdargs.output
    fileprefix = None
    if filename:
        if filename_ext:
            if filename_ext[0] == '.':
                pass
            else:
                filename_ext = '.' + filename_ext
        else:
            filename_ext = '.rule'

        if filename[-1:] in ['_', '/', '\\']:
            fileprefix = filename
        else:
            try:
                out = open(filename, "w", encoding='utf-8')
            except (IOError, OSError) as e:
                print("Failed to open output file '%s': %s" %
                      (filename, str(e)),
                      file=sys.stderr)
                exit(ERR_OUTPUT)
    else:
        out = sys.stdout

    error = 0
    output_array = []
    for sigmafile in get_inputs(cmdargs.inputs, cmdargs.recurse):
        logger.debug("* Processing Sigma input %s" % (sigmafile))
        success = True
        try:
            if cmdargs.inputs == ['-']:
                f = sigmafile
            else:
                f = sigmafile.open(encoding='utf-8')
            parser = SigmaCollectionParser(f, sigmaconfigs, rulefilter,
                                           sigmafile)
            results = parser.generate(backend)

            nb_result = len(list(copy.deepcopy(results)))
            inc_filenane = None if nb_result < 2 else 0

            newline_separator = '\0' if cmdargs.print0 else '\n'

            results = list(
                results
            )  # Since results is an iterator and used twice we convert it a list
            for result in results:
                if not fileprefix == None and not inc_filenane == None:  #yml action
                    try:
                        filename = fileprefix + str(sigmafile.name)
                        filename = filename.replace(
                            '.yml', '_' + str(inc_filenane) + filename_ext)
                        inc_filenane += 1
                        out = open(filename, "w", encoding='utf-8')
                    except (IOError, OSError) as e:
                        print("Failed to open output file '%s': %s" %
                              (filename, str(e)),
                              file=sys.stderr)
                        exit(ERR_OUTPUT)
                elif not fileprefix == None and inc_filenane == None:  # a simple yml
                    try:
                        filename = fileprefix + str(sigmafile.name)
                        filename = filename.replace('.yml', filename_ext)
                        out = open(filename, "w", encoding='utf-8')
                    except (IOError, OSError) as e:
                        print("Failed to open output file '%s': %s" %
                              (filename, str(e)),
                              file=sys.stderr)
                        exit(ERR_OUTPUT)
                if not cmdargs.output_fields:
                    print(result, file=out, end=newline_separator)

            if cmdargs.output_fields:  # Handle output fields
                output = {}
                f.seek(0)
                docs = yaml.load_all(f, Loader=yaml.FullLoader)
                for doc in docs:
                    for k, v in doc.items():
                        if k in output_fields_filtered:
                            output[k] = v
                output['rule'] = [result for result in results]
                if "filename" in output_fields_filtered:
                    output['filename'] = str(sigmafile.name)
                output_array.append(output)

            if nb_result == 0:  # backend get only 1 output
                if not fileprefix == None:  # want a prefix anyway
                    try:
                        filename = "%s%s_mono_output%s" % (
                            fileprefix, cmdargs.target, filename_ext)
                        out = open(filename, "w", encoding='utf-8')
                        fileprefix = None  # no need to open the same file many time
                    except (IOError, OSError) as e:
                        print("Failed to open output file '%s': %s" %
                              (filename, str(e)),
                              file=sys.stderr)
                        exit(ERR_OUTPUT)

        except OSError as e:
            print("Failed to open Sigma file %s: %s" % (sigmafile, str(e)),
                  file=sys.stderr)
            logger.debug("* Convertion Sigma input %s FAILURE" % (sigmafile))
            success = False
            error = ERR_OPEN_SIGMA_RULE
        except (yaml.parser.ParserError, yaml.scanner.ScannerError) as e:
            print("Error: Sigma file %s is no valid YAML: %s" %
                  (sigmafile, str(e)),
                  file=sys.stderr)
            logger.debug("* Convertion Sigma input %s FAILURE" % (sigmafile))
            success = False
            error = ERR_INVALID_YAML
            if not cmdargs.defer_abort:
                sys.exit(error)
        except (SigmaParseError, SigmaCollectionParseError) as e:
            print("Error: Sigma parse error in %s: %s" % (sigmafile, str(e)),
                  file=sys.stderr)
            logger.debug("* Convertion Sigma input %s FAILURE" % (sigmafile))
            success = False
            error = ERR_SIGMA_PARSING
            if not cmdargs.defer_abort:
                sys.exit(error)
        except NotSupportedError as e:
            print(
                "Error: The Sigma rule requires a feature that is not supported by the target system: "
                + str(e),
                file=sys.stderr)
            logger.debug("* Convertion Sigma input %s FAILURE" % (sigmafile))
            success = False
            if not cmdargs.ignore_backend_errors:
                error = ERR_NOT_SUPPORTED
                if not cmdargs.defer_abort:
                    sys.exit(error)
        except BackendError as e:
            print("Error: Backend error in %s: %s" % (sigmafile, str(e)),
                  file=sys.stderr)
            logger.debug("* Convertion Sigma input %s FAILURE" % (sigmafile))
            success = False
            if not cmdargs.ignore_backend_errors:
                error = ERR_BACKEND
                if not cmdargs.defer_abort:
                    sys.exit(error)
        except (NotImplementedError, TypeError) as e:
            print(
                "An unsupported feature is required for this Sigma rule (%s): "
                % (sigmafile) + str(e),
                file=sys.stderr)
            logger.debug("* Convertion Sigma input %s FAILURE" % (sigmafile))
            success = False
            if not cmdargs.ignore_backend_errors:
                error = ERR_NOT_IMPLEMENTED
                if not cmdargs.defer_abort:
                    sys.exit(error)
        except PartialMatchError as e:
            print("Error: Partial field match error: %s" % str(e),
                  file=sys.stderr)
            logger.debug("* Convertion Sigma input %s FAILURE" % (sigmafile))
            success = False
            if not cmdargs.ignore_backend_errors:
                error = ERR_PARTIAL_FIELD_MATCH
                if not cmdargs.defer_abort:
                    sys.exit(error)
        except FullMatchError as e:
            print("Error: Full field match error", file=sys.stderr)
            logger.debug("* Convertion Sigma input %s FAILURE" % (sigmafile))
            success = False
            if not cmdargs.ignore_backend_errors:
                error = ERR_FULL_FIELD_MATCH
                if not cmdargs.defer_abort:
                    sys.exit(error)
        finally:
            try:
                f.close()
            except:
                pass

        if success:
            logger.debug("* Convertion Sigma input %s SUCCESS" % (sigmafile))

    result = backend.finalize()
    if result:
        print(result, file=out)

    if cmdargs.output_fields:
        if cmdargs.output_format == 'json':
            print(json.dumps(output_array, indent=4, ensure_ascii=False),
                  file=out)
        elif cmdargs.output_format == 'yaml':
            print(ruamel.yaml.round_trip_dump(output_array), file=out)

    out.close()

    sys.exit(error)