├── 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 | 
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 |
--------------------------------------------------------------------------------