├── requirements.txt ├── screenshots └── screen-0.0.1.png ├── tests ├── fw-log1.txt ├── checkpoint-event.txt ├── win-system-service-event.xml ├── win-sec-event.xml ├── win-event.xml └── sysmon-event.xml ├── README.md ├── .gitignore ├── LICENSE └── evt2sigma.py /requirements.txt: -------------------------------------------------------------------------------- 1 | colorama==0.3.9 -------------------------------------------------------------------------------- /screenshots/screen-0.0.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/evt2sigma/master/screenshots/screen-0.0.1.png -------------------------------------------------------------------------------- /tests/fw-log1.txt: -------------------------------------------------------------------------------- 1 | Jun 1 22:01:57 [xx] ns5gt: NetScreen device_id=ns5gt [Root]system-alert-00016: Port scan! From 1.2.3.4:55181 to 2.3.4.5:1358, proto TCP (zone Untrust, int untrust). Occurred 1 times. (2004-06-01 22:09:25) -------------------------------------------------------------------------------- /tests/checkpoint-event.txt: -------------------------------------------------------------------------------- 1 | Apr 11 11:04:48 hostng Checkpoint: 21Aug2007 12:00:00 accept 10.10.10.2 >eth0 rule: 100; rule_uid: {00000000-0000-0000-0000-000000000000}; service_id: nbdatagram; src: 10.10.10.3; dst: 10.10.10.255; proto: udp; product: VPN-1 & FireWall-1; service: 138; s_port: 138; -------------------------------------------------------------------------------- /tests/win-system-service-event.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7045 5 | 0 6 | 4 7 | 0 8 | 0 9 | 0x8080000000000000 10 | 11 | 201584 12 | 13 | 14 | System 15 | PROMETHEUS 16 | 17 | 18 | 19 | WCESERVICE 20 | C:\temp\wce\wce.exe -S 21 | user mode service 22 | demand start 23 | LocalSystem 24 | 25 | -------------------------------------------------------------------------------- /tests/win-sec-event.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4688 5 | 1 6 | 0 7 | 13312 8 | 0 9 | 0x8020000000000000 10 | 11 | 18468479 12 | 13 | 14 | Security 15 | PROMETHEUS 16 | 17 | 18 | 19 | S-1-5-19 20 | LOCAL SERVICE 21 | NT AUTHORITY 22 | 0x3e5 23 | 0x120 24 | C:\Windows\System32\audiodg.exe 25 | %%1936 26 | 0x338 27 | C:\Windows\system32\AUDIODG.EXE 0x7c 28 | 29 | -------------------------------------------------------------------------------- /tests/win-event.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4688 5 | 1 6 | 0 7 | 13312 8 | 0 9 | 0x8020000000000000 10 | 11 | 18468410 12 | 13 | 14 | Security 15 | PROMETHEUS 16 | 17 | 18 | 19 | S-1-5-18 20 | PROMETHEUS$ 21 | WORKGROUP 22 | 0x3e7 23 | 0xad0 24 | C:\Windows\System32\GWX\GWXConfigManager.exe 25 | %%1936 26 | 0x254 27 | C:\Windows\system32\GWX\GWXConfigManager.exe /RefreshConfig 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # evt2sigma 2 | Log Entry to Sigma Rule Converter 3 | 4 | # What it does 5 | 6 | It takes a log entry from a file and tries to create a [Sigma](https://github.com/Neo23x0/sigma) rule. It is optimized for the XML format of Windows EVTX event logs but can be easily modified to support more log formats by adding a new regular expression for the respective log type. 7 | 8 | # Status 9 | 10 | The current state is "alpha". It's more like a public POC so that others can learn and extend. 11 | 12 | # Usage 13 | 14 | usage: evt2sigma.py [-h] [-f file] [-o out-file] [-fc field-count] [--debug] 15 | [--trace] [-a] [-r] [-l] [-t] [-d] [-p] [-s] [-c] 16 | 17 | Event 2 Sigma Converter 18 | 19 | optional arguments: 20 | -h, --help show this help message and exit 21 | -f file Read the log entry from a file 22 | -o out-file Write rule to an output file 23 | -fc field-count use the top X fields 24 | --debug Debug output 25 | --trace Trace output 26 | 27 | Fields: 28 | -a Author name 29 | -r Reference 30 | -l Level 31 | -t Title 32 | -d Description 33 | -p Product (e.g. windows, linux) 34 | -s Service (e.g. security, sysmon) 35 | -c Category (e.g. proxy) 36 | 37 | # Screenshot 38 | 39 | ![evt2sigma Screenshot](https://github.com/Neo23x0/evt2sigma/blob/master/screenshots/screen-0.0.1.png "Example of conversion") 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | rule.yml 106 | -------------------------------------------------------------------------------- /tests/sysmon-event.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 5 6 | 4 7 | 1 8 | 0 9 | 0x8000000000000000 10 | 11 | 1247136 12 | 13 | 14 | Microsoft-Windows-Sysmon/Operational 15 | PROMETHEUS 16 | 17 | 18 | 19 | 2018-05-26 10:23:19.332 20 | {C1B49677-3597-5B08-0000-0010D2635100} 21 | 1196 22 | C:\Windows\System32\mmc.exe 23 | "C:\Windows\system32\mmc.exe" "C:\Windows\system32\eventvwr.msc" /s 24 | C:\Windows\system32\ 25 | PROMETHEUS\neo 26 | {C1B49677-2C06-5B09-0000-002007FF0100} 27 | 0x1ff07 28 | 1 29 | High 30 | SHA1=F5DC12D658402900A2B01AF2F018D113619B96B8,MD5=9FEA051A9585F2A303D55745B4BF63AA 31 | {C1B49676-2C07-5B09-0000-00107F1F0200} 32 | 2224 33 | C:\Windows\explorer.exe 34 | C:\Windows\Explorer.EXE 35 | 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /evt2sigma.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | __AUTHOR__ = 'Florian Roth' 4 | __VERSION__ = "0.0.1 May 2018" 5 | 6 | """ 7 | Install dependencies with: 8 | 9 | pip3 install colorama 10 | """ 11 | 12 | import re 13 | import operator 14 | import datetime 15 | from itertools import islice 16 | import argparse 17 | from colorama import init, Fore, Back, Style 18 | import sys 19 | 20 | # Config 21 | 22 | XML = r'<([\w]+)[^\>\/]*>([^<]+)<\/' 23 | XML_DATA = r'<[\w]+ Name="([^\"]+)">([^<]+)<\/' 24 | CP1 = r' ([A-Za-z_]+): ([^;]+)[;]?' 25 | DEF1 = r' (from|to|protocol|proto|src|dst|service|id|port|dstport|srcport)[:]? ["\']?([\w.:]+)["\']?' 26 | DEF2 = r' (from|to|protocol|proto|src|dst|service|id|port|dstport|srcport)=["\']?([\w.:]+)["\']?' 27 | 28 | REGEX_SET = [XML_DATA, XML, CP1, DEF1, DEF2] 29 | 30 | SIGMA_TEMPLATE = """ 31 | title: %%%title%%% 32 | status: experimental 33 | description: '%%%description%%%' 34 | date: %%%date%%% 35 | references: 36 | - %%%reference%%% 37 | author: %%%author%%% 38 | logsource: 39 | %%%logsource%%% 40 | detection: 41 | selection: %%%selection%%% 42 | condition: selection 43 | falsepositives: 44 | - Unknown 45 | level: %%%level%%% 46 | """ 47 | 48 | UNUSABLE_FIELDS = ['rule_uid', 'ruleid'] 49 | 50 | # Program 51 | 52 | def read_file(file_path): 53 | """ 54 | Reads a file and returns the string 55 | :param file_path: 56 | :return: 57 | """ 58 | with open(file_path, 'r') as fh: 59 | return fh.read() 60 | 61 | def generate_sigma(kvs, args): 62 | """ 63 | Generates a Sigma rule using a set of key/value pairs 64 | :param kvs: key/value pairs as dictionary 65 | :return rule: rule string 66 | """ 67 | # Replace values in template 68 | rule = SIGMA_TEMPLATE 69 | rule = rule.replace('%%%title%%%', args.t) 70 | rule = rule.replace('%%%description%%%', args.d) 71 | rule = rule.replace('%%%reference%%%', args.r) 72 | rule = rule.replace('%%%author%%%', args.a) 73 | rule = rule.replace('%%%date%%%', datetime.datetime.today().strftime('%Y-%m-%d')) 74 | logsource = "product: %s" % args.p 75 | if args.s: 76 | logsource += "\n\tservice: %s" % args.s 77 | if args.c: 78 | logsource = "category: %s" % args.c 79 | rule = rule.replace('%%%logsource%%%', logsource) 80 | rule = rule.replace('%%%level%%%', args.l) 81 | 82 | # Create the selection 83 | selection = "" 84 | for k, v in kvs.items(): 85 | # Integer 86 | if v.isdigit(): 87 | selection_element = "\n\t%s: %s" % (k, v) 88 | else: 89 | selection_element = "\n\t%s: '%s'" % (k, v) 90 | selection += selection_element 91 | 92 | rule = rule.replace('%%%selection%%%', selection) 93 | 94 | return rule 95 | 96 | 97 | def extract_values(string, re_set): 98 | """ 99 | Extract the key/value pairs from the string 100 | :param string: event log entry string 101 | :param re_set: set of regular expressions to use 102 | :return: 103 | """ 104 | kvs = {} 105 | for regex in re_set: 106 | extracted = dict(regex.findall(string, re.IGNORECASE)) 107 | kvs = {**kvs, **extracted} 108 | return kvs 109 | 110 | 111 | def take(n, iterable): 112 | """ 113 | Return first n items of the iterable as a list 114 | :param n: number of items 115 | :param iterable: dictionary 116 | :return: 117 | """ 118 | return list(islice(iterable, n)) 119 | 120 | 121 | def filter_kvs(kvs, top_count): 122 | """ 123 | Filter key value pairs and set a score by key to improve the selection of relevant values 124 | :param kvs: key/value pairs 125 | :return keyscores: keys and their scores in a dictionary 126 | """ 127 | key_scores = {} 128 | # Loop over key/value pairs 129 | for k, v in kvs.items(): 130 | # Key not already set 131 | if k not in key_scores: 132 | key_scores[k] = 0 133 | 134 | # NEGATIVE SCORES 135 | # Empty values 136 | if v == "" or v == " " or v == "\n": 137 | key_scores[k] -= 50 138 | # Event Record Id 139 | if "recordid" in k.lower(): 140 | key_scores[k] -= 20 141 | # Data Fields in Windows EVTX events 142 | if k == "Data": 143 | key_scores[k] -= 50 144 | # Computer Names 145 | if "computer" in k.lower(): 146 | key_scores[k] -= 20 147 | # Timestamp 148 | if "time" in k.lower(): 149 | key_scores[k] -= 30 150 | # GUIDs 151 | if "guid" in k.lower(): 152 | key_scores[k] -= 20 153 | # Process IDs 154 | if "processid" in k.lower() or "processguid" in k.lower(): 155 | key_scores[k] -= 20 156 | # Sysmon 157 | if k == "LogonGuid": 158 | key_scores[k] -= 30 159 | # Too many space values could indicate an error in extraction 160 | if v.count(" ") > 4: 161 | key_scores[k] -= 3 162 | # Too many space values could indicate an error in extraction 163 | if "version" in k.lower(): 164 | key_scores[k] -= 2 165 | # Unusable fields 166 | for uf in UNUSABLE_FIELDS: 167 | if uf == k: 168 | key_scores[k] -= 30 169 | 170 | # POSITIVE SCORES 171 | # EventIDs 172 | if k == "EventID": 173 | key_scores[k] += 40 174 | 175 | # Generic Strings 176 | if k == "ImagePath": 177 | key_scores[k] += 20 178 | if k == "Type": 179 | key_scores[k] += 5 180 | if k == "Service": 181 | key_scores[k] += 5 182 | 183 | # Values 184 | if ".exe" in v.lower(): 185 | key_scores[k] += 5 186 | if "temp" in v.lower(): 187 | key_scores[k] += 5 188 | 189 | # Sysmon 190 | if k == "CommandLine": 191 | key_scores[k] += 40 192 | if k == "ParentImage": 193 | key_scores[k] += 20 194 | if k == "ParentCommandLine": 195 | key_scores[k] += 19 196 | if k == "NewProcessName": 197 | key_scores[k] += 15 198 | if k == "TokenElevationType": 199 | key_scores[k] += 5 200 | if k == "MD5" or k == "SHA1" or k == "SHA256" or k.lower() == "imphash": 201 | key_scores[k] += 15 202 | 203 | # Sort the key scores to get a list with decending scores 204 | key_scores = sorted(key_scores.items(), key=operator.itemgetter(1), reverse=True) 205 | if args.trace: 206 | print("Key scores:") 207 | print(key_scores) 208 | 209 | # Get only the top X kvs 210 | selected_kvs = {} 211 | count = 0 212 | for k, c in key_scores: 213 | selected_kvs[k] = kvs[k] 214 | count += 1 215 | if count > top_count: 216 | break 217 | 218 | return selected_kvs 219 | 220 | 221 | if __name__ == '__main__': 222 | 223 | init(autoreset=False) 224 | 225 | print(Style.RESET_ALL) 226 | print(Fore.BLACK + Back.WHITE) 227 | print(" ____ __ ___ _____ ".ljust(80)) 228 | print(" / __/ __/ /_|_ |/ __(_)__ ___ _ ___ _ ".ljust(80)) 229 | print(" / _/| |/ / __/ __/_\ \/ / _ `/ ' \/ _ `/ ".ljust(80)) 230 | print(" /___/|___/\__/____/___/_/\_, /_/_/_/\_,_/ ".ljust(80)) 231 | print(" /___/ ".ljust(80)) 232 | print(" ".ljust(80)) 233 | print(" Converts a log line to a Sigma rule".ljust(80)) 234 | print((" " + __AUTHOR__ + " - " + __VERSION__ + "").ljust(80)) 235 | print(" ".ljust(80) + Style.RESET_ALL) 236 | print(Style.RESET_ALL + " ") 237 | 238 | parser = argparse.ArgumentParser(description='Event 2 Sigma Converter') 239 | 240 | parser.add_argument('-f', help='Read the log entry from a file', metavar='file', default='') 241 | parser.add_argument('-o', help='Write rule to an output file', metavar='out-file', default='') 242 | 243 | parser.add_argument('-fc', help='use the top X fields', metavar='field-count', default='4') 244 | parser.add_argument('--debug', action='store_true', default=False, help='Debug output') 245 | parser.add_argument('--trace', action='store_true', default=False, help='Trace output') 246 | 247 | group_header = parser.add_argument_group('Fields') 248 | group_header.add_argument('-a', help='Author name', metavar='', default='Evt2Sigma') 249 | group_header.add_argument('-r', help='Reference', metavar='', default='Internal Research') 250 | group_header.add_argument('-l', help='Level', metavar='', default='medium') 251 | group_header.add_argument('-t', help='Title', metavar='', default='Relevant Event') 252 | group_header.add_argument('-d', help='Description', metavar='', default='Auto-generated Sigma rule') 253 | group_header.add_argument('-p', help='Product (e.g. windows, linux)', metavar='', default='windows') 254 | group_header.add_argument('-s', help='Service (e.g. security, sysmon)', metavar='', default='') 255 | group_header.add_argument('-c', help='Category (e.g. proxy)', metavar='', default='') 256 | 257 | args = parser.parse_args() 258 | if len(sys.argv) <2: 259 | parser.print_usage() 260 | sys.exit(1) 261 | 262 | # Prepare Regex set 263 | re_set = [] 264 | for regex_string in REGEX_SET: 265 | regex = re.compile(regex_string) 266 | re_set.append(regex) 267 | 268 | # Read a log entry from a file 269 | entry = read_file(args.f) 270 | #if args.debug: 271 | print(Fore.BLACK + Back.WHITE, "Event Entry:", Style.RESET_ALL) 272 | print("") 273 | print(entry) 274 | print("") 275 | 276 | # Parse the log entry 277 | kvs = extract_values(entry, re_set) 278 | if args.trace: 279 | print("All extracted key value pairs:") 280 | print(kvs) 281 | selected_kvs = take(int(args.fc), kvs.items()) 282 | 283 | # Generate a rule 284 | rule = generate_sigma(filter_kvs(kvs, int(args.fc)), args) 285 | #if args.debug: 286 | print(Fore.BLACK + Back.WHITE, "Sigma Rule:", Style.RESET_ALL) 287 | print(rule) 288 | print("") 289 | 290 | # Write an output file 291 | if args.o: 292 | with open(args.o, "w") as fh: 293 | fh.write(rule) 294 | 295 | --------------------------------------------------------------------------------