2017-02-13 23:14:40 +01:00
#!/usr/bin/env python3
# A Sigma to SIEM converter
2017-12-07 21:55:43 +01:00
# Copyright 2016-2017 Thomas Patzke, Florian Roth
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2017-02-13 23:14:40 +01:00
import sys
import argparse
import yaml
2022-08-10 11:42:27 +02:00
import ruamel . yaml
2017-02-13 23:14:40 +01:00
import json
2017-03-06 09:36:10 +01:00
import pathlib
import itertools
2021-10-14 15:05:05 +00:00
import logging , traceback
2018-07-27 00:02:07 +02:00
from sigma . parser . collection import SigmaCollectionParser
from sigma . parser . exceptions import SigmaCollectionParseError , SigmaParseError
2018-08-27 00:17:27 +02:00
from sigma . configuration import SigmaConfiguration , SigmaConfigurationChain
2019-05-17 09:13:59 +02:00
from sigma . config . collection import SigmaConfigurationManager
2018-07-27 23:54:18 +02:00
from sigma . config . exceptions import SigmaConfigParseError , SigmaRuleFilterParseException
from sigma . filter import SigmaRuleFilter
2018-07-20 23:30:32 +02:00
import sigma . backends . discovery as backends
from sigma . backends . base import BackendOptions
from sigma . backends . exceptions import BackendError , NotSupportedError , PartialMatchError , FullMatchError
2019-05-26 23:58:56 +02:00
from sigma . parser . modifiers import modifiers
2017-12-13 00:12:56 +01:00
import codecs
2021-08-01 19:34:07 +02:00
import copy
2022-02-14 15:03:41 -08:00
import time
import datetime
2022-09-09 09:08:50 +02:00
from termcolor import colored
2017-12-13 00:12:56 +01:00
sys . stdout = codecs . getwriter ( ' utf-8 ' ) ( sys . stdout . detach ( ) )
2017-02-13 23:14:40 +01:00
2019-04-22 23:15:35 +02:00
# Error codes
2019-04-23 00:53:52 +02:00
ERR_OUTPUT = 1
ERR_INVALID_YAML = 3
ERR_SIGMA_PARSING = 4
ERR_OPEN_SIGMA_RULE = 5
ERR_OPEN_CONFIG_FILE = 5
2019-04-23 00:52:31 +02:00
ERR_CONFIG_INVALID_YAML = 6
2019-04-23 00:53:52 +02:00
ERR_CONFIG_PARSING = 6
ERR_BACKEND = 8
ERR_NOT_SUPPORTED = 9
ERR_NO_TARGET = 10
2019-04-22 23:15:35 +02:00
ERR_RULE_FILTER_PARSING = 11
2019-04-23 00:53:52 +02:00
ERR_CONFIG_REQUIRED = 20
ERR_CONFIG_ORDER = 21
2019-05-20 01:00:33 +02:00
ERR_CONFIG_BACKEND = 22
2021-08-12 15:26:46 +02:00
ERR_OUTPUT_FORMAT = 30
2019-04-23 00:53:52 +02:00
ERR_NOT_IMPLEMENTED = 42
2019-04-22 23:15:35 +02:00
ERR_PARTIAL_FIELD_MATCH = 80
2019-04-23 00:53:52 +02:00
ERR_FULL_FIELD_MATCH = 90
2019-04-22 23:15:35 +02:00
2021-08-12 15:26:46 +02:00
# Allowed fields in output
allowed_fields = [ " title " , " id " , " status " , " description " , " author " , " references " , " fields " , " falsepositives " , " level " , " tags " , " filename " ]
2022-09-09 12:24:30 +02:00
deprecation_warning_message = colored ( " Sigmac will be deprecated by the end of 2022 " ,
" red " ) + " in favour of sigma-cli and pySigma. Please " + colored ( " stop contributing backends " , " red " ) + \
" to this tool. Limited support is offered until the end of 2023, " \
" especially for backends that haven ' t been migrated yet. \n "
2017-03-06 09:36:10 +01:00
def alliter ( path ) :
for sub in path . iterdir ( ) :
2017-12-14 22:39:51 +01:00
if sub . name . startswith ( " . " ) :
continue
2017-03-06 09:36:10 +01:00
if sub . is_dir ( ) :
yield from alliter ( sub )
else :
yield sub
def get_inputs ( paths , recursive ) :
2018-10-07 10:11:47 -05:00
if paths == [ ' - ' ] :
return [ sys . stdin ]
2017-03-06 09:36:10 +01:00
if recursive :
return list ( itertools . chain . from_iterable ( [ list ( alliter ( pathlib . Path ( p ) ) ) for p in paths ] ) )
else :
2017-03-07 09:41:46 +01:00
return [ pathlib . Path ( p ) for p in paths ]
2017-03-06 09:36:10 +01:00
2020-06-06 00:49:57 +02:00
class ActionBackendHelp ( argparse . Action ) :
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 "
2018-03-21 00:53:44 +01:00
2020-06-06 00:49:57 +02:00
print ( helptext )
exit ( 0 )
2018-03-21 00:53:44 +01:00
2019-06-10 09:55:52 +03:00
def set_argparser ( ) :
""" Sets up and parses the command line arguments for Sigmac.
Returns the argparser """
2022-09-09 12:24:30 +02:00
argparser = argparse . ArgumentParser ( description = " Convert Sigma rules into SIEM signatures. \n " + deprecation_warning_message , formatter_class = argparse . RawTextHelpFormatter )
2019-06-10 09:55:52 +03:00
argparser . add_argument ( " --recurse " , " -r " , action = " store_true " , help = " Use directory as input (recurse into subdirectories is not implemented yet) " )
argparser . add_argument ( " --filter " , " -f " , help = """
Define comma-separated filters that must match (AND-linked) to rule to be processed.
2021-09-28 10:33:10 +02:00
Valid filters: level<=x, level>=x, level=x, status=y, logsource=z, tag=t, target=o.
2019-06-10 09:55:52 +03:00
x is one of: low, medium, high, critical.
y is one of: experimental, testing, stable.
z is a word appearing in an arbitrary log source attribute.
t is a tag that must appear in the rules tag list, case-insensitive matching.
2021-09-28 10:33:10 +02:00
o is a target that must appear in the rules target list, case-insensitive matching.
2019-06-10 09:55:52 +03:00
Multiple log source specifications are AND linked.
2021-09-28 10:33:10 +02:00
Special filter:
inlastday=X rule create or modified in the last X days period
2022-05-01 23:07:25 +02:00
tlp=valid_tlp if rule have no tlp set to WHITE
2019-06-10 09:55:52 +03:00
""" )
2020-04-08 23:23:44 +02:00
argparser . add_argument ( " --target " , " -t " , choices = backends . getBackendDict ( ) . keys ( ) , help = " Output target format " )
2019-06-10 09:55:52 +03:00
argparser . add_argument ( " --lists " , " -l " , action = " store_true " , help = " List available output target formats and configurations " )
2022-02-14 15:03:41 -08:00
argparser . add_argument ( " --lists-files-after-date " , " -L " , help = " List yml files which is modified/created after the date (Example of the date: 2022/02/01). " )
2021-02-24 14:43:13 +00:00
argparser . add_argument ( " --config " , " -c " , action = " append " , help = " Configurations with field name and index mapping for target environment. Multiple configurations are merged into one. Last config is authoritative in case of conflicts. " )
2021-06-29 08:13:48 +02:00
argparser . add_argument ( " --output " , " -o " , default = None , help = " Output file or filename prefix (if end with a ' _ ' , ' / ' or ' \\ ' ) " )
2022-05-01 23:07:25 +02:00
argparser . add_argument ( " --output-fields " , " -of " , help = """ Enhance your output with additional fields from the Sigma rule (not only the converted rule itself).
2021-08-12 15:26:46 +02:00
Select the fields you want by providing their list delimited with commas (no space). Only work with the ' --output-format ' option and with ' json ' or ' yaml ' value.
available additional fields : title, id, status, description, author, references, fields, falsepositives, level, tags.
This option do not have any effect for backends that already format output : elastalert, kibana, splukxml etc. """ )
2021-08-12 15:54:02 +02:00
argparser . add_argument ( " --output-format " , " -oF " , choices = [ " json " , " yaml " ] , help = " Use only if you want to have JSON or YAML output (default is raw text) " )
2021-08-18 19:00:57 +00:00
argparser . add_argument ( " --output-extention " , " -e " , default = None , help = " Extension of Output file for filename prefix use " )
2020-12-04 18:22:24 +01:00
argparser . add_argument ( " --print0 " , action = " store_true " , help = " Delimit results by NUL-character " )
2019-06-10 09:55:52 +03:00
argparser . add_argument ( " --backend-option " , " -O " , action = " append " , help = " Options and switches that are passed to the backend " )
2019-10-07 22:30:57 +02:00
argparser . add_argument ( " --backend-config " , " -C " , help = " Configuration file (YAML format) containing options to pass to the backend " )
2020-06-06 00:49:57 +02:00
argparser . add_argument ( " --backend-help " , action = ActionBackendHelp , help = " Print backend options " )
2019-06-10 09:55:52 +03:00
argparser . add_argument ( " --defer-abort " , " -d " , action = " store_true " , help = " Don ' t abort on parse or conversion errors, proceed with next rule. The exit code from the last error is returned " )
argparser . add_argument ( " --ignore-backend-errors " , " -I " , action = " store_true " , help = " Only return error codes for parse errors and ignore errors for rules that cause backend errors. Useful, when you want to get as much queries as possible. " )
argparser . add_argument ( " --shoot-yourself-in-the-foot " , action = " store_true " , help = argparse . SUPPRESS )
argparser . add_argument ( " --verbose " , " -v " , action = " store_true " , help = " Be verbose " )
argparser . add_argument ( " --debug " , " -D " , action = " store_true " , help = " Debugging output " )
argparser . add_argument ( " inputs " , nargs = " * " , help = " Sigma input files ( ' - ' for stdin) " )
2022-05-01 23:07:25 +02:00
2019-06-10 09:55:52 +03:00
return argparser
2020-03-31 11:42:16 +02:00
def list_backends ( debug ) :
2020-02-24 22:59:59 +01:00
for backend in sorted ( backends . getBackendList ( ) , key = lambda backend : backend . identifier ) :
2020-03-31 11:42:16 +02:00
if debug :
2020-02-03 22:16:00 +01:00
print ( " {:>15} : {} ( {} ) " . format ( backend . identifier , backend . __doc__ , backend . __name__ ) )
else :
print ( " {:>15} : {} " . format ( backend . identifier , backend . __doc__ ) )
2019-05-17 09:13:59 +02:00
2020-03-31 12:42:02 +02:00
def list_configurations ( backend = None , scm = None ) :
2020-02-24 22:59:59 +01:00
for conf_id , title , backends in sorted ( scm . list ( ) , key = lambda config : config [ 0 ] ) :
2019-05-24 22:41:47 +02:00
if backend is not None and backend in backends or backend is None or len ( backends ) == 0 :
print ( " {:>30} : {} " . format ( conf_id , title ) )
2020-03-31 11:42:16 +02:00
def list_modifiers ( modifiers ) :
2019-05-26 23:58:56 +02:00
for modifier_id , modifier in modifiers . items ( ) :
print ( " {:>10} : {} " . format ( modifier_id , modifier . __doc__ ) )
2022-02-14 15:03:41 -08:00
def get_fileName_after_date ( inputs , recurse , date ) :
#date: 2021/05/06
#modified: 2021/11/30
dateTime = time . mktime ( datetime . datetime . strptime ( date , " % Y/ % m/ %d " ) . timetuple ( ) )
for sigmafile in get_inputs ( inputs , recurse ) :
f = sigmafile . open ( encoding = ' utf-8 ' )
yamls = yaml . safe_load_all ( f )
datestr = None
modifiedstr = None
for data in yamls :
modifiedstr = data . get ( " modified " , None )
datestr = data . get ( " date " , None )
if not modifiedstr and not datestr :
continue ;
if not modifiedstr and not datestr :
print ( " %s , No date " % sigmafile )
continue
if not modifiedstr :
modifiedstr = datestr
modified = time . mktime ( datetime . datetime . strptime ( modifiedstr , " % Y/ % m/ %d " ) . timetuple ( ) )
if modified > dateTime :
print ( " %s , Updated " % sigmafile )
2020-03-31 11:30:14 +02:00
def main ( ) :
argparser = set_argparser ( )
cmdargs = argparser . parse_args ( )
scm = SigmaConfigurationManager ( )
logger = logging . getLogger ( __name__ )
if cmdargs . debug : # pragma: no cover
2021-09-25 19:33:30 +02:00
logging . basicConfig ( filename = ' sigmac.log ' , filemode = ' w ' , level = logging . DEBUG )
2020-03-31 11:30:14 +02:00
logger . setLevel ( logging . DEBUG )
2019-11-03 23:32:50 +01:00
2020-03-31 11:30:14 +02:00
if cmdargs . lists :
2020-06-25 13:21:43 +02:00
print ( " Backends (Targets): " )
2020-03-31 11:42:16 +02:00
list_backends ( cmdargs . debug )
2020-03-31 11:30:14 +02:00
print ( )
2020-06-25 13:21:43 +02:00
print ( " Configurations (Sources): " )
2020-03-31 11:42:16 +02:00
list_configurations ( backend = cmdargs . target , scm = scm )
2019-11-03 23:32:50 +01:00
2020-03-31 11:30:14 +02:00
print ( )
print ( " Modifiers: " )
2020-03-31 11:42:16 +02:00
list_modifiers ( modifiers = modifiers )
2020-03-31 11:30:14 +02:00
sys . exit ( 0 )
elif len ( cmdargs . inputs ) == 0 :
print ( " Nothing to do! " )
2022-09-09 12:24:30 +02:00
print ( deprecation_warning_message )
2020-03-31 11:30:14 +02:00
argparser . print_usage ( )
sys . exit ( 0 )
2022-02-14 15:03:41 -08:00
if cmdargs . lists_files_after_date is not None :
get_fileName_after_date ( cmdargs . inputs , cmdargs . recurse , cmdargs . lists_files_after_date )
sys . exit ( 0 )
2020-03-31 11:30:14 +02:00
if cmdargs . target is None :
print ( " No target selected, select one with -t/--target " )
argparser . print_usage ( )
sys . exit ( ERR_NO_TARGET )
2021-09-25 19:33:30 +02:00
logger . debug ( " * Target selected %s " % ( cmdargs . target ) )
2020-03-31 11:30:14 +02:00
rulefilter = None
if cmdargs . filter :
2018-08-27 00:17:27 +02:00
try :
2020-03-31 11:30:14 +02:00
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): " )
2020-03-31 11:46:05 +02:00
list_configurations ( backend = cmdargs . target , scm = scm )
2020-03-31 11:30:14 +02:00
sys . exit ( ERR_CONFIG_REQUIRED )
2020-07-15 16:29:27 +01:00
if backend_class . default_config is not None :
cmdargs . config = backend_class . default_config
2019-04-23 00:54:10 +02:00
2020-03-31 11:30:14 +02:00
if cmdargs . config :
order = 0
for conf_name in cmdargs . config :
2019-05-20 01:00:33 +02:00
try :
2020-03-31 11:30:14 +02:00
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 )
2021-08-12 15:26:46 +02:00
if cmdargs . output_fields :
2022-05-01 23:07:25 +02:00
if cmdargs . output_format :
2021-08-12 15:26:46 +02:00
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 :
2021-08-12 15:54:02 +02:00
print ( " The ' --output-fields ' or ' -of ' arguments must be used with ' --output-format ' or ' -oF ' equal to ' json ' or ' yaml ' " , file = sys . stderr )
2021-08-12 15:26:46 +02:00
exit ( ERR_OUTPUT_FORMAT )
2020-03-31 11:30:14 +02:00
backend_options = BackendOptions ( cmdargs . backend_option , cmdargs . backend_config )
backend = backend_class ( sigmaconfigs , backend_options )
2022-05-01 23:07:25 +02:00
2021-06-29 08:13:48 +02:00
filename_ext = cmdargs . output_extention
2020-03-31 11:30:14 +02:00
filename = cmdargs . output
2021-06-28 19:27:20 +02:00
fileprefix = None
2020-03-31 11:30:14 +02:00
if filename :
2021-06-29 08:13:48 +02:00
if filename_ext :
if filename_ext [ 0 ] == ' . ' :
pass
else :
filename_ext = ' . ' + filename_ext
else :
filename_ext = ' .rule '
2022-05-01 23:07:25 +02:00
2021-06-28 21:25:51 +02:00
if filename [ - 1 : ] in [ ' _ ' , ' / ' , ' \\ ' ] :
2021-06-28 19:27:20 +02:00
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 )
2020-03-31 11:30:14 +02:00
else :
out = sys . stdout
2019-05-20 01:00:33 +02:00
2020-03-31 11:30:14 +02:00
error = 0
2021-08-12 15:26:46 +02:00
output_array = [ ]
2022-03-08 09:30:27 -08:00
result = backend . initialize ( )
if result :
print ( result , file = out )
2020-03-31 11:30:14 +02:00
for sigmafile in get_inputs ( cmdargs . inputs , cmdargs . recurse ) :
logger . debug ( " * Processing Sigma input %s " % ( sigmafile ) )
2021-09-25 19:33:30 +02:00
success = True
2020-03-31 11:30:14 +02:00
try :
if cmdargs . inputs == [ ' - ' ] :
f = sigmafile
else :
f = sigmafile . open ( encoding = ' utf-8 ' )
2021-05-28 10:51:08 +02:00
parser = SigmaCollectionParser ( f , sigmaconfigs , rulefilter , sigmafile )
2022-02-14 15:03:41 -08:00
backend . setYmlFileName ( str ( sigmafile ) )
2020-03-31 11:30:14 +02:00
results = parser . generate ( backend )
2021-08-12 15:26:46 +02:00
2021-08-01 19:34:07 +02:00
nb_result = len ( list ( copy . deepcopy ( results ) ) )
inc_filenane = None if nb_result < 2 else 0
2022-05-01 23:07:25 +02:00
2020-12-06 20:08:00 +01:00
newline_separator = ' \0 ' if cmdargs . print0 else ' \n '
2021-08-12 15:26:46 +02:00
results = list ( results ) # Since results is an iterator and used twice we convert it a list
2020-03-31 11:30:14 +02:00
for result in results :
2021-06-29 17:45:59 +02:00
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 )
2022-05-01 23:07:25 +02:00
filename = filename . replace ( ' .yml ' , filename_ext )
2021-06-29 17:45:59 +02:00
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 )
2021-08-12 15:26:46 +02:00
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 ]
2022-02-26 18:24:15 +01:00
if len ( output [ ' rule ' ] ) > 0 : # avoid printing empty rules
if " filename " in output_fields_filtered :
output [ ' filename ' ] = str ( sigmafile . name )
output_array . append ( output )
2021-08-12 15:26:46 +02:00
2021-08-05 20:37:07 +02:00
if nb_result == 0 : # backend get only 1 output
if not fileprefix == None : # want a prefix anyway
2021-08-01 19:34:07 +02:00
try :
2021-08-05 22:38:48 +02:00
filename = " %s %s _mono_output %s " % ( fileprefix , cmdargs . target , filename_ext )
2021-08-01 19:34:07 +02:00
out = open ( filename , " w " , encoding = ' utf-8 ' )
2021-08-05 20:37:07 +02:00
fileprefix = None # no need to open the same file many time
2021-08-01 19:34:07 +02:00
except ( IOError , OSError ) as e :
print ( " Failed to open output file ' %s ' : %s " % ( filename , str ( e ) ) , file = sys . stderr )
2022-05-01 23:07:25 +02:00
exit ( ERR_OUTPUT )
2021-08-12 15:26:46 +02:00
2018-08-27 00:17:27 +02:00
except OSError as e :
2020-03-31 11:30:14 +02:00
print ( " Failed to open Sigma file %s : %s " % ( sigmafile , str ( e ) ) , file = sys . stderr )
2021-09-25 19:33:30 +02:00
logger . debug ( " * Convertion Sigma input %s FAILURE " % ( sigmafile ) )
success = False
2020-03-31 11:30:14 +02:00
error = ERR_OPEN_SIGMA_RULE
2018-08-27 00:17:27 +02:00
except ( yaml . parser . ParserError , yaml . scanner . ScannerError ) as e :
2021-05-05 12:59:13 +02:00
print ( " Error: Sigma file %s is no valid YAML: %s " % ( sigmafile , str ( e ) ) , file = sys . stderr )
2021-09-25 19:33:30 +02:00
logger . debug ( " * Convertion Sigma input %s FAILURE " % ( sigmafile ) )
success = False
2020-03-31 11:30:14 +02:00
error = ERR_INVALID_YAML
2018-06-22 00:22:45 +02:00
if not cmdargs . defer_abort :
sys . exit ( error )
2020-03-31 11:30:14 +02:00
except ( SigmaParseError , SigmaCollectionParseError ) as e :
2021-05-05 12:59:13 +02:00
print ( " Error: Sigma parse error in %s : %s " % ( sigmafile , str ( e ) ) , file = sys . stderr )
2021-09-25 19:33:30 +02:00
logger . debug ( " * Convertion Sigma input %s FAILURE " % ( sigmafile ) )
success = False
2020-03-31 11:30:14 +02:00
error = ERR_SIGMA_PARSING
2018-06-07 23:32:52 +02:00
if not cmdargs . defer_abort :
sys . exit ( error )
2020-03-31 11:30:14 +02:00
except NotSupportedError as e :
2021-05-05 12:59:13 +02:00
print ( " Error: The Sigma rule requires a feature that is not supported by the target system: " + str ( e ) , file = sys . stderr )
2021-09-25 19:33:30 +02:00
logger . debug ( " * Convertion Sigma input %s FAILURE " % ( sigmafile ) )
success = False
2020-03-31 11:30:14 +02:00
if not cmdargs . ignore_backend_errors :
error = ERR_NOT_SUPPORTED
if not cmdargs . defer_abort :
sys . exit ( error )
except BackendError as e :
2021-05-05 12:59:13 +02:00
print ( " Error: Backend error in %s : %s " % ( sigmafile , str ( e ) ) , file = sys . stderr )
2021-09-25 19:33:30 +02:00
logger . debug ( " * Convertion Sigma input %s FAILURE " % ( sigmafile ) )
success = False
2020-03-31 11:30:14 +02:00
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 )
2021-10-26 18:25:23 +00:00
# traceback.print_exc()
2021-09-25 19:33:30 +02:00
logger . debug ( " * Convertion Sigma input %s FAILURE " % ( sigmafile ) )
success = False
2020-03-31 11:30:14 +02:00
if not cmdargs . ignore_backend_errors :
error = ERR_NOT_IMPLEMENTED
if not cmdargs . defer_abort :
sys . exit ( error )
except PartialMatchError as e :
2021-05-05 12:59:13 +02:00
print ( " Error: Partial field match error: %s " % str ( e ) , file = sys . stderr )
2021-09-25 19:33:30 +02:00
logger . debug ( " * Convertion Sigma input %s FAILURE " % ( sigmafile ) )
success = False
2020-03-31 11:30:14 +02:00
if not cmdargs . ignore_backend_errors :
error = ERR_PARTIAL_FIELD_MATCH
if not cmdargs . defer_abort :
sys . exit ( error )
except FullMatchError as e :
2021-05-05 12:59:13 +02:00
print ( " Error: Full field match error " , file = sys . stderr )
2021-09-25 19:33:30 +02:00
logger . debug ( " * Convertion Sigma input %s FAILURE " % ( sigmafile ) )
success = False
2020-03-31 11:30:14 +02:00
if not cmdargs . ignore_backend_errors :
error = ERR_FULL_FIELD_MATCH
if not cmdargs . defer_abort :
2022-05-01 23:07:25 +02:00
sys . exit ( error )
2020-03-31 11:30:14 +02:00
finally :
try :
f . close ( )
except :
pass
2022-05-01 23:07:25 +02:00
2021-09-25 19:33:30 +02:00
if success :
2022-05-01 23:07:25 +02:00
logger . debug ( " * Convertion Sigma input %s SUCCESS " % ( sigmafile ) )
2020-03-31 11:30:14 +02:00
result = backend . finalize ( )
if result :
print ( result , file = out )
2021-09-25 19:33:30 +02:00
2021-08-12 15:26:46 +02:00
if cmdargs . output_fields :
if cmdargs . output_format == ' json ' :
print ( json . dumps ( output_array , indent = 4 , ensure_ascii = False ) , file = out )
2022-08-10 07:42:50 +02:00
elif cmdargs . output_format == ' yaml ' :
print ( ruamel . yaml . round_trip_dump ( output_array ) , file = out )
2021-08-12 15:26:46 +02:00
2020-03-31 11:30:14 +02:00
out . close ( )
2018-08-02 22:41:32 +02:00
2020-03-31 11:30:14 +02:00
sys . exit ( error )
2017-08-02 00:56:22 +02:00
2020-03-31 11:30:14 +02:00
if __name__ == " __main__ " :
main ( )