logstash-filter-sig 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2511 @@
1
+ # encoding: utf-8
2
+ # Filter "SIG" analyze signature regexp with condition
3
+ # POC on event normalized -- experimental version
4
+ # Contact: Lionel PRAT (lionel.prat9@gmail.com)
5
+
6
+ require "logstash/filters/base"
7
+ require "logstash/namespace"
8
+ require "json"
9
+ require "simhash"
10
+ require 'digest'
11
+ require "openssl"
12
+ require 'ipaddr'
13
+ require 'time'
14
+
15
+ #TODO fix fingerprint must be used when SIG/REF/IOC detected
16
+ #plugin multi function:
17
+ # - signature
18
+ # - IOC
19
+ # - ANOMALIE
20
+ # - new value in time or no time
21
+ # - fingerprint simhash
22
+ # - filter false positive
23
+ # - first drop list on fingerprint or field -> regexp (ex: host & domain)
24
+ # Optimiz
25
+
26
+ #TODO: SIG add tag on sig for FIR
27
+ class ::Hash
28
+ def deep_merge(second)
29
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
30
+ self.merge(second, &merger)
31
+ end
32
+ end
33
+
34
+ class LogStash::Filters::Sig < LogStash::Filters::Base
35
+ config_name "sig"
36
+ milestone 1
37
+ ############PLUGIN LOGSTASH SIG -- lionel.prat9@gmail.com #############
38
+ ############MULTI FUNCTIONNALITY IN ORDER CALL########################
39
+ ###### DROP_FIRST[FIELD(regexp_list)]->NEW_VALUE[time/notime]->BL->SIG[FIELD_IOC(misp_extract),RULES(list),FALSE_POSITIVE(drop),ANOMALIE(db_reference),DROP_END[SIMHASH(match_list)],FREQ(db_frequence -> create new event if alert) ########
40
+ ###### SIG add special_tag if match #######
41
+ ############### CONFIG DROP SIMPLE FIRST & FINGERPRINT SIMHASH ###################
42
+ ## DESCRIPTION: use for drop noise without risk with very simple rule, if nothing detected then create fingerprint simhash, thus check if fingerprint content in db fingerprint false positive to drop.
43
+ ## Fingerprint hash can use by active add information (scan active, whois, ssl check, ...) for avoid to verify multi time for same alert.
44
+ ## EXAMPLE: { "domain" : "^google.(com|fr)$"}
45
+ #disable by field in event
46
+ config :no_check, :validate => :string, :default => "sig_no_apply_all"
47
+ #disable functions
48
+ config :disable_drop, :validate => :boolean, :default => false
49
+ config :disable_enr, :validate => :boolean, :default => false
50
+ config :disable_fp, :validate => :boolean, :default => false
51
+ config :disable_nv, :validate => :boolean, :default => false
52
+ config :disable_bl, :validate => :boolean, :default => false
53
+ config :disable_ioc, :validate => :boolean, :default => false
54
+ config :disable_sig, :validate => :boolean, :default => false
55
+ config :disable_ref, :validate => :boolean, :default => false
56
+ config :disable_freq, :validate => :boolean, :default => false
57
+ config :disable_note, :validate => :boolean, :default => false
58
+
59
+ #if field exist in event then no apply drop & fingerprint
60
+ config :noapply_sig_dropfp, :validate => :string, :default => "sig_no_apply_dropfp"
61
+ config :noapply_sig_dropdb, :validate => :string, :default => "sig_no_apply_dropdb"
62
+
63
+
64
+ #CONF FINGERPRINT - format: json {"type": {fields: [a,b,c], delay: 3600, hashbit: 16},}
65
+ # create simhash (on hashbit) with fields [a,b,c] for delay 3600 . The delay is used for tag first alert or complementary information. Use delay by exemple if you use dhcp and ip in fingerprint...
66
+ config :conf_fp, :validate => :path, :default => "/etc/logstash/db/fingerprint_conf.json"
67
+
68
+ #DROP RULES DB - format: json {"field": "regexp"} - don't use same field name more time
69
+ config :db_drop, :validate => :path, :default => "/etc/logstash/db/drop-db.json"
70
+ #DROP FINGERPRINT DB - format: json {"fingerprint": "raison of fp"}
71
+ config :db_dropfp, :validate => :path, :default => "/etc/logstash/db/drop-fp.json"
72
+
73
+ #Name of field for select rules fp - exemple event['type']="squid" -- in fp_conf.sig: #{"squid":{"fields":["src_ip","dst_host","dst_ip","uri_proto","sig_detected_name","ioc_detected","tags"],"hashbit":8,"delay":3600}}
74
+ #  |--> ^^^^^ ^^^^^
75
+ config :select_fp, :validate => :string, :default => "type"
76
+ #Name of field to save fingerprint
77
+ config :target_fp, :validate => :string, :default => "fingerprint"
78
+
79
+ # add tage name if not match
80
+ # tag mark for difference first fingerprint see, another fingerprint identical is tagger with tag_name_after (complementary information)
81
+ config :tag_name_first, :validate => :string, :default => "first_alert"
82
+ config :tag_name_after, :validate => :string, :default => "info_comp"
83
+ #Select field for write tag information fp: first or complementary
84
+ config :target_tag_fp, :validate => :string, :default => "tags"
85
+
86
+ #interval to refresh conf fingerprint & db
87
+ config :refresh_interval_conffp, :validate => :number, :default => 3600
88
+ #interval to refresh database rules & fingerprint
89
+ config :refresh_interval_dropdb, :validate => :number, :default => 3600
90
+
91
+ ############### CONFIG ENRICHMENT ###################
92
+ #Description: add info in event by enrichment active or passive
93
+
94
+ #File config - format: json
95
+ config :conf_enr, :validate => :path, :default => "/etc/logstash/db/enr.json"
96
+
97
+ #if field exist in event then no apply new value tag
98
+ config :noapply_sig_enr, :validate => :string, :default => "sig_no_apply_enr"
99
+
100
+ #interval to refresh conf new_value
101
+ config :refresh_interval_enr, :validate => :number, :default => 3600
102
+
103
+ #field name where you add request for server add information active
104
+ config :field_enr, :validate => :string, :default => "request_enrichiment"
105
+
106
+ #enr_tag_response used for identify who is origin of resquest, and send response to good server
107
+ config :enr_tag_response, :validate => :string, :required => :true, :default => "ENR_RETURN_TO_JOHN"
108
+
109
+ #When information not in db and you must to have, send event to another server (contacted by lumberjack) who ask info and add in @field_enr
110
+ # after add info in field, resend to server origin by lumberjack
111
+
112
+ ############### CONFIG NEW VALUE ###################
113
+ #Description: check by rule if event is new and tag event
114
+ #Exemple: verify on field domain new value, if field domain in event content new value then add in db and tag event
115
+
116
+ #File config - format: json {"rules": ["fieldy","fieldx"]}
117
+ config :conf_nv, :validate => :path, :default => "/etc/logstash/db/new.json"
118
+
119
+ #File save db - format: json
120
+ config :db_nv, :validate => :path, :default => "/etc/logstash/db/new-save.json"
121
+
122
+ #if field exist in event then no apply new value tag
123
+ config :noapply_sig_nv, :validate => :string, :default => "sig_no_apply_nv"
124
+
125
+ #interval to refresh conf new_value
126
+ config :refresh_interval_confnv, :validate => :number, :default => 3600
127
+
128
+ #interval to save file db new value
129
+ config :save_interval_dbnv, :validate => :number, :default => 3600
130
+
131
+ #Name of prefix field to save new_value tag (prefix+field_name)
132
+ config :target_nv, :validate => :string, :default => "new_value_"
133
+
134
+ ############### CONFIG BL REPUTATION ###################
135
+ #Description: check if field value is present in DB REPUTATION
136
+ #JUST IP for first time
137
+
138
+ #BL REPUT config - format: json {fieldx: {dbs: [file_name,...], note: X, id: X, category: "malware"}}
139
+ config :conf_bl, :validate => :path, :default => "/etc/logstash/db/conf_bl.json"
140
+
141
+ #File contains BL REPUTATION
142
+ #https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset
143
+ #https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level2.netset
144
+ #https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level3.netset
145
+ #https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level4.netset
146
+ #https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_webserver.netset
147
+ #https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_webclient.netset
148
+ #https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_abusers_30d.netset
149
+ #https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_anonymous.netset
150
+ #https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_proxies.netset
151
+ config :file_bl, :validate => :array, :default => ["/etc/logstash/db/firehol_level1.netset","/etc/logstash/db/firehol_level2.netset","/etc/logstash/db/firehol_level3.netset","/etc/logstash/db/firehol_level4.netset","/etc/logstash/db/firehol_webserver.netset","/etc/logstash/db/firehol_webclient.netset","/etc/logstash/db/firehol_abusers_30d.netset","/etc/logstash/db/firehol_anonymous.netset","/etc/logstash/db/firehol_proxies.netset"]
152
+
153
+ #if field exist in event then no apply new value tag
154
+ config :noapply_sig_bl, :validate => :string, :default => "sig_no_apply_bl"
155
+
156
+ #interval to refresh conf new_value
157
+ config :refresh_interval_confbl, :validate => :number, :default => 3600
158
+
159
+ #field where add information on category detected
160
+ config :targetname_bl, :validate => :string, :default => "bl_detected_category"
161
+
162
+ ############### CONFIG SIG BASE ###################
163
+ #numeric test: R[1]['champs0']['numope']['egal'|'inf'|'sup'|'diff']=numeric_value
164
+ #format file SIG JSON example: {"rules":[{"field2":{"motif":["mot1","mot2"],"note":5, "name":"test", "type":1, "id": 1, "extract": {'field': 'ioc_field'}},"field3":{"false":{}},"field1":{"regexp":["/update\\\?id\=[-0-9A-Fa-f]{8}","/[0-9A-F]{8}/[0-9A-F]{8}/[0-9A-F]{8}"]}},{"fieldx6":{},"fieldx5":{},"fieldx4":{}}]}
165
+ #R[1]['champs0']['regexp']=[]
166
+ #R[1]['champs1']['notregexp']=[]
167
+ #R[1]['champs2']['motif']=[]
168
+ #R[1]['champs0']['date']['egal'|'inf'|'sup'|'diff']=x -> (time.now)-x ope value field
169
+ #R[1]['champs0']['hour']['egal'|'inf'|'sup'|'diff']=19 [interger]
170
+ #R[1]['champs0']['day']['egal'|'inf'|'sup'|'diff']=0 (0==sunday,1==monday,...) [Interger]
171
+ #R[1]['champs0']['ipaddr']['egal'|'diff']="192.168.0.0/24"
172
+ #R[1]['champs0']['sizeope']['egal'|'inf'|'sup'|'diff']=0
173
+ #R[1]['champs0']['numope']['egal'|'inf'|'sup'|'diff']=0
174
+ #R[1]['champs0']['compope']['champsX']['egal'|'inf'|'sup'|'diff'] => string(not sup & info for string)
175
+ #R[1]['champs3']['false']
176
+ #R[1]['champs3']['note'] = numeric, add one by rule/sig /* not importance for field use for note, juste one time */
177
+ #R[1]['champs3']['name'] = "SIG_DETECTED_TEST_01" /* not importance for field use for name, juste one time */
178
+ #R[1]['champs3']['type'] = 1 (primary sig -- defaut value) -- 2 (secondary sig -> add if only detect primary sig before)
179
+ #R[1]['champs3']['modeFP'] = true or false (true == delete & false or not present == detect)
180
+ #R[1]['champs3']['modeFP'] = true or false (true == delete & false or not present == detect)
181
+ # brute force & correlation sig add: "freq_field:" [field,field,field,field],"freq_delay":60s,freq_count: 3, freq_resettime: 3600s, correlate_change_fieldvalue: []
182
+ # use extract on sure alerte without false postive to add IOC in IOC check list in real time
183
+ # extract field value to insert in ioc_field; ex: extract: {'src_ip': 'ioc_ip', 'user_agent': 'ioc_user-agent'}
184
+ #order verify: FIELD, MOTIF, REGEXP
185
+ #At first detected sig, then stop search another sig!!!!
186
+ #File content rules signatures expression in json
187
+ config :conf_rules_sig, :validate => :path, :default => "/etc/logstash/db/sig.json"
188
+ config :file_save_localioc, :validate => :path, :default => "/etc/logstash/db/ioc_local.json"
189
+ #format json -- example:
190
+ #{"rules":[
191
+ # {"id":[22],"optid":[16,38],"opt_num":1,"noid":[],"note":3,"overwrite":true}
192
+ #]}
193
+ # id: list contains id of rules must present
194
+ # optid & opt_num: list contains if of rules can present with minimum of "opt_num" id present
195
+ # exemple: [16,38] with opt_num =1 then if 16 or 38 or (16 and 38) present is match
196
+ # noid: list id of rules must absent
197
+ # overwrite: if overwrite is true, it's significate than if note is more less then defined before, the value is overwrite and note is more less.
198
+ # note: it's value of new note for event match.
199
+ config :conf_rules_note, :validate => :path, :default => "/etc/logstash/db/note.json"
200
+
201
+ #Name of fields to save value if sig match: name sig, count
202
+ config :target_sig, :validate => :string, :default => "sig_detected"
203
+ config :targetnum_sig, :validate => :string, :default => "sig_detected_count"
204
+ config :targetname_sig, :validate => :string, :default => "sig_detected_name"
205
+ #Interval to refresh conf rules sig
206
+ config :refresh_interval_confrules, :validate => :number, :default => 3600
207
+
208
+ #if field exist in event then no apply rules check
209
+ config :noapply_sig_rules, :validate => :string, :default => "sig_no_apply_rules"
210
+
211
+ #stop check at one time find sig
212
+ config :check_stop, :validate => :boolean, :default => false
213
+
214
+ #LIST File content IOC - format json - exemple: {"ioc_as":["44050","55960","24961","203973"]}
215
+ config :db_ioc, :validate => :array, :default => ["/etc/logstash/db/ioc.json", "/etc/logstash/db/ioc_local.json"]
216
+ #Rules IOC Conf- format json - exemple get rules from list_field_ioc file: {"ioc_hostname":["_host"], "ioc_hostname_downcase":true, "ioc_hostname_iocnote":1, "ioc_hostname_iocid":1001}
217
+ # conf file significate for ioc_hostname search in value of field name containt string '_host'
218
+ # If ioc_hostname_downcase is true then force downcase value in field
219
+ # ioc_hostname_note give note to event if ioc match
220
+ # ioc_hostname_iocid: give id number to ioc, used in note_sig for change note by relation with another match (sig...).
221
+ # Ioc ID must be more than 1000 -> 1001..1999
222
+ config :conf_ioc, :validate => :path, :default => "/etc/logstash/db/ioc_conf.json"
223
+
224
+ #Name of fields to save value if ioc match: name ioc, count
225
+ config :target_ioc, :validate => :string, :default => "ioc_detected"
226
+ config :targetnum_ioc, :validate => :string, :default => "ioc_detected_count"
227
+ config :targetname_ioc, :validate => :string, :default => "ioc_detected_name"
228
+
229
+ #Name of field where save note of sig & ioc ...
230
+ config :targetnote, :validate => :string, :default => "sig_detected_note"
231
+ config :targetid, :validate => :string, :default => "sig_detected_id"
232
+
233
+ #Interval to refresh db ioc
234
+ config :refresh_interval_dbioc, :validate => :number, :default => 3600
235
+
236
+ #if field exist in event then no apply check ioc
237
+ config :noapply_ioc, :validate => :string, :default => "sig_no_apply_ioc"
238
+
239
+ ##ANOMALIE
240
+ #Conf ref -- format json -- PIVOT -> SIG -> REF
241
+ # rules[ {"pivot_field":[field1,field2], "list_sig": [fieldx,fieldy,...]} ]
242
+ #list_sig: all field used for sig, if all field not present, it doesn't matter, use field present in event and list_sig
243
+ config :conf_ref, :validate => :path, :default => "/etc/logstash/db/conf_ref.json"
244
+ #DB reference extract of ES by script
245
+ config :db_ref, :validate => :path, :default => "/etc/logstash/db/reference.json"
246
+ #RegExp DB FILE
247
+ config :db_pattern, :validate => :path, :default => "/etc/logstash/db/pattern.db"
248
+ #Interval to refresh db reference
249
+ config :refresh_interval_dbref, :validate => :number, :default => 3600
250
+ #if field exist in event then no apply check ref
251
+ config :noapply_ref, :validate => :string, :default => "sig_no_apply_ref"
252
+ #Name of fields to save value if ref match: name ioc, count
253
+ config :target_ref, :validate => :string, :default => "ref_detected"
254
+ config :targetnum_ref, :validate => :string, :default => "ref_detected_count"
255
+ config :targetname_ref, :validate => :string, :default => "ref_detected_name"
256
+ config :ref_aroundfloat, :default => 0.5 # TODO :validate => :float
257
+ config :ref_stop_after_firstffind, :validate => :boolean, :default => true
258
+ #pivot 1 syslog_programm -> add in ref.json for add multi profil
259
+ #config :sg_extract, :validate => :string, :default => "syslog_program"
260
+ #pivot 2 syslog_pri -> add in ref.json for add multi profil
261
+ #config :spri_extract, :validate => :string, :default => "syslog_pri"
262
+ #exclude field for create sig -> add field list for create sig and add in ref.json
263
+ #config :exclude_create_sig, :validate => :array, :default => ["tags","@source_host","_type","type","@timestamp","@message","@version","_id","_index","_type","host","message","received_at","received_from","syslog_facility","syslog_facility_code","syslog_pri","syslog_pid","syslog_program","syslog_severity_code","syslog_severity"]
264
+
265
+ ##FREQUENCE
266
+ #rules_freq = [ {'select_field': {'fieldx':[value_list],'fieldy':[value_list]}, 'note': X, 'refresh_time': Xseconds,'reset_time': Xseconds[1j], 'reset_hour': '00:00:00', 'wait_after_reset': 10, 'id': 30XXX},...]
267
+ config :conf_freq, :validate => :path, :default => "/etc/logstash/db/conf_freq.json"
268
+ #Interval to refresh rules frequence
269
+ config :refresh_interval_freqrules, :validate => :number, :default => 3600
270
+ #if field exist in event then no apply check freq
271
+ config :noapply_freq, :validate => :string, :default => "sig_no_apply_freq"
272
+ #rules_freq = [ {'select_field': {'fieldx':[value_list],'fieldy':[value_list]}, 'note': X, 'refresh_time': Xseconds,'reset_time': Xseconds[1j], 'reset_hour': '00:00:00', 'wait_after_reset': 10, 'id': 30XXX},...]
273
+ #select field for select => first filter
274
+ #select field value => second filter
275
+ #refresh_time for check and calculate all time result: max & variation
276
+ # note if match
277
+ # reset time in second for reset all counter value
278
+ # reset hour for begin reset with hour => use for 24h reset begin at 00:00
279
+ # wait_after_reset: dont't check before 10 times values
280
+ #db_freq = { '30XXX': {'refresh_date': date, 'old_date': date,'num_time': Xtimes, 'V_prev': x/m, 'Varia_avg': z/m, 'count_prev': Xtimes, 'count_cour': Xtimes, 'V_max': x/m, 'Varia_max': x/m, 'Varia_min': +/- x/m, 'Varia_glob': x/m}}
281
+ #check refresh db ref
282
+ public
283
+ def register
284
+ @logger.info("Plugin SIG. Loading conf...")
285
+ #create var extract file db & conf
286
+ @ioc_db = {}
287
+ @ioc_db_local = JSON.parse( IO.read(@file_save_localioc, encoding:'utf-8') ) unless @disable_sig and @disable_ioc #use on sig extract
288
+ @ioc_rules = {}
289
+ @note_db = []
290
+ @sig_db = {}
291
+ @sig_db_array = []
292
+ @sig_db_array_false = []
293
+ @sig_db_array_len = 0
294
+ @nv_db = JSON.parse( IO.read(@db_nv, encoding:'utf-8') ) unless @disable_nv
295
+ @nv_rules = {}
296
+ @fp_rules = {}
297
+ @fp_db = {}
298
+ @drop_db = {}
299
+ @fingerprint_db = {} #temporary db
300
+ @ref_db = {}
301
+ @pattern_db = {}
302
+ @ref_rules = {}
303
+ @freq_rules = {}
304
+ @db_freq = {}
305
+ @bl_db = {} # {file_name:[IP]}
306
+ @bl_rules = {}
307
+ @db_enr = {}
308
+ ###
309
+ ###special DB
310
+ @sig_db_freq = {}
311
+ ###
312
+ #hash file
313
+ @hash_conf_rules_sig = ""
314
+ @hash_conf_rules_note = ""
315
+ @hash_conf_freq = ""
316
+ @hash_conf_fp = ""
317
+ @hash_conf_nv = ""
318
+ @hash_conf_bl = ""
319
+ @hash_dbbl = {}
320
+ @hash_dbioc = {}
321
+ @hash_conf_ioc = ""
322
+ @hash_dbref = ""
323
+ @hash_dbpattern = ""
324
+ @hash_conf_ref = ""
325
+ @hash_dropdb = ""
326
+ @hash_dropfp = ""
327
+ @hash_conf_enr = ""
328
+ @hash_dbfile_enr = {}
329
+ @hash_db_enr = {}
330
+ ###
331
+ #load conf & db
332
+ @load_statut = false
333
+ load_conf_rules_sig unless @disable_sig
334
+ load_conf_rules_note unless @disable_sig and @disable_ioc and @disable_ref
335
+ load_conf_fp unless @disable_fp
336
+ load_conf_nv unless @disable_nv
337
+ load_conf_ioc unless @disable_ioc
338
+ load_conf_bl unless @disable_bl
339
+ load_db_ioc unless @disable_ioc
340
+ load_db_drop unless @disable_drop
341
+ load_db_dropfp unless @disable_fp
342
+ load_db_pattern unless @disable_ref
343
+ load_db_ref unless @disable_ref
344
+ load_rules_freq unless @disable_freq
345
+ load_db_enr unless @disable_enr
346
+ @load_statut = true
347
+ @load_statut_rules = true
348
+ @load_statut_fp = true
349
+ @load_statut_nv = true
350
+ @load_statut_bl = true
351
+ @save_statut_nv = true
352
+ @load_statut_ioc = true
353
+ @load_statut_ref = true
354
+ @load_statut_drop = true
355
+ @load_statut_freqrules = true
356
+ @load_statut_note = true
357
+ @load_statut_enr = true
358
+ ###
359
+ @logger.info("finish")
360
+ #next refresh file
361
+ tnow = Time.now
362
+ @next_refresh_dbref = tnow + @refresh_interval_dbref
363
+ @next_refresh_dbioc = tnow + @refresh_interval_dbioc
364
+ @next_refresh_confrules = tnow + @refresh_interval_confrules
365
+ @next_refresh_confnv = tnow + @refresh_interval_confnv
366
+ @next_refresh_confbl = tnow + @refresh_interval_confbl
367
+ @next_refresh_dbnv = tnow + @save_interval_dbnv
368
+ @next_refresh_dropdb = tnow + @refresh_interval_dropdb
369
+ @next_refresh_conffp = tnow + @refresh_interval_conffp
370
+ @next_refresh_note = tnow + @refresh_interval_confrules
371
+ @next_refresh_freqrules = tnow + @refresh_interval_freqrules
372
+ @next_refresh_enr = tnow + @refresh_interval_enr
373
+ ###
374
+ end # def register
375
+
376
+ public
377
+ def filter(event)
378
+ return unless filter?(event)
379
+ #check field no_check if present stop search
380
+ return unless event.get(@no_check).nil?
381
+ #get time for refresh
382
+ tnow = Time.now
383
+
384
+ ######DROP FIRST DB USE######
385
+ #refresh db
386
+ unless @disable_drop
387
+ if @next_refresh_dropdb < tnow
388
+ if @load_statut_drop == true
389
+ @load_statut_drop = false
390
+ load_db_drop
391
+ @next_refresh_dropdb = tnow + @refresh_interval_dropdb
392
+ @load_statut_drop = true
393
+ end
394
+ end
395
+ sleep(1) until @load_statut_drop
396
+ end
397
+ #check if db not empty
398
+ if not @drop_db.empty? and event.get(@noapply_sig_dropdb).nil? and not @disable_drop
399
+ @drop_db.each do |dkey,dval|
400
+ #search field with name of dkey
401
+ if not event.get(dkey).nil? and event.get(dkey).is_a?(String) and not dval.empty? and event.get(dkey) =~ /#{dval}/
402
+ #key exist and match with regexp
403
+ event.cancel
404
+ return
405
+ end
406
+ end
407
+ end
408
+ #######################
409
+
410
+ ######ENRICHISSEMENT: add info db local, active info, ...######
411
+ #{"1": {file: path_db, db: {loaded by path db contains hash},"prefix": "prefix_...", filters: {field:regexp,...}, link: [["name_field_select_value_to_search_in_db",...],[WHOIS2,...]], "form_in_db": "https://$1$:$2$", if_empty: 'WHOIS'}, "filter_insert": [], "filter_noinsert": []}
412
+ # in db {'value_field_link': {name_info1: info1, name_info2: info2, ...}}
413
+ #probleme sur link lié a la construction d'un nom dans la base par exemple https://host:port (3 fields)
414
+ #2 eme cas quand l'on veut faire un whois sur plusieurs field: champs1 et champs2
415
+ #create var for add new field name (for check drop)
416
+ #choose order for link by enrichissment ex: infoclient -> IP (get MAC by db ip2mac) and second time get info by mac
417
+ new_field_enr = []
418
+ #refresh db
419
+ unless @disable_enr
420
+ if @next_refresh_enr < tnow
421
+ if @load_statut_enr == true
422
+ @load_statut_enr = false
423
+ save_dbs_enr # save db with news data response -TODO -> 1 verify if db change (md5 hash) if no change save, if change... create diff with save!
424
+ #load_db_enr #load - use save for load too
425
+ @next_refresh_enr = tnow + @refresh_interval_enr
426
+ @load_statut_enr = true
427
+ end
428
+ end
429
+ sleep(1) until @load_statut_enr
430
+ end
431
+ #check if db is not empty
432
+ if not @db_enr.empty? and event.get(@noapply_sig_enr).nil? and not @disable_enr
433
+ if event.get(@field_enr).is_a?(Array)
434
+ #check response by response
435
+ for respo in event.get(@field_enr)
436
+ respo.each do |rkey,rval| #{rval['if_empty'] => {"id": rkey.to_s, "field": lval.to_s}}
437
+ next if rval['id'].nil? or rval['field'].nil? or rval['name_in_db'].nil? or rval['response'].nil? or @db_enr[rval['id'].to_s].nil?
438
+ #add in event
439
+ rval['response'].each do |xk,xval|
440
+ next if xval.empty? or @db_enr[rval['id'].to_s]["filter_noinsert"].include?(xk) or (not @db_enr[rval['id'].to_s]["filter_insert"].include?(xk) and not @db_enr[rval['id'].to_s]["filter_insert"].empty? and @db_enr[rval['id'].to_s]["filter_noinsert"].empty?)
441
+ #!!! overwrite if exist!!!
442
+ event.set(@db_enr[rval['id'].to_s]['prefix'].to_s+xk.to_s,xval)
443
+ #add in "FIELD_TEMP_ENR_DROP_NEW"
444
+ if event.get("FIELD_TEMP_ENR_DROP_NEW").nil?
445
+ event.set("FIELD_TEMP_ENR_DROP_NEW",[(@db_enr[rval['id'].to_s]['prefix'].to_s+xk.to_s)])
446
+ else
447
+ event.set("FIELD_TEMP_ENR_DROP_NEW",event.get("FIELD_TEMP_ENR_DROP_NEW")+[(@db_enr[rval['id'].to_s]['prefix'].to_s+xk.to_s)])
448
+ end
449
+ end
450
+ #add info in db
451
+ if rval['name_in_db'].empty? and rval['response'].is_a?(Hash) and not rval['response'].empty?
452
+ @db_enr[rval['id'].to_s]['db'][rval['name_in_db'].to_s] = rval['response']
453
+ end
454
+ end
455
+ end
456
+ #clean event
457
+ event.remove(@field_enr)
458
+ else
459
+ #check rule by rule
460
+ eventK = event.to_hash.keys
461
+ @db_enr.each do |rkey,rval|
462
+ # rule by rule
463
+ #check filter
464
+ #chekc is all keys present in event
465
+ inter = rval['filters'].keys & eventK
466
+ #check if fields rule present in event
467
+ if inter.length == rval['filters'].keys.length
468
+ #field present
469
+ #check filed by field
470
+ sig_add = {}
471
+ check_sig=false
472
+ for kfield in inter
473
+ check_sig=false
474
+ # field X -- check type
475
+ if event.get(kfield).is_a?(Array)
476
+ #array type
477
+ # if rule value regexp is Array?
478
+ if rval['filters'][kfield].is_a?(Array)
479
+ for regexp in rval['filters'][kfield]
480
+ check_sig=false
481
+ for elem in event.get(kfield)
482
+ match = Regexp.new(regexp, nil, 'n').match(elem.to_s)
483
+ if not match.nil?
484
+ check_sig=true
485
+ break
486
+ end
487
+ end
488
+ break unless check_sig
489
+ end
490
+ else
491
+ #rule not array
492
+ for elem in event.get(kfield)
493
+ match = Regexp.new(rval['filters'][kfield], nil, 'n').match(elem.to_s)
494
+ if not match.nil?
495
+ check_sig=true
496
+ break
497
+ end
498
+ end
499
+ end
500
+ else
501
+ #other type
502
+ # if rule value regexp is Array?
503
+ if rval['filters'][kfield].is_a?(Array)
504
+ #array
505
+ for regexp in rval['filters'][kfield]
506
+ match = Regexp.new(regexp, nil, 'n').match(event.get(kfield).to_s)
507
+ if not match.nil?
508
+ sig_add[kfield.to_s]="Regexp found #{match}"
509
+ check_sig=true
510
+ next
511
+ end
512
+ break unless check_sig
513
+ end
514
+ else
515
+ #other
516
+ match = Regexp.new(rval['filters'][kfield], nil, 'n').match(event.get(kfield).to_s)
517
+ if not match.nil?
518
+ check_sig=true
519
+ next
520
+ end
521
+ end
522
+ end
523
+ break unless check_sig
524
+ end
525
+ #check if filters match
526
+ if check_sig
527
+ #matched
528
+ #check if link present in event & db & link not empty
529
+ next if rval['link'].empty?
530
+ next if rval['form_in_db'].empty?
531
+ lkey=rval['form_in_db'].dup
532
+ pnext=false
533
+ cnt_e=0
534
+ for lval in rval['link']
535
+ cnt_e+=1
536
+ if event.get(lval.to_s).nil?
537
+ pnext=true
538
+ break
539
+ else
540
+ #create dbkey
541
+ lkey.gsub! '$'+cnt_e.to_s+'$', event.get(lval.to_s)
542
+ end
543
+ end
544
+ next if pnext
545
+ next if cnt_e != rval['link'].length or lkey =~ /\$\d+\$/
546
+ if not rval['db'][lkey.to_s].is_a?(Hash)
547
+ #if not present and must present, then send to server active enrichissement and wait to return
548
+ #check if if_empty exist?
549
+ if rval['if_empty'].is_a?(String) and not rval['if_empty'].empty?
550
+ #send requets to server for resolve information
551
+ #Add field request_resolv: [{WHOIS: {"id": id_rule, "field": field_name}},{SSL: {"id": id_rule, "field": field_name}}]
552
+ #TODO verify number of element in form and link
553
+ request_enr = {rval['if_empty'] => {"id" => rkey.to_s, "field" => rval['link'], "name_in_db" => lkey}}
554
+ if event.get(@field_enr).nil?
555
+ event.set(@field_enr,[request_enr])
556
+ else
557
+ event.set(@field_enr,event.get(@field_enr)+[request_enr])
558
+ end
559
+ #send to server (at end, for possible add multi request by rule
560
+ end
561
+ else
562
+ #if present add
563
+ next if not rval['prefix'].is_a?(String) or rval['prefix'].empty?
564
+ #"filter_insert": [], "filter_noinsert": []
565
+ rval['db'][lkey].each do |xk,xval|
566
+ next if xval.empty? or rval["filter_noinsert"].include?(xk) or (not rval["filter_insert"].include?(xk) and not rval["filter_insert"].empty? and rval["filter_noinsert"].empty?)
567
+ #!!! overwrite if exist!!!
568
+ event.set(rval['prefix'].to_s+xk.to_s,xval)
569
+ #add in new_field_enr
570
+ new_field_enr.push(*(rval['prefix'].to_s+xk.to_s))
571
+ end
572
+ end
573
+ end
574
+ end
575
+ end
576
+ event.tag(@enr_tag_response) if not event.get(@field_enr).nil?
577
+ event.set("FIELD_TEMP_ENR_DROP_NEW",new_field_enr)
578
+ #when event.get(@field_enr) is set hten not check apply on event, in configuration add to send to server enrichment which resend after add informations
579
+ end
580
+ end
581
+ #######################
582
+
583
+ ######DROP SECOND######
584
+ ## JUST CHECK NEW FIELD (created by enr)
585
+ #check if db not empty
586
+ if not @drop_db.empty? and event.get(@noapply_sig_dropdb).nil? and not @disable_drop and event.get(@field_enr).nil? and not event.get("FIELD_TEMP_ENR_DROP_NEW").nil?
587
+ for nfield in event.get("FIELD_TEMP_ENR_DROP_NEW")
588
+ if @drop_db[nfield] and event.get(nfield).is_a?(String) and event.get(nfield) =~ /#{@drop_db[nfield]}/
589
+ #key exist and match with regexp
590
+ event.cancel
591
+ return
592
+ end
593
+ end
594
+ end
595
+ event.remove("FIELD_TEMP_ENR_DROP_NEW")
596
+ #######################
597
+
598
+ ######New Value USE######
599
+ #reshresh conf & save db
600
+ unless @disable_nv
601
+ if @next_refresh_dbnv < tnow
602
+ if @save_statut_nv == true
603
+ @save_statut_nv = false
604
+ save_db_nv
605
+ @next_refresh_dbnv = tnow + @save_interval_dbnv
606
+ @save_statut_nv = true
607
+ end
608
+ end
609
+ if @next_refresh_confnv < tnow
610
+ if @load_statut_nv == true
611
+ @load_statut_nv = false
612
+ load_conf_nv
613
+ @next_refresh_confnv = tnow + @refresh_interval_confnv
614
+ @load_statut_nv = true
615
+ end
616
+ end
617
+ sleep(1) until @load_statut_nv
618
+ end
619
+ #check if db &conf are not empty + select_fp exist
620
+ if not @nv_rules.empty? and @nv_rules['rules'].is_a?(Array) and not @nv_db.empty? and event.get(@noapply_sig_nv).nil? and not @disable_nv and event.get(@field_enr).nil?
621
+ #check all rules
622
+ for rule in @nv_rules['rules']
623
+ #if rule exist in event?
624
+ if event.get(rule.to_s)
625
+ #yes
626
+ #event content type Array
627
+ if event.get(rule.to_s).is_a?(Array)
628
+ for elem in event.get(rule.to_s)
629
+ if elem.is_a?(String) or elem.is_a?(Numeric)
630
+ if not @nv_db[rule.to_s].include?(elem)
631
+ #new value => add
632
+ @nv_db[rule.to_s].push(*elem)
633
+ event.set(@target_nv+rule.to_s, elem.to_s)
634
+ end
635
+ end
636
+ end
637
+ #event content type String or Numeric
638
+ elsif event.get(rule.to_s).is_a?(String) or event.get(rule.to_s).is_a?(Numeric)
639
+ if not @nv_db[rule.to_s].include?(event.get(rule.to_s))
640
+ #new value => add
641
+ @nv_db[rule.to_s].push(*event.get(rule.to_s))
642
+ event.set(@target_nv+rule.to_s, event.get(rule.to_s).to_s)
643
+ end
644
+ end
645
+ end
646
+ end
647
+ end
648
+ #########################
649
+
650
+ ######BL REPUTATION USE######
651
+ #reshresh conf & save db
652
+ unless @disable_bl
653
+ if @next_refresh_confbl < tnow
654
+ if @load_statut_bl == true
655
+ @load_statut_bl = false
656
+ load_conf_bl
657
+ @next_refresh_confbl = tnow + @refresh_interval_confbl
658
+ @load_statut_bl = true
659
+ end
660
+ end
661
+ sleep(1) until @load_statut_bl
662
+ end
663
+ #check if db &conf are not empty + select_fp exist
664
+ if not @bl_rules.empty? and not @bl_db.empty? and event.get(@noapply_sig_bl).nil? and not @disable_bl and event.get(@field_enr).nil?
665
+ #bl_rules: {fieldx: {dbs: [file_name,...], category: , note: X, id: X}}
666
+ #bl_db: {file_name: [IPs]}
667
+ #rule by rule
668
+ @bl_rules.each do |fkey,fval|
669
+ #veirfy field exist
670
+ if not event.get(fkey).nil?
671
+ #verify field contains IP
672
+ ip = ""
673
+ next if not ip = IPAddr.new(event.get(fkey).to_s) rescue false
674
+ for dbbl in fval['dbs']
675
+ #if @bl_db[dbbl].include?(ip)
676
+ if @bl_db[dbbl].any?{|block| block === ip}
677
+ #FIELD FIND IN DB BL REPUTATION
678
+ #ADD SCORE & ID & CAT
679
+ unless event.get(@targetnote).nil?
680
+ if event.get(@targetnote) < fval['note']
681
+ event.set(@targetnote, detected_sig_note)
682
+ end
683
+ else
684
+ event.set(@targetnote, fval['note'])
685
+ end
686
+ unless event.get(@targetname_bl).nil?
687
+ event.set(@targetname_bl, event.get(@targetname_bl) + [fval['category']])
688
+ else
689
+ event.set(@targetname_bl, [fval['category']])
690
+ end
691
+ unless event.get(@targetid).nil?
692
+ event.set(@targetid, event.get(@targetid) + [fval['id']])
693
+ else
694
+ event.set(@targetid, [fval['id']])
695
+ end
696
+ end
697
+ end
698
+ end
699
+ end
700
+ end
701
+ #########################
702
+
703
+ ######IOC SEARCH######
704
+ #refresh db
705
+ unless @disable_ioc
706
+ if @next_refresh_dbioc < tnow
707
+ if @load_statut_ioc == true
708
+ @load_statut_ioc = false
709
+ load_conf_ioc
710
+ load_db_ioc
711
+ @next_refresh_dbioc = tnow + @refresh_interval_dbioc
712
+ @load_statut_ioc = true
713
+ end
714
+ end
715
+ sleep(1) until @load_statut_ioc
716
+ end
717
+ #check db not empty
718
+ if not @ioc_rules.empty? and not @ioc_db.empty? and event.get(@noapply_ioc).nil? and not @disable_ioc and event.get(@field_enr).nil?
719
+ detected_ioc = Array.new
720
+ detected_ioc_count = 0
721
+ detected_ioc_name = Array.new
722
+ detected_ioc_id = Array.new
723
+ detected_ioc_note = 0
724
+ #verify ioc by rules
725
+ @ioc_rules.each do |rkey,rval|
726
+ #rule by rule
727
+ if rval.is_a?(Array) and not rkey =~ /_downcase$|_iocnote$|_iocid$/ and @ioc_db[rkey.to_s]
728
+ list_search = []
729
+ #create list value by rule to check ioc
730
+ for elemvalue in rval
731
+ #Collect value of field name contains "elemvalue"
732
+ hash_tmp = event.to_hash.select{|k,v| (k.to_s).include? elemvalue }
733
+ if hash_tmp.values.any?
734
+ #hash not empty
735
+ if list_search.empty?
736
+ if @ioc_rules[rkey+'_downcase']
737
+ #case compare by downcase
738
+ list_search = hash_tmp.values.map!(&:downcase)
739
+ else
740
+ #case normaly compare
741
+ list_search = hash_tmp.values
742
+ end
743
+ else
744
+ if @ioc_rules[rkey+'_downcase']
745
+ #case compare by downcase
746
+ list_search = list_search + hash_tmp.values.map!(&:downcase)
747
+ else
748
+ #case normaly compare
749
+ list_search = list_search + hash_tmp.values
750
+ end
751
+ end
752
+ end
753
+ end
754
+ #compare list_value extract of event for one case of ioc and db_ioc -- intersection
755
+ inter=list_search & @ioc_db[rkey.to_s]
756
+ if inter.any?
757
+ #value(s) find
758
+ ioc_add = {rkey.to_s => inter}
759
+ detected_ioc_name.push(*rkey.to_s)
760
+ detected_ioc.push(*ioc_add)
761
+ detected_ioc_count = detected_ioc_count + 1
762
+ detected_ioc_id.push(*@ioc_rules[rkey+'_iocid'])
763
+ if detected_ioc_note < @ioc_rules[rkey+'_iocnote']
764
+ detected_ioc_note = @ioc_rules[rkey+'_iocnote']
765
+ end
766
+ ioc_add.clear
767
+ end
768
+ end
769
+ end
770
+ #check if ioc find
771
+ if detected_ioc.any?
772
+ #ioc find, add information in event (count, name, id, note)
773
+ unless event.get(@target_ioc).nil?
774
+ event.set(@target_ioc, event.get(@target_ioc) + detected_ioc)
775
+ else
776
+ event.set(@target_ioc, detected_ioc)
777
+ end
778
+ unless event.get(@targetnum_ioc).nil?
779
+ event.set(@targetnum_ioc, event.get(@targetnum_ioc) + detected_ioc_count)
780
+ else
781
+ event.set(@targetnum_ioc, detected_ioc_count)
782
+ end
783
+ unless event.get(@targetname_ioc).nil?
784
+ event.set(@targetname_ioc, event.get(@targetname_ioc) + detected_ioc_name)
785
+ else
786
+ event.set(@targetname_ioc, detected_ioc_name)
787
+ end
788
+ unless event.get(@targetid).nil?
789
+ event.set(@targetid, event.get(@targetid) + detected_ioc_id)
790
+ else
791
+ event.set(@targetid, detected_ioc_id)
792
+ end
793
+ unless event.get(@targetnote).nil?
794
+ if event.get(@targetnote) < detected_ioc_note
795
+ event.set(@targetnote, detected_ioc_note)
796
+ end
797
+ else
798
+ event.set(@targetnote, detected_ioc_note)
799
+ end
800
+ end
801
+ end
802
+ ######################
803
+
804
+ ######SIG SEARCH######
805
+ unless @disable_sig
806
+ if @next_refresh_confrules < tnow
807
+ if @load_statut_rules == true
808
+ @load_statut_rules = false
809
+ load_conf_rules_sig
810
+ save_db_ioclocal
811
+ clean_db_sigfreq(tnow)
812
+ @next_refresh_confrules = tnow + @refresh_interval_confrules
813
+ @load_statut_rules = true
814
+ end
815
+ end
816
+ sleep(1) until @load_statut_rules
817
+ end
818
+ if not @sig_db.empty? and event.get(@noapply_sig_rules).nil? and not @disable_sig and event.get(@field_enr).nil?
819
+ #create var local for all rules check
820
+ detected_sig = Array.new
821
+ detected_sig_name = Array.new
822
+ detected_sig_count = 0
823
+ detected_sig_note = 0
824
+ detected_sig_id = Array.new
825
+ detected_sig_id_corre = Array.new
826
+ type_sig = 0
827
+ type_obl = 0
828
+ # get list of all name field present in event
829
+ eventK = event.to_hash.keys
830
+ #check all rules
831
+ (0..@sig_db_array_len).each do |i|
832
+ #verify exist field used in rule
833
+ verif=@sig_db_array[i].length
834
+ inter=@sig_db_array[i] & eventK
835
+ if inter.length == verif
836
+ #OK all field rule are present
837
+ #verify if field name exclude by rule are present
838
+ inter=@sig_db_array_false[i] & eventK
839
+ if inter.length == 0
840
+ #OK exclude field are not present in event
841
+ #create variable local by rule
842
+ validfield=0
843
+ #length of field check contains in rule
844
+ countfield=@sig_db_array[i].length
845
+ sig_add = {"Rules" => "Detected rule at emplacement: #{i} (not id)"}
846
+ sig_add["note"] = 0
847
+ #check rule field by field in event
848
+ for kfield in @sig_db_array[i]
849
+ #CHECK SIG BY FIELD BEGIN
850
+ #check_sig used for know if check result step by step for break if not match rules
851
+ check_sig=true
852
+ #BEGIN : CHECK BY MOTIF
853
+ unless @sig_db['rules'][i][kfield]['motif'].nil?
854
+ check_sig=false
855
+ if event.get(kfield).is_a?(Array)
856
+ l_tmp = event.get(kfield).flatten(10)
857
+ inter = l_tmp & @sig_db['rules'][i][kfield]['motif']
858
+ if inter.length != 0
859
+ sig_add[kfield.to_s]="motif found: #{inter}"
860
+ check_sig=true
861
+ end
862
+ elsif @sig_db['rules'][i][kfield]['motif'].include? event.get(kfield)
863
+ sig_add[kfield.to_s]="motif found #{event.get(kfield)}"
864
+ check_sig=true
865
+ end
866
+ end
867
+ break if check_sig == false
868
+ #END : CHECK BY MOTIF
869
+ #BEGIN : CHECK BY Compare value of two fields
870
+ unless @sig_db['rules'][i][kfield]['compope'].nil?
871
+ @sig_db['rules'][i][kfield]['compope'].each do |xk,xval|
872
+ if event.get(xk)
873
+ if event.get(xk).is_a?(Numeric)
874
+ unless @sig_db['rules'][i][kfield]['compope'][xk].nil?
875
+ if event.get(kfield).is_a?(Numeric)
876
+ unless @sig_db['rules'][i][kfield]['compope'][xk]['egal'].nil?
877
+ check_sig=false
878
+ if event.get(kfield) == event.get(xk)
879
+ sig_add[kfield.to_s]="Fields Value numeric #{event.get(kfield)} == #{event.get(xk)} found"
880
+ check_sig=true
881
+ end
882
+ end
883
+ break if check_sig == false
884
+ unless @sig_db['rules'][i][kfield]['compope'][xk]['sup'].nil?
885
+ check_sig=false
886
+ if event.get(kfield) > event.get(xk)
887
+ sig_add[kfield.to_s]="Fields Value numeric #{event.get(kfield)} > #{event.get(xk)} found"
888
+ check_sig=true
889
+ end
890
+ end
891
+ break if check_sig == false
892
+ unless @sig_db['rules'][i][kfield]['compope'][xk]['inf'].nil?
893
+ check_sig=false
894
+ if event.get(kfield) < event.get(xk)
895
+ sig_add[kfield.to_s]="Fields Value numeric #{event.get(kfield)} < #{event.get(xk)} found"
896
+ check_sig=true
897
+ end
898
+ end
899
+ break if check_sig == false
900
+ unless @sig_db['rules'][i][kfield]['compope'][xk]['diff'].nil?
901
+ check_sig=false
902
+ if event.get(kfield) != event.get(xk)
903
+ sig_add[kfield.to_s]="Fields Value numeric #{event.get(kfield)} != #{event.get(xk)} found"
904
+ check_sig=true
905
+ end
906
+ end
907
+ break if check_sig == false
908
+ end
909
+ end
910
+ elsif event.get(xk).is_a?(String)
911
+ unless @sig_db['rules'][i][kfield]['compope'][xk].nil?
912
+ if event.get(kfield).is_a?(String)
913
+ unless @sig_db['rules'][i][kfield]['compope'][xk]['egal'].nil?
914
+ check_sig=false
915
+ if event.get(kfield).eql?(event.get(xk))
916
+ sig_add[kfield.to_s]="Fields Value String #{event.get(kfield)} == #{event.get(xk)} found"
917
+ check_sig=true
918
+ end
919
+ end
920
+ break if check_sig == false
921
+ unless @sig_db['rules'][i][kfield]['compope'][xk]['diff'].nil?
922
+ check_sig=false
923
+ if not event.get(kfield).eql?(event.get(xk))
924
+ sig_add[kfield.to_s]="Fields Value String #{event.get(kfield)} != #{event.get(xk)} found"
925
+ check_sig=true
926
+ end
927
+ end
928
+ break if check_sig == false
929
+ end
930
+ end
931
+ #add elsif event.get(kfield).is_a?(Array) ?
932
+ end
933
+ end
934
+ end
935
+ end
936
+ break if check_sig == false
937
+ #END : CHECK BY Compare value of two fields
938
+ #BEGIN : CHECK BY numeric operation
939
+ unless @sig_db['rules'][i][kfield]['numope'].nil?
940
+ if event.get(kfield).is_a?(Numeric)
941
+ unless @sig_db['rules'][i][kfield]['numope']['egal'].nil?
942
+ check_sig=false
943
+ if event.get(kfield) == @sig_db['rules'][i][kfield]['numope']['egal']
944
+ sig_add[kfield.to_s]="Value numeric #{event.get(kfield)} == #{@sig_db['rules'][i][kfield]['numope']['egal']} found"
945
+ check_sig=true
946
+ end
947
+ end
948
+ break if check_sig == false
949
+ unless @sig_db['rules'][i][kfield]['numope']['sup'].nil?
950
+ check_sig=false
951
+ if event.get(kfield) > @sig_db['rules'][i][kfield]['numope']['sup']
952
+ sig_add[kfield.to_s]="Value numeric #{event.get(kfield)} > #{@sig_db['rules'][i][kfield]['numope']['sup']} found"
953
+ check_sig=true
954
+ end
955
+ end
956
+ break if check_sig == false
957
+ unless @sig_db['rules'][i][kfield]['numope']['inf'].nil?
958
+ check_sig=false
959
+ if event.get(kfield) < @sig_db['rules'][i][kfield]['numope']['inf']
960
+ sig_add[kfield.to_s]="Value numeric #{event.get(kfield)} < #{@sig_db['rules'][i][kfield]['numope']['inf']} found"
961
+ check_sig=true
962
+ end
963
+ end
964
+ break if check_sig == false
965
+ unless @sig_db['rules'][i][kfield]['numope']['diff'].nil?
966
+ check_sig=false
967
+ if event.get(kfield) != @sig_db['rules'][i][kfield]['numope']['diff']
968
+ sig_add[kfield.to_s]="Value numeric #{event.get(kfield)} != #{@sig_db['rules'][i][kfield]['numope']['diff']} found"
969
+ check_sig=true
970
+ end
971
+ end
972
+ break if check_sig == false
973
+ end
974
+ end
975
+ #END : CHECK BY numeric operation
976
+ #BEGIN : CHECK BY date
977
+ unless @sig_db['rules'][i][kfield]['date'].nil?
978
+ if event.get(kfield).is_a?(String) and not event.get(kfield).nil? and event.get(kfield).length > 0
979
+ unless @sig_db['rules'][i][kfield]['date']['egal'].nil?
980
+ check_sig=false
981
+ if Time.parse(event.get(kfield)) == (tnow - @sig_db['rules'][i][kfield]['date']['egal'])
982
+ sig_add[kfield.to_s]="Value date #{event.get(kfield)} == #{@sig_db['rules'][i][kfield]['date']['egal']} found"
983
+ check_sig=true
984
+ end
985
+ end
986
+ break if check_sig == false
987
+ unless @sig_db['rules'][i][kfield]['date']['sup'].nil?
988
+ check_sig=false
989
+ if Time.parse(event.get(kfield)) > (tnow - @sig_db['rules'][i][kfield]['date']['sup'])
990
+ sig_add[kfield.to_s]="Value date #{event.get(kfield)} > #{@sig_db['rules'][i][kfield]['date']['sup']} found"
991
+ check_sig=true
992
+ end
993
+ end
994
+ break if check_sig == false
995
+ unless @sig_db['rules'][i][kfield]['date']['inf'].nil?
996
+ check_sig=false
997
+ if Time.parse(event.get(kfield)) < (tnow - @sig_db['rules'][i][kfield]['date']['inf'])
998
+ sig_add[kfield.to_s]="Value date #{event.get(kfield)} < #{@sig_db['rules'][i][kfield]['date']['inf']} found"
999
+ check_sig=true
1000
+ end
1001
+ end
1002
+ break if check_sig == false
1003
+ unless @sig_db['rules'][i][kfield]['date']['diff'].nil?
1004
+ check_sig=false
1005
+ if Time.parse(event.get(kfield)) != (tnow - @sig_db['rules'][i][kfield]['date']['diff'])
1006
+ sig_add[kfield.to_s]="Value date #{event.get(kfield)} != #{@sig_db['rules'][i][kfield]['date']['diff']} found"
1007
+ check_sig=true
1008
+ end
1009
+ end
1010
+ break if check_sig == false
1011
+ elsif event.get(kfield).is_a?(Array) and not event.get(kfield).nil? and event.get(kfield).length > 0
1012
+ for elem_list in event.get(kfield)
1013
+ if elem_list.is_a?(String)
1014
+ unless @sig_db['rules'][i][kfield]['date']['egal'].nil?
1015
+ check_sig=false
1016
+ if Time.parse(elem_list) == (tnow - @sig_db['rules'][i][kfield]['date']['egal'])
1017
+ sig_add[kfield.to_s]="Value date #{event.get(kfield)} == #{@sig_db['rules'][i][kfield]['date']['egal']} found"
1018
+ check_sig=true
1019
+ end
1020
+ end
1021
+ break if check_sig == false
1022
+ unless @sig_db['rules'][i][kfield]['date']['sup'].nil?
1023
+ check_sig=false
1024
+ if Time.parse(elem_list) > (tnow - @sig_db['rules'][i][kfield]['date']['sup'])
1025
+ sig_add[kfield.to_s]="Value date #{event.get(kfield)} > #{@sig_db['rules'][i][kfield]['date']['sup']} found"
1026
+ check_sig=true
1027
+ end
1028
+ end
1029
+ break if check_sig == false
1030
+ unless @sig_db['rules'][i][kfield]['date']['inf'].nil?
1031
+ check_sig=false
1032
+ if Time.parse(elem_list) < (tnow - @sig_db['rules'][i][kfield]['date']['inf'])
1033
+ sig_add[kfield.to_s]="Value date #{event.get(kfield)} < #{@sig_db['rules'][i][kfield]['date']['inf']} found"
1034
+ check_sig=true
1035
+ end
1036
+ end
1037
+ break if check_sig == false
1038
+ unless @sig_db['rules'][i][kfield]['date']['diff'].nil?
1039
+ check_sig=false
1040
+ if Time.parse(elem_list) != (tnow - @sig_db['rules'][i][kfield]['date']['diff'])
1041
+ sig_add[kfield.to_s]="Value date #{event.get(kfield)} != #{@sig_db['rules'][i][kfield]['date']['diff']} found"
1042
+ check_sig=true
1043
+ end
1044
+ end
1045
+ break if check_sig == false
1046
+ end
1047
+ end
1048
+ end
1049
+ end
1050
+ #END : CHECK BY date
1051
+ #BEGIN : CHECK BY hour
1052
+ unless @sig_db['rules'][i][kfield]['hour'].nil?
1053
+ if event.get(kfield).is_a?(String) and not event.get(kfield).nil?
1054
+ unless @sig_db['rules'][i][kfield]['hour']['egal'].nil?
1055
+ check_sig=false
1056
+ if Time.parse(event.get(kfield)).hour.to_i == @sig_db['rules'][i][kfield]['hour']['egal'].to_i
1057
+ sig_add[kfield.to_s]="Value hour #{event.get(kfield)} == #{@sig_db['rules'][i][kfield]['hour']['egal'].to_s} found"
1058
+ check_sig=true
1059
+ end
1060
+ end
1061
+ break if check_sig == false
1062
+ unless @sig_db['rules'][i][kfield]['hour']['sup'].nil?
1063
+ check_sig=false
1064
+ if Time.parse(event.get(kfield)).hour.to_i > @sig_db['rules'][i][kfield]['hour']['sup'].to_i
1065
+ sig_add[kfield.to_s]="Value hour #{event.get(kfield)} > #{@sig_db['rules'][i][kfield]['hour']['sup'].to_s} found"
1066
+ check_sig=true
1067
+ end
1068
+ end
1069
+ break if check_sig == false
1070
+ unless @sig_db['rules'][i][kfield]['hour']['inf'].nil?
1071
+ check_sig=false
1072
+ if Time.parse(event.get(kfield)).hour.to_i < @sig_db['rules'][i][kfield]['hour']['inf'].to_i
1073
+ sig_add[kfield.to_s]="Value hour #{event.get(kfield)} < #{@sig_db['rules'][i][kfield]['hour']['inf'].to_s} found"
1074
+ check_sig=true
1075
+ end
1076
+ end
1077
+ break if check_sig == false
1078
+ unless @sig_db['rules'][i][kfield]['hour']['diff'].nil?
1079
+ check_sig=false
1080
+ if Time.parse(event.get(kfield)).hour.to_i != @sig_db['rules'][i][kfield]['hour']['diff'].to_i
1081
+ sig_add[kfield.to_s]="Value hour #{event.get(kfield)} != #{@sig_db['rules'][i][kfield]['hour']['diff'].to_s} found"
1082
+ check_sig=true
1083
+ end
1084
+ end
1085
+ break if check_sig == false
1086
+ end
1087
+ end
1088
+ #END : CHECK BY hour
1089
+ #BEGIN : CHECK BY day
1090
+ unless @sig_db['rules'][i][kfield]['day'].nil?
1091
+ if event.get(kfield).is_a?(String) and not event.get(kfield).nil?
1092
+ unless @sig_db['rules'][i][kfield]['day']['egal'].nil?
1093
+ check_sig=false
1094
+ if Time.parse(event.get(kfield)).wday.to_i == @sig_db['rules'][i][kfield]['day']['egal'].to_i
1095
+ sig_add[kfield.to_s]="Value day #{event.get(kfield)} == #{@sig_db['rules'][i][kfield]['day']['egal'].to_s} found"
1096
+ check_sig=true
1097
+ end
1098
+ end
1099
+ break if check_sig == false
1100
+ unless @sig_db['rules'][i][kfield]['day']['sup'].nil?
1101
+ check_sig=false
1102
+ if Time.parse(event.get(kfield)).wday.to_i > @sig_db['rules'][i][kfield]['day']['sup'].to_i
1103
+ sig_add[kfield.to_s]="Value day #{event.get(kfield)} > #{@sig_db['rules'][i][kfield]['day']['sup'].to_s} found"
1104
+ check_sig=true
1105
+ end
1106
+ end
1107
+ break if check_sig == false
1108
+ unless @sig_db['rules'][i][kfield]['day']['inf'].nil?
1109
+ check_sig=false
1110
+ if Time.parse(event.get(kfield)).wday.to_i < @sig_db['rules'][i][kfield]['dat']['inf'].to_i
1111
+ sig_add[kfield.to_s]="Value day #{event.get(kfield)} < #{@sig_db['rules'][i][kfield]['day']['inf'].to_s} found"
1112
+ check_sig=true
1113
+ end
1114
+ end
1115
+ break if check_sig == false
1116
+ unless @sig_db['rules'][i][kfield]['day']['diff'].nil?
1117
+ check_sig=false
1118
+ if Time.parse(event.get(kfield)).wday.to_i != @sig_db['rules'][i][kfield]['day']['diff'].to_i
1119
+ sig_add[kfield.to_s]="Value day #{event.get(kfield)} != #{@sig_db['rules'][i][kfield]['day']['diff'].to_s} found"
1120
+ check_sig=true
1121
+ end
1122
+ end
1123
+ break if check_sig == false
1124
+ end
1125
+ end
1126
+ #END : CHECK BY day
1127
+ #BEGIN : CHECK BY ip adress
1128
+ unless @sig_db['rules'][i][kfield]['ipaddr'].nil?
1129
+ if event.get(kfield).is_a?(String) and not event.get(kfield).nil?
1130
+ unless @sig_db['rules'][i][kfield]['ipaddr']['egal'].nil?
1131
+ check_sig=false
1132
+ net = IPAddr.new(@sig_db['rules'][i][kfield]['ipaddr']['egal'])
1133
+ if net===event.get(kfield).to_s
1134
+ sig_add[kfield.to_s]="Value IP address #{event.get(kfield)} != #{@sig_db['rules'][i][kfield]['ipaddr']['egal']} found"
1135
+ check_sig=true
1136
+ end
1137
+ end
1138
+ break if check_sig == false
1139
+ unless @sig_db['rules'][i][kfield]['ipaddr']['diff'].nil?
1140
+ check_sig=false
1141
+ net = IPAddr.new(@sig_db['rules'][i][kfield]['ipaddr']['diff'])
1142
+ if not net===event.get(kfield).to_s
1143
+ sig_add[kfield.to_s]="Value IP address #{event.get(kfield)} != #{@sig_db['rules'][i][kfield]['ipaddr']['diff']} found"
1144
+ check_sig=true
1145
+ end
1146
+ end
1147
+ break if check_sig == false
1148
+ end
1149
+ end
1150
+ #END : CHECK BY ip adress
1151
+ #BEGIN : CHECK BY size field operation
1152
+ unless @sig_db['rules'][i][kfield]['sizeope'].nil?
1153
+ if event.get(kfield).is_a?(String) and not event.get(kfield).nil?
1154
+ unless @sig_db['rules'][i][kfield]['sizeope']['egal'].nil?
1155
+ check_sig=false
1156
+ if event.get(kfield).length == @sig_db['rules'][i][kfield]['sizeope']['egal']
1157
+ sig_add[kfield.to_s]="Value numeric #{event.get(kfield).length} == #{@sig_db['rules'][i][kfield]['sizeope']['egal']} found"
1158
+ check_sig=true
1159
+ end
1160
+ end
1161
+ break if check_sig == false
1162
+ unless @sig_db['rules'][i][kfield]['sizeope']['sup'].nil?
1163
+ check_sig=false
1164
+ if event.get(kfield).length > @sig_db['rules'][i][kfield]['sizeope']['sup']
1165
+ sig_add[kfield.to_s]="Value numeric #{event.get(kfield).length} > #{@sig_db['rules'][i][kfield]['sizeope']['sup']} found"
1166
+ check_sig=true
1167
+ end
1168
+ end
1169
+ break if check_sig == false
1170
+ unless @sig_db['rules'][i][kfield]['sizeope']['inf'].nil?
1171
+ check_sig=false
1172
+ if event.get(kfield).length < @sig_db['rules'][i][kfield]['sizeope']['inf']
1173
+ sig_add[kfield.to_s]="Value numeric #{event.get(kfield).length} < #{@sig_db['rules'][i][kfield]['sizeope']['inf']} found"
1174
+ check_sig=true
1175
+ end
1176
+ end
1177
+ break if check_sig == false
1178
+ unless @sig_db['rules'][i][kfield]['sizeope']['diff'].nil?
1179
+ check_sig=false
1180
+ if event.get(kfield).length != @sig_db['rules'][i][kfield]['sizeope']['diff']
1181
+ sig_add[kfield.to_s]="Value numeric #{event.get(kfield).length} != #{@sig_db['rules'][i][kfield]['sizeope']['diff']} found"
1182
+ check_sig=true
1183
+ end
1184
+ end
1185
+ break if check_sig == false
1186
+ end
1187
+ end
1188
+ #END : CHECK BY size field operation
1189
+ #BEGIN : CHECK BY regexp
1190
+ unless @sig_db['rules'][i][kfield]['regexp'].nil?
1191
+ check_sig=false
1192
+ for regexp in @sig_db['rules'][i][kfield]['regexp']
1193
+ if event.get(kfield).is_a?(String) and not event.get(kfield).nil?
1194
+ match = Regexp.new(regexp, nil, 'n').match(event.get(kfield))
1195
+ if not match.nil?
1196
+ sig_add[kfield.to_s]="Regexp found #{match}"
1197
+ check_sig=true
1198
+ break
1199
+ end
1200
+ elsif event.get(kfield).is_a?(Array)
1201
+ for elem_list in event.get(kfield)
1202
+ if elem_list.is_a?(String)
1203
+ match = Regexp.new(regexp, nil, 'n').match(elem_list)
1204
+ if not match.nil?
1205
+ sig_add[kfield.to_s]="Regexp found #{match}"
1206
+ check_sig=true
1207
+ break
1208
+ end
1209
+ end
1210
+ end
1211
+ end
1212
+ end
1213
+ end
1214
+ break if check_sig == false
1215
+ #END : CHECK BY regexp
1216
+ #BEGIN : CHECK BY regexp excluse (not present)
1217
+ unless @sig_db['rules'][i][kfield]['notregexp'].nil?
1218
+ check_sig=false
1219
+ regexplen=@sig_db['rules'][i][kfield]['notregexp'].length
1220
+ veriflen=0
1221
+ for regexp in @sig_db['rules'][i][kfield]['notregexp']
1222
+ if event.get(kfield).is_a?(String)
1223
+ match = Regexp.new(regexp, nil, 'n').match(event.get(kfield))
1224
+ if match.nil?
1225
+ veriflen=veriflen+1
1226
+ end
1227
+ elsif event.get(kfield).is_a?(Array)
1228
+ for elem_list in event.get(kfield)
1229
+ if elem_list.is_a?(String)
1230
+ match = Regexp.new(regexp, nil, 'n').match(elem_list)
1231
+ if match.nil?
1232
+ veriflen=veriflen+1
1233
+ end
1234
+ end
1235
+ end
1236
+ end
1237
+ end
1238
+ if veriflen==regexplen
1239
+ sig_add[kfield.to_s]="Not Regexp present: OK"
1240
+ check_sig=true
1241
+ end
1242
+ end
1243
+ break if check_sig == false
1244
+ #END : CHECK BY regexp excluse (not present)
1245
+ #CHECK SIG BY FIELD END
1246
+ #check SIG RESULT FIND and get information name, type, modefp, note, id
1247
+ if check_sig == true
1248
+ validfield = validfield + 1
1249
+ if @sig_db['rules'][i][kfield]['id'].is_a?(Numeric)
1250
+ sig_add["id"] = @sig_db['rules'][i][kfield]['id'].to_i
1251
+ else
1252
+ #all information must to be on same field
1253
+ next
1254
+ end
1255
+ if @sig_db['rules'][i][kfield]['name'].is_a?(String)
1256
+ if sig_add["name_sig"].nil?
1257
+ sig_add["name_sig"] = @sig_db['rules'][i][kfield]['name']
1258
+ else
1259
+ sig_add["name_sig"] = sig_add["name_sig"] + @sig_db['rules'][i][kfield]['name']
1260
+ end
1261
+ end
1262
+ if @sig_db['rules'][i][kfield]['type'].is_a?(Numeric)
1263
+ if @sig_db['rules'][i][kfield]['type'] == 2
1264
+ type_sig = type_sig + 1
1265
+ end
1266
+ if @sig_db['rules'][i][kfield]['type'] == 1
1267
+ type_obl = type_obl + 1
1268
+ end
1269
+ end
1270
+ if @sig_db['rules'][i][kfield]['modeFP'].nil?
1271
+ if @sig_db['rules'][i][kfield]['modeFP'] == true
1272
+ sig_add["modeFP"] = true
1273
+ end
1274
+ end
1275
+ if @sig_db['rules'][i][kfield]['note'].is_a?(Numeric)
1276
+ if sig_add["note"].nil?
1277
+ sig_add["note"] = @sig_db['rules'][i][kfield]['note'].to_s
1278
+ else
1279
+ sig_add["note"] = (sig_add["note"].to_i + @sig_db['rules'][i][kfield]['note'].to_i).to_s
1280
+ end
1281
+ end
1282
+ if @sig_db['rules'][i][kfield]['extract'].is_a?(Hash)
1283
+ sig_add["extract"] = @sig_db['rules'][i][kfield]['extract']
1284
+ end
1285
+ #"freq_field:" [field,field,field,field],"freq_delay":60s,freq_count: 3, freq_resettime: 3600s, correlate_change_fieldvalue: []
1286
+ #use for correlate multi event type with correlate_change_fieldvalue
1287
+ # or use for freq select, by exemple brute force without correlate_change_fieldvalue
1288
+ if @sig_db['rules'][i][kfield]['freq_field'].is_a?(Array) and @sig_db['rules'][i][kfield]['freq_delay'].is_a?(Interger) and @sig_db['rules'][i][kfield]['freq_resettime'].is_a?(Integer) and @sig_db['rules'][i][kfield]['freq_count'].is_a?(Integer)
1289
+ sig_add["freq_field"] = @sig_db['rules'][i][kfield]['freq_field']
1290
+ sig_add["freq_delay"] = @sig_db['rules'][i][kfield]['freq_delay']
1291
+ sig_add["freq_count"] = @sig_db['rules'][i][kfield]['freq_count']
1292
+ sig_add["freq_resettime"] = @sig_db['rules'][i][kfield]['freq_resettime']
1293
+ if @sig_db['rules'][i][kfield]['correlate_change_fieldvalue'].is_a?(Array) and not @sig_db['rules'][i][kfield]['correlate_change_fieldvalue'].empty?
1294
+ sig_add["correlate_change_fieldvalue"] = @sig_db['rules'][i][kfield]['correlate_change_fieldvalue']
1295
+ end
1296
+ end
1297
+ end
1298
+ #end check result find
1299
+ end
1300
+ #verify all field checked and all checks are matched
1301
+ if countfield > 0 and countfield == validfield
1302
+ #if mode FP break and delete event
1303
+ if sig_add["modeFP"] == true
1304
+ #@logger.warn("DROP EVENT FP:", :string => sig_add["name_sig"])
1305
+ sig_add.clear
1306
+ detected_sig.clear
1307
+ detected_sig_count=0
1308
+ event.cancel
1309
+ return
1310
+ end
1311
+ #detected freq & correlate
1312
+ if sig_add["freq_field"]
1313
+ #get id sig for know if you create alert or no
1314
+ #example if just id match then don't create alert
1315
+ detected_sig_id_corre.push(*sig_add["id"])
1316
+ #create hash of event
1317
+ fields_value=""
1318
+ for fx in sig_add["freq_field"]
1319
+ if event.get(fx)
1320
+ fields_value = fields_value + event.get(fx).to_s.downcase
1321
+ end
1322
+ end
1323
+ hash_field = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, "SIG-PLUGIN-FREQ", fields_value.to_s).force_encoding(Encoding::UTF_8)
1324
+ if @sig_db_freq[hash_field]
1325
+ #hash in db
1326
+ #verify if valid is false
1327
+ if @sig_db_freq[hash_field]['valid'] == false
1328
+ #ok hash not matched
1329
+ #verify delay
1330
+ if @sig_db_freq[hash_field]['delay'] < tnow
1331
+ #delay is out
1332
+ #restart of 0
1333
+ @sig_db_freq[hash_field]['count'] = 1
1334
+ @sig_db_freq[hash_field]['delay'] = tnow + sig_add["freq_delay"]
1335
+ if sig_add["correlate_change_fieldvalue"]
1336
+ fields_corre_value=""
1337
+ @sig_db_freq[hash_field]['corre_value'] = []
1338
+ for fy in sig_add["freq_field"]
1339
+ if event.get(fy)
1340
+ fields_corre_value = fields_corre_value + event.get(fy).to_s.downcase
1341
+ end
1342
+ end
1343
+ @sig_db_freq[hash_field]['corre_value'].push(*OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, "SIG-PLUGIN-FREQ", fields_corre_value.to_s).force_encoding(Encoding::UTF_8))
1344
+ end
1345
+ @sig_db_freq[hash_field]['valid'] = false
1346
+ else
1347
+ #ok count, because delay is valid
1348
+ #check if sig_add["correlate_change_fieldvalue"] is present
1349
+ hash_corre_value = ""
1350
+ if sig_add["correlate_change_fieldvalue"]
1351
+ fields_corre_value=""
1352
+ for fy in sig_add["freq_field"]
1353
+ if event.get(fy)
1354
+ fields_corre_value = fields_corre_value + event.get(fy).to_s.downcase
1355
+ end
1356
+ end
1357
+ hash_corre_value = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, "SIG-PLUGIN-FREQ", fields_corre_value.to_s).force_encoding(Encoding::UTF_8)
1358
+ if not @sig_db_freq[hash_field]['corre_value'].include?(hash_corre_value)
1359
+ #if correlate hash not exist count ++
1360
+ @sig_db_freq[hash_field]['count'] = @sig_db_freq[hash_field]['count'] + 1
1361
+ @sig_db_freq[hash_field]['corre_value'].push(*hash_corre_value)
1362
+ end
1363
+ else
1364
+ #no correlate
1365
+ @sig_db_freq[hash_field]['count'] = @sig_db_freq[hash_field]['count'] + 1
1366
+ end
1367
+ #verify if count reach count_value rule
1368
+ if @sig_db_freq[hash_field]['count'] >= sig_add["freq_resettime"]
1369
+ #valid sig
1370
+ @sig_db_freq[hash_field]['delay'] = tnow + sig_add["freq_resettime"]
1371
+ @sig_db_freq[hash_field]['valid'] = true
1372
+ detected_sig_id_corre.clear
1373
+ end
1374
+ end
1375
+ else
1376
+ #hash matched in past, verify if resettime is passed?
1377
+ if @sig_db_freq[hash_field]['delay'] < tnow
1378
+ #delay is passed, restart to 0
1379
+ @sig_db_freq[hash_field]['count'] = 1
1380
+ if sig_add["correlate_change_fieldvalue"]
1381
+ @sig_db_freq[hash_field]['corre_value'] = []
1382
+ fields_corre_value=""
1383
+ for fy in sig_add["freq_field"]
1384
+ if event.get(fy)
1385
+ fields_corre_value = fields_corre_value + event.get(fy).to_s.downcase
1386
+ end
1387
+ end
1388
+ @sig_db_freq[hash_field]['corre_value'].push(*OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, "SIG-PLUGIN-FREQ", fields_corre_value.to_s).force_encoding(Encoding::UTF_8))
1389
+ end
1390
+ @sig_db_freq[hash_field]['delay'] = tnow + sig_add["freq_delay"]
1391
+ @sig_db_freq[hash_field]['valid'] = false
1392
+ end
1393
+ end
1394
+ else
1395
+ #new hash
1396
+ @sig_db_freq[hash_field] = {}
1397
+ @sig_db_freq[hash_field]['count'] = 1
1398
+ if sig_add["correlate_change_fieldvalue"]
1399
+ fields_corre_value=""
1400
+ @sig_db_freq[hash_field]['corre_value'] = []
1401
+ for fy in sig_add["freq_field"]
1402
+ if event.get(fy)
1403
+ fields_corre_value = fields_corre_value + event.get(fy).to_s.downcase
1404
+ end
1405
+ end
1406
+ @sig_db_freq[hash_field]['corre_value'].push(*OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, "SIG-PLUGIN-FREQ", fields_corre_value.to_s).force_encoding(Encoding::UTF_8))
1407
+ end
1408
+ @sig_db_freq[hash_field]['delay'] = tnow + sig_add["freq_delay"]
1409
+ @sig_db_freq[hash_field]['valid'] = false
1410
+ end
1411
+ end
1412
+ #detected_extract
1413
+ if sig_add["extract"]
1414
+ #extract field and insert in ioc local
1415
+ sig_add["extract"].each do |ekey,eval|
1416
+ if event.get(ekey) and @ioc_db_local
1417
+ if @ioc_db_local[eval]
1418
+ unless @ioc_db_local[eval].include?(event.get(ekey))
1419
+ @ioc_db_local[eval].push(*event.get(ekey))
1420
+ sleep(1) until @load_statut_ioc
1421
+ @load_statut_ioc = false
1422
+ @ioc_db = @ioc_db.merge(db_tmp) {|key, first, second| first.is_a?(Array) && second.is_a?(Array) ? first | second : second }
1423
+ @load_statut_ioc = true
1424
+ end
1425
+ else
1426
+ @ioc_db_local[eval] = []
1427
+ @ioc_db_local[eval].push(*event.get(ekey))
1428
+ sleep(1) until @load_statut_ioc
1429
+ @load_statut_ioc = false
1430
+ @ioc_db = @ioc_db.merge(db_tmp) {|key, first, second| first.is_a?(Array) && second.is_a?(Array) ? first | second : second }
1431
+ @load_statut_ioc = true
1432
+ end
1433
+ end
1434
+ end
1435
+ end
1436
+ detected_sig.push(*sig_add)
1437
+ #no continu if one rule match
1438
+ if @check_stop
1439
+ detected_sig_count = 1
1440
+ detected_sig_note = sig_add["note"].to_i
1441
+ detected_sig_id.push(*sig_add["id"])
1442
+ detected_sig_name.push(*sig_add["name_sig"])
1443
+ sig_add.clear
1444
+ break
1445
+ else
1446
+ detected_sig_count = detected_sig_count + 1
1447
+ detected_sig_name.push(*sig_add["name_sig"])
1448
+ detected_sig_id.push(*sig_add["id"])
1449
+ if detected_sig_note < sig_add["note"].to_i
1450
+ detected_sig_note = sig_add["note"].to_i
1451
+ end
1452
+ sig_add.clear
1453
+ end
1454
+ else
1455
+ sig_add.clear
1456
+ end
1457
+ end
1458
+ end
1459
+ end
1460
+ eventK.clear
1461
+ #check if sig detected, and add to @targetxxx_sig
1462
+ if detected_sig.any? and type_sig < detected_sig_count and type_obl > 0
1463
+ #verify if not juste correlate rule match
1464
+ if detected_sig_id != detected_sig_id_corre
1465
+ unless event.get(@target_sig).nil?
1466
+ event.set(@target_sig, event.get(@target_sig) + detected_sig)
1467
+ else
1468
+ event.set(@target_sig, detected_sig)
1469
+ end
1470
+ unless event.get(@targetnum_sig).nil?
1471
+ event.set(@targetnum_sig, event.get(@targetnum_sig) + detected_sig_count)
1472
+ else
1473
+ event.set(@targetnum_sig, detected_sig_count)
1474
+ end
1475
+ unless event.get(@targetnote).nil?
1476
+ if event.get(@targetnote) < detected_sig_note
1477
+ event.set(@targetnote, detected_sig_note)
1478
+ end
1479
+ else
1480
+ event.set(@targetnote, detected_sig_note)
1481
+ end
1482
+ unless event.get(@targetname_sig).nil?
1483
+ event.set(@targetname_sig, event.get(@targetname_sig) + detected_sig_name)
1484
+ else
1485
+ event.set(@targetname_sig, detected_sig_name)
1486
+ end
1487
+ unless event.get(@targetid).nil?
1488
+ event.set(@targetid, event.get(@targetid) + detected_sig_id)
1489
+ else
1490
+ event.set(@targetid, detected_sig_id)
1491
+ end
1492
+ end
1493
+ #@logger.warn("Dectected SIG", :detected_sig_name => detected_sig_name)
1494
+ end
1495
+ end
1496
+ ######################
1497
+
1498
+ ######REFERENCE#######
1499
+ #check refresh db ref
1500
+ unless @disable_ref
1501
+ if @next_refresh_confrules < tnow
1502
+ if @load_statut_rules == true
1503
+ @load_statut_rules = false
1504
+ load_db_ref
1505
+ @next_refresh_confrules = tnow + @refresh_interval_confrules
1506
+ @load_statut_rules = true
1507
+ end
1508
+ end
1509
+ sleep(1) until @load_statut_rules
1510
+ end
1511
+ #check if db and rule not empty
1512
+ if not @ref_rules.empty? and not @ref_db.empty? and not @pattern_db and not @disable_ref and event.get(@noapply_ref).nil? and event.get(@field_enr).nil?
1513
+ #list all rules
1514
+ #!!!! amelioration de la sig avec simhash...
1515
+ detected_ref = Array.new
1516
+ detected_ref_field = Array.new
1517
+ detected_ref_id = Array.new
1518
+ detected_ref_err_count = 0
1519
+ detected_ref_note = 0
1520
+ eventK = event.to_hash.keys
1521
+ for r_rule in @ref_rules
1522
+ #rules[ {"pivot_field":{field1:'value'},{field2:'value'}, "list_sig": [fieldx,fieldy,...], "relation_min": 10, "simhash_size": 16, "simhash_use_size": 14, "id": 200X} ]
1523
+ # if pivot containt array, !!! order is important
1524
+ # list_sig containt field possible, if one field not exist, it works too
1525
+ num_p = r_rule["pivot_field"].keys.length
1526
+ pivot = r_rule["pivot_field"].keys & eventK
1527
+ tmp_detect={}
1528
+ tmp_detect[r_rule["id"].to_s]={}
1529
+ #heck if pivot present in event
1530
+ if num_p == pivot.length
1531
+ stop = false
1532
+ for keyx in pivot
1533
+ if event.get(keyx) === r_rule["pivot_field"][keyx]
1534
+ stop = true
1535
+ break
1536
+ end
1537
+ end
1538
+ next if stop
1539
+ if @ref_db[r_rule["id"].to_s]
1540
+ #{ 'ID20XXXX': {
1541
+ # 'field': {
1542
+ # 'TYPE': 'Array|Int|String|...',
1543
+ # 'Uniq_value': true or false, #define if value is random => true
1544
+ # 'NOTE_UNIQ_REDUC': 0.1 # for reduce note if match on uniq fueld
1545
+ # 'LIST_VALUE': ['value_possible1','value_possible2','value_possibleX'],
1546
+ # 'NOTE_LISTV': 0.25 # note between 0.x and 4 default 0.25
1547
+ # 'ENCODING': true or false, # value contains than ascii caratere
1548
+ # 'NOTE_ENCODING': 0.25 # note between 0.x and 4 default 0.25
1549
+ # 'LEN_MAX': numeric_value,
1550
+ # 'NOTE_LEN': 0.25 # note between 0.x and 4 default 0.25
1551
+ # 'LEN_MIN': numeric_value,
1552
+ # 'LEN_AVG': numeric_value,
1553
+ # 'LEN_AVG_PRCT': pourcent for AVG,
1554
+ # 'NOTE_LEN_AVG': 0.1 # note between 0.x and 4 default 0.1
1555
+ # 'LEN_EVENorUNEVENnum': numeric_value, #even num = 1;uneven num = 2; unknown/undefine = 0
1556
+ # 'NOTE_LEN_EVEN': 0.25 # note between 0.x and 4 default 0.25
1557
+ # 'REGEXP_MIN': [],
1558
+ # 'NOTE_REGEXP_MIN': 0.25 # note between 0.x and 4 default 0.25
1559
+ # 'REGEXP': []
1560
+ # 'NOTE_REGEXP': 0.25 # note between 0.x and 4 default 0.25
1561
+ # } ,
1562
+ # #relation value_fix contains list of value of field not unique (random)
1563
+ # # by exemple fld1: '1'; fld2: 'blabla';fld3: '10.10.10.10'
1564
+ # # create LIST simhash value and attention to order field
1565
+ # # you can optimiz with simhash - end if earn place memory
1566
+ # # important you count SIMHASH:COUNT for use COUNT if very little score => suspect [use conf -> relation_min]
1567
+ # 'relation_value_fix": {'SIMHASH1':COUNTX,'SIMHASH2':COUNTY,'SIMHASH3':COUNTX},
1568
+ # 'NOTE_DEFAULT': 2# note between 0.x and 4 default 2
1569
+ # !!!!!!!!!!!!!!! if NOTE or relation_value_fix is name of real field == problem!!!!
1570
+ # }}}
1571
+ #create sig event
1572
+ sig_tmp = r_rule["list_sig"] & eventK
1573
+ if sig_tmp.any?
1574
+ #sif is not empty
1575
+ #CHECK FIELD by FIELD
1576
+ sig_not_uniq = []
1577
+ for field in sig_tmp
1578
+ tmp_detect[r_rule["id"].to_s][field.to_s]={}
1579
+ string_field = true
1580
+ #CHECK: TYPE -> int/string/array/hash/... not for note, juste for next step for good choice => nummber or string analysis
1581
+ if ['boolean', 'long', 'integer', 'short', 'byte', 'double', 'float'].include?(@ref_db[r_rule["id"].to_s][field]['TYPE'].to_s)
1582
+ string_field = false
1583
+ end
1584
+ #CHECK: LIST_VALUE is not empty then check if contains
1585
+ if not @ref_db[r_rule["id"].to_s][field]['LIST_VALUE'].empty? and not @ref_db[r_rule["id"].to_s][field]['LIST_VALUE'].include?(event.get(field.to_s))
1586
+ detected_ref_note = detected_ref_note + @ref_db[r_rule["id"].to_s][field]['NOTE_LISTV']
1587
+ detected_ref_err_count = detected_ref_err_count + 1
1588
+ detected_ref_id.push(*r_rule["id"]) if not detected_ref_id.include?(r_rule["id"])
1589
+ detected_ref_field.push(*field.to_s) if not detected_ref_field.include?(field.to_s)
1590
+ tmp_detect[r_rule["id"].to_s][field.to_s]['LIST_VALUE']="Value not in list: " + event.get(field.to_s)
1591
+ end
1592
+ #CHECK: ENCODING char, not check if not string
1593
+ if string_field and not @ref_db[r_rule["id"].to_s][field]['ENCODING'].include?(event.get(field.to_s).encoding.to_s)
1594
+ detected_ref_note = detected_ref_note + @ref_db[r_rule["id"].to_s][field]['NOTE_ENCODING']
1595
+ detected_ref_err_count = detected_ref_err_count + 1
1596
+ detected_ref_id.push(*r_rule["id"]) if not detected_ref_id.include?(r_rule["id"])
1597
+ detected_ref_field.push(*field.to_s) if not detected_ref_field.include?(field.to_s)
1598
+ tmp_detect[r_rule["id"].to_s][field.to_s]['ENCODING']=event.get(field.to_s).encoding.to_s
1599
+ end
1600
+ #CHECK: TYPE class of number, not check for string
1601
+ if not string_field and not @ref_db[r_rule["id"].to_s][field]['ENCODING'].include?(event.get(field.to_s).class.to_s)
1602
+ detected_ref_note = detected_ref_note + @ref_db[r_rule["id"].to_s][field]['NOTE_ENCODING']
1603
+ detected_ref_err_count = detected_ref_err_count + 1
1604
+ detected_ref_id.push(*r_rule["id"]) if not detected_ref_id.include?(r_rule["id"])
1605
+ detected_ref_field.push(*field.to_s) if not detected_ref_field.include?(field.to_s)
1606
+ tmp_detect[r_rule["id"].to_s][field.to_s]['ENCODING']=event.get(field.to_s).encoding.to_s
1607
+ end
1608
+ #CHECK: LEN for compare to MAX/MIN/AVG
1609
+ f_len=0
1610
+ #DIfferent check if field type string or number
1611
+ if string_field
1612
+ f_len=event.get(field.to_s).length
1613
+ else
1614
+ f_len=event.get(field.to_s)
1615
+ end
1616
+ prct_h = @ref_db[r_rule["id"].to_s][field]['LEN_AVG'].to_f + ( @ref_db[r_rule["id"].to_s][field]['LEN_AVG'].to_f / 100.to_f * @ref_db[r_rule["id"].to_s][field]['LEN_AVG_PRCT'].to_f )
1617
+ prct_l = @ref_db[r_rule["id"].to_s][field]['LEN_AVG'].to_f - ( @ref_db[r_rule["id"].to_s][field]['LEN_AVG'].to_f / 100.to_f * @ref_db[r_rule["id"].to_s][field]['LEN_AVG_PRCT'].to_f )
1618
+ if f_len > @ref_db[r_rule["id"].to_s][field]['LEN_MAX'] or f_len < @ref_db[r_rule["id"].to_s][field]['LEN_MIN'] or (prct_l >= f_len.to_f and f_len.to_f <= prct_h)
1619
+ detected_ref_note = detected_ref_note + @ref_db[r_rule["id"].to_s][field]['NOTE_LEN']
1620
+ detected_ref_err_count = detected_ref_err_count + 1
1621
+ detected_ref_id.push(*r_rule["id"]) if not detected_ref_id.include?(r_rule["id"])
1622
+ detected_ref_field.push(*field.to_s) if not detected_ref_field.include?(field.to_s)
1623
+ tmp_detect[r_rule["id"].to_s][field.to_s]['LEN']=f_len
1624
+ end
1625
+ #CHECK: type number (unven/uneven) if value different of 0
1626
+ f_len_even = 2
1627
+ if f_len.even?
1628
+ f_len_even = 1
1629
+ end
1630
+ if @ref_db[r_rule["id"].to_s][field]['LEN_EVENorUNEVENnum'] != 0 and f_len_even != @ref_db[r_rule["id"].to_s][field]['LEN_EVENorUNEVENnum']
1631
+ detected_ref_note = detected_ref_note + @ref_db[r_rule["id"].to_s][field]['NOTE_LEN_EVEN']
1632
+ detected_ref_err_count = detected_ref_err_count + 1
1633
+ detected_ref_id.push(*r_rule["id"]) if not detected_ref_id.include?(r_rule["id"])
1634
+ detected_ref_field.push(*field.to_s) if not detected_ref_field.include?(field.to_s)
1635
+ tmp_detect[r_rule["id"].to_s][field.to_s]['LEN_EVEN']=f_len_even
1636
+ end
1637
+ #CHECK: Regexp pattern Normaly/MInimal
1638
+ #create regexp list match of field
1639
+ rlist = []
1640
+ @pattern_db.each do |key, value|
1641
+ match = Regexp.new(value, nil, 'n').match(event.get(field.to_s).to_s)
1642
+ if not match.nil?
1643
+ rlist << key
1644
+ end
1645
+ end
1646
+ #intersection with reference
1647
+ regexp_min = @ref_db[r_rule["id"].to_s][field]['REGEXP_MIN'] & rlist
1648
+ #if all reference not present in event
1649
+ if regexp_min.length != @ref_db[r_rule["id"].to_s][field]['REGEXP_MIN'].length
1650
+ detected_ref_note = detected_ref_note + @ref_db[r_rule["id"].to_s][field]['NOTE_REGEXP_MIN']
1651
+ detected_ref_err_count = detected_ref_err_count + 1
1652
+ detected_ref_id.push(*r_rule["id"]) if not detected_ref_id.include?(r_rule["id"])
1653
+ detected_ref_field.push(*field.to_s) if not detected_ref_field.include?(field.to_s)
1654
+ tmp_detect[r_rule["id"].to_s][field.to_s]['REGEXP_MIN']=regexp_min - rlist
1655
+ end
1656
+ #create regexp sig
1657
+ srlist=rlist.join("::")
1658
+ #Search regexp sig in reference
1659
+ unless @ref_db[r_rule["id"].to_s][field]['REGEXP'].include?(srlist)
1660
+ detected_ref_note = detected_ref_note + @ref_db[r_rule["id"].to_s][field]['NOTE_REGEXP']
1661
+ detected_ref_err_count = detected_ref_err_count + 1
1662
+ detected_ref_id.push(*r_rule["id"]) if not detected_ref_id.include?(r_rule["id"])
1663
+ detected_ref_field.push(*field.to_s) if not detected_ref_field.include?(field.to_s)
1664
+ tmp_detect[r_rule["id"].to_s][field.to_s]['REGEXP']=srlist
1665
+ end
1666
+ #CHECK: Unique Value -> create SIG UNIQ
1667
+ unless @ref_db[r_rule["id"].to_s][field]['Uniq_value']
1668
+ sig_not_uniq << field.to_s
1669
+ end
1670
+ end
1671
+ #CHECK: GLOBAL relation of uniq field by simhash for PIVOT->SIG
1672
+ #create simhash of sig_not_uniq value
1673
+ sig_not_uniq = sig_not_uniq.sort
1674
+ sig_not_uniq_value = []
1675
+ for xfield in sig_not_uniq
1676
+ sig_not_uniq_value << event.get(xfield.to_s)
1677
+ end
1678
+ #create simhash
1679
+ sig_not_uniq_value = sig_not_uniq_value.to_s.force_encoding('iso-8859-1').encode('utf-8') #string
1680
+ simhash_event = sig_not_uniq_value.simhash(:hashbits => r_rule["simhash_size"]).to_s
1681
+ if @ref_db[r_rule["id"].to_s]['relation_value_fix'].key?(simhash_event)
1682
+ #present , verify count
1683
+ if @ref_db[r_rule["id"].to_s]['relation_value_fix'][simhash_event] < r_rule["relation_min"]
1684
+ # more less than count_min
1685
+ detected_ref_note = detected_ref_note + @ref_db[r_rule["id"].to_s][field]['NOTE']
1686
+ detected_ref_err_count = detected_ref_err_count + 1
1687
+ detected_ref_id.push(*r_rule["id"]) if not detected_ref_id.include?(r_rule["id"])
1688
+ detected_ref_field.push(*field.to_s) if not detected_ref_field.include?(field.to_s)
1689
+ tmp_detect[r_rule["id"].to_s][field.to_s]['RELATION_LOW']=simhash_event
1690
+ end
1691
+ else
1692
+ # not present
1693
+ detected_ref_note = detected_ref_note + @ref_db[r_rule["id"].to_s][field]['NOTE']
1694
+ detected_ref_err_count = detected_ref_err_count + 1
1695
+ detected_ref_id.push(*r_rule["id"]) if not detected_ref_id.include?(r_rule["id"])
1696
+ detected_ref_field.push(*field.to_s) if not detected_ref_field.include?(field.to_s)
1697
+ tmp_detect[r_rule["id"].to_s][field.to_s]['RELATION']=simhash_event
1698
+ end
1699
+ detected_ref.push(*tmp_detect)
1700
+ end
1701
+ end
1702
+ end
1703
+ if @ref_stop_after_firstffind and detected_ref_err_count > 0
1704
+ break
1705
+ end
1706
+ end
1707
+ #add detected to event
1708
+ if detected_ref.any? and detected_ref_err_count > 0
1709
+ unless event.get(@target_ref).nil?
1710
+ event.set(@target_ref, event.get(@target_ref) + detected_ref)
1711
+ else
1712
+ event.set(@target_ref, detected_ref)
1713
+ end
1714
+ unless event.get(@targetnum_ref).nil?
1715
+ event.set(@targetnum_ref, event.get(@targetnum_ref) + detected_ref_err_count)
1716
+ else
1717
+ event.set(@targetnum_ref, detected_ref_err_count)
1718
+ end
1719
+ detected_ref_note = ( detected_ref_note + @ref_aroundfloat ).to_i #around float to int -- default + 0.5
1720
+ if detected_ref_note > 4
1721
+ detected_ref_note = 4
1722
+ end
1723
+ unless event.get(@targetnote).nil?
1724
+ if event.get(@targetnote) < detected_ref_note
1725
+ event.set(@targetnote, detected_ref_note)
1726
+ end
1727
+ else
1728
+ event.set(@targetnote, detected_ref_note)
1729
+ end
1730
+ unless event.get(@targetname_ref).nil?
1731
+ event.set(@targetname_ref, event.get(@targetname_ref) + detected_ref_field)
1732
+ else
1733
+ event.set(@targetname_ref, detected_ref_field)
1734
+ end
1735
+ unless event.get(@targetid).nil?
1736
+ event.set(@targetid, event.get(@targetid) + detected_ref_id)
1737
+ else
1738
+ event.set(@targetid, detected_ref_id)
1739
+ end
1740
+ #@logger.warn("Dectected SIG", :detected_sig_name => detected_sig_name)
1741
+ end
1742
+ end
1743
+ ######################
1744
+
1745
+ ######## NOTE ########
1746
+ #check refresh db note
1747
+ if not event.get(@targetid).nil? and not @disable_note
1748
+ if @next_refresh_note < tnow
1749
+ if @load_statut_note == true
1750
+ @load_statut_note = false
1751
+ load_conf_rules_note
1752
+ @next_refresh_note = tnow + @refresh_interval_confrules
1753
+ @load_statut_note = true
1754
+ end
1755
+ end
1756
+ sleep(1) until @load_statut_note
1757
+ end
1758
+ #check if db note empty and @targetid in event exist
1759
+ if not @note_db.empty? and not event.get(@targetid).nil? and not @disable_note and event.get(@field_enr).nil?
1760
+ note_max=0
1761
+ overwrite=false
1762
+ #check all rules
1763
+ for r_note in @note_db
1764
+ #check note
1765
+ if r_note['id'] #id must present
1766
+ if r_note['id'].is_a?(Array) #id must be type Array
1767
+ verif=r_note['id'].length
1768
+ #create intersection with event id and id present in rule
1769
+ intersec = event.get(@targetid) & r_note['id']
1770
+ #verify all id present in event
1771
+ if not intersec.length == verif
1772
+ next
1773
+ end
1774
+ end
1775
+ #check if option id present in rule
1776
+ if not r_note['optid'].nil? and not r_note['opt_num'].nil? #id find with opt_num present
1777
+ intersec = event.get(@targetid) & r_note['optid'] #create intersection
1778
+ #verify minimum X (@opt_num) present in event
1779
+ if not intersec.length >= r_note['opt_num'].to_i
1780
+ next
1781
+ end
1782
+ end
1783
+ #check if not id present option in rule
1784
+ if r_note['noid'].is_a?(Array) and not r_note['noid'].empty?
1785
+ intersec = event.get(@targetid) & r_note['noid'] #create intersection
1786
+ #verify none id present in event
1787
+ if not intersec.length == 0
1788
+ next
1789
+ end
1790
+ end
1791
+ #change note if upper
1792
+ if note_max < r_note['note']
1793
+ note_max = r_note['note']
1794
+ # if option overwrite, change note even if note lower
1795
+ if r_note['overwrite']
1796
+ overwrite=true
1797
+ end
1798
+ end
1799
+ end
1800
+ end
1801
+ if note_max != 0
1802
+ if ( event.get(@targetnote) > note_max and overwrite ) or ( event.get(@targetnote) < note_max )
1803
+ event.set(@targetnote, note_max)
1804
+ end
1805
+ end
1806
+ end
1807
+ ######################
1808
+
1809
+ ######FINGERPRINT USE & DROP END######
1810
+ # create fingerprint at end because, you need to have sig & ioc detected for unique event
1811
+ #refresh db & conf fingerprint
1812
+ unless @disable_fp
1813
+ if @next_refresh_conffp < tnow
1814
+ if @load_statut_fp == true
1815
+ @load_statut_fp = false
1816
+ load_conf_fp
1817
+ load_db_dropfp
1818
+ @next_refresh_conffp = tnow + @refresh_interval_conffp
1819
+ @load_statut_fp = true
1820
+ end
1821
+ end
1822
+ sleep(1) until @load_statut_fp
1823
+ end
1824
+ #chekc if db &conf are not empty + select_fp exist
1825
+ if not @fp_rules.empty? and not @fp_db.nil? and not event.get(@select_fp).nil? and not @disable_fp and event.get(@field_enr).nil?
1826
+ to_string = ""
1827
+ if event.get(@select_fp).is_a?(Array)
1828
+ for elemsfp in event.get(@select_fp)
1829
+ #check if rules match with select_fp (case: Array)
1830
+ if @fp_rules.key?(elemsfp.to_s)
1831
+ if @fp_rules[elemsfp.to_s]['fields'].is_a?(Array) and @fp_rules[elemsfp.to_s]['hashbit'].is_a?(Numeric)
1832
+ #create fingerprint
1833
+ @fp_rules[elemsfp.to_s]['fields'].sort.each do |k|
1834
+ if event.get(k)
1835
+ to_string << "|#{k}|#{event.get(k)}"
1836
+ end
1837
+ end
1838
+ to_string << "|"
1839
+ to_string = to_string.force_encoding('iso-8859-1').encode('utf-8') #string
1840
+ event.set(@target_fp, to_string.simhash(:hashbits => @fp_rules[elemsfp.to_s]['hashbit']).to_s)
1841
+ #check db fp drop
1842
+ if event.get(@noapply_sig_dropfp).nil? and @fp_db[event.get(@target_fp)]
1843
+ event.cancel
1844
+ return
1845
+ end
1846
+ if @fingerprint_db[event.get(@target_fp)]
1847
+ #key existe -- event known
1848
+ if @fingerprint_db[event.get(@target_fp)] < tnow
1849
+ #date is passed
1850
+ @fingerprint_db[event.get(@target_fp)] = tnow + @fp_rules[elemsfp.to_s]['delay']
1851
+ #(event[@target_tag_fp] ||= []) << @tag_name_first
1852
+ event.set(@target_tag_fp, []) unless event.get(@target_tag_fp)
1853
+ event.set(@target_tag_fp, event.get(@target_tag_fp) + @tag_name_first)
1854
+ else
1855
+ #add tag
1856
+ #(event.get(@target_tag_fp) ||= []) << @tag_name_after
1857
+ event.set(@target_tag_fp, []) unless event.get(@target_tag_fp)
1858
+ event.set(@target_tag_fp, event.get(@target_tag_fp) + @tag_name_after)
1859
+ end
1860
+ else
1861
+ #key not exist -- new event
1862
+ @fingerprint_db[event.get(@target_fp)] = tnow + @fp_rules[elemsfp.to_s]['delay']
1863
+ #(event[@target_tag_fp] ||= []) << @tag_name_first
1864
+ event.set(@target_tag_fp, []) unless event.get(@target_tag_fp)
1865
+ event.set(@target_tag_fp, event.get(@target_tag_fp) + @tag_name_first)
1866
+ end
1867
+ end
1868
+ break
1869
+ end
1870
+ end
1871
+ #check if rules match with select_fp (case String)
1872
+ elsif event.get(@select_fp).is_a?(String) and @fp_rules.key?(event.get(@select_fp))
1873
+ if @fp_rules[event.get(@select_fp)]['fields'].is_a?(Array) and @fp_rules[event.get(@select_fp)]['hashbit'].is_a?(Integer)
1874
+ #create fingerprint
1875
+ @fp_rules[event.get(@select_fp)]['fields'].sort.each do |k|
1876
+ if event.get(k)
1877
+ to_string << "|#{k}|#{event.get(k)}"
1878
+ end
1879
+ end
1880
+ to_string << "|"
1881
+ to_string = to_string.force_encoding('iso-8859-1').encode('utf-8') #string
1882
+ event.set(@target_fp, to_string.simhash(:hashbits => @fp_rules[event.get(@select_fp)]['hashbit']).to_s)
1883
+ #check db fp drop
1884
+ if event.get(@noapply_sig_dropfp).nil? and @fp_db[event.get(@target_fp)]
1885
+ event.cancel
1886
+ return
1887
+ end
1888
+ if @fingerprint_db[event.get(@target_fp)]
1889
+ #key existe -- event known
1890
+ if @fingerprint_db[event.get(@target_fp)] < tnow
1891
+ #date is passed
1892
+ @fingerprint_db[event.get(@target_fp)] = tnow + @fp_rules[event.get(@select_fp)]['delay']
1893
+ #(event[@target_tag_fp] ||= []) << @tag_name_first
1894
+ event.set(@target_tag_fp, []) unless event.get(@target_tag_fp)
1895
+ event.set(@target_tag_fp, event.get(@target_tag_fp) + [@tag_name_first])
1896
+ else
1897
+ #add tag
1898
+ #(event[@target_tag_fp] ||= []) << @tag_name_after
1899
+ event.set(@target_tag_fp, []) unless event.get(@target_tag_fp)
1900
+ event.set(@target_tag_fp, event.get(@target_tag_fp) + [@tag_name_after])
1901
+ end
1902
+ else
1903
+ #key not exist -- new event
1904
+ @fingerprint_db[event.get(@target_fp)] = tnow + @fp_rules[event.get(@select_fp)]['delay']
1905
+ #(event[@target_tag_fp] ||= []) << @tag_name_first
1906
+ event.set(@target_tag_fp, []) unless event.get(@target_tag_fp)
1907
+ event.set(@target_tag_fp, event.get(@target_tag_fp) + [@tag_name_first])
1908
+ end
1909
+ end
1910
+ end
1911
+ end
1912
+ ###########################
1913
+
1914
+ ######## FREQ EVENT ########
1915
+ #rules_freq = [ {'select_field': {'fieldx':[value_list],'fieldy':[value_list]}, 'note': X, 'refresh_time': Xseconds,'reset_time': Xseconds[1j], 'reset_hour': '00:00:00', 'wait_after_reset': 10, 'id': 30XXX},...]
1916
+ #TODO: CREATE TEMPLATE FOR NEW MESSAGE
1917
+ #select field for select => first filter
1918
+ #select field value => second filter
1919
+ #refresh_time for check and calculate all time result: max & variation
1920
+ # note if match
1921
+ # reset time in second for reset all counter value
1922
+ # reset hour for begin reset with hour => use for 24h reset begin at 00:00
1923
+ # wait_after_reset: dont't check before 10 times values
1924
+ #db_freq = { '30XXX': {'status_acces':true,'reset_time': date,'refresh_date': date, 'old_date': date,'num_time': Xtimes, 'V_prev': x/m, 'Varia_avg': z/m, 'count_prev': Xtimes, 'count_cour': Xtimes, 'V_max': x/m, 'Varia_max': x/m, 'Varia_min': +/- x/m, 'Varia_glob': x/m}}
1925
+ #check refresh db ref
1926
+ #
1927
+ unless @disable_freq
1928
+ if @next_refresh_freqrules < tnow
1929
+ if @load_statut_freqrules == true
1930
+ @load_statut_freqrules = false
1931
+ load_rules_freq # load rules and create db_freq with init var
1932
+ @next_refresh_freqrules = tnow + @refresh_interval_freqrules
1933
+ @load_statut_freqrules = true
1934
+ end
1935
+ end
1936
+ sleep(1) until @load_statut_freqrules
1937
+ end
1938
+ #verify db & rules is not empty
1939
+ if not @freq_rules.empty? and not @db_freq.empty? and not @disable_freq and event.get(@noapply_freq).nil? #and event.get(@field_enr).nil?
1940
+ eventK = event.to_hash.keys
1941
+ #CHECK RULE BY RULE
1942
+ no_match = true
1943
+ for f_rule in @freq_rules
1944
+ f_rule.each do |fkey,fval|
1945
+ #VERIFY FIELD by FIELD if present and value match
1946
+ no_match = true
1947
+ if not event.get(fkey.to_s).nil? and fval.include?(event.get(fkey.to_s))
1948
+ no_match = false
1949
+ end
1950
+ break if no_match
1951
+ end
1952
+ # if rule no match then next
1953
+ next if no_match
1954
+ # if rule match increment count
1955
+ if @db_freq[f_rule['id']]
1956
+ #incrimente count
1957
+ @db_freq[f_rule['id']]['count_cour'] = @db_freq[f_rule['id']]['count_cour'] + 1
1958
+ #check if time to calculate varia & freq
1959
+ #check if first time to check
1960
+ if ( @db_freq[f_rule['id']]['num_time'] == 0 and @db_freq[f_rule['id']]['status_acces'] == true ) or ( @db_freq[f_rule['id']]['reset_time'] <= tnow and @db_freq[f_rule['id']]['status_acces'] == true )
1961
+ #first time
1962
+ @db_freq[f_rule['id']]['status_acces'] = false
1963
+ #init old_date & refresh date
1964
+ @db_freq[f_rule['id']]['reset_time'] = tnow + f_rule['reset_time']
1965
+ @db_freq[f_rule['id']]['old_date'] = tnow
1966
+ @db_freq[f_rule['id']]['refresh_date'] = tnow + f_rule['refresh_time']
1967
+ @db_freq[f_rule['id']]['count_prev'] = @db_freq[f_rule['id']]['count_cour']
1968
+ @db_freq[f_rule['id']]['status_acces']['v_max']=0
1969
+ @db_freq[f_rule['id']]['status_acces']['varia_min']=10000
1970
+ @db_freq[f_rule['id']]['status_acces']['varia_max']=0
1971
+ @db_freq[f_rule['id']]['v_prev'] = 1
1972
+ @db_freq[f_rule['id']]['varia_glob'] = 0
1973
+ @db_freq[f_rule['id']]['num_time'] = 1
1974
+ @db_freq[f_rule['id']]['status_acces'] = true
1975
+ elsif @db_freq[f_rule['id']]['num_time'] != 0
1976
+ if @db_freq[f_rule['id']]['refresh_date'] <= tnow and @db_freq[f_rule['id']]['status_acces'] == true
1977
+ @db_freq[f_rule['id']]['status_acces'] = false
1978
+ #time to re-calculate
1979
+ # put all in same unit => 60s
1980
+ #calculate diff between ald date and new date
1981
+ diff_time = tnow - @db_freq[f_rule['id']]['old_date'] #in seconds
1982
+ #reinit old_date & refresh date
1983
+ @db_freq[f_rule['id']]['old_date'] = tnow
1984
+ @db_freq[f_rule['id']]['refresh_date'] = tnow + f_rule['refresh_time']
1985
+ #calculate diff between previous count and count courant
1986
+ count_diff = @db_freq[f_rule['id']]['count_cour'] - @db_freq[f_rule['id']]['count_prev']
1987
+ #reinit count_previous
1988
+ @db_freq[f_rule['id']]['count_prev'] = @db_freq[f_rule['id']]['count_cour']
1989
+ #calculate v
1990
+ v_cour = (((count_diff / diff_time)*60)+0.5).to_i # vcour/60s to interger
1991
+ #check v_max
1992
+ if @db_freq[f_rule['id']]['v_max'] < v_cour
1993
+ @db_freq[f_rule['id']]['v_max'] = v_cour
1994
+ #CREATE ALERT
1995
+ end
1996
+ #cacl varia
1997
+ varia_cour = v_cour - db_freq[f_rule['id']]['v_prev']
1998
+ #reinit v_prev
1999
+ db_freq[f_rule['id']]['v_prev'] = v_cour
2000
+ #incriment varia_glob
2001
+ db_freq[f_rule['id']]['varia_glob'] = db_freq[f_rule['id']]['varia_glob'] + varia_cour.abs
2002
+ #check varia_max & varia_min
2003
+ if @db_freq[f_rule['id']]['varia_max'] < varia_cour
2004
+ #CREATE ALERT
2005
+ if f_rule['wait_after_reset'] < @db_freq[f_rule['id']]['num_time']
2006
+ new_event = LogStash::Event.new
2007
+ new_event.set("message", "ALERT FREQ -- rule id:" + f_rule['id'].to_s + " -- count " + v_cour.to_s + "events for 60s -- VARIA : " + varia_cour.to_s + "(varia courant) -- The value change old varia max: " + @db_freq[f_rule['id']]['varia_max'])
2008
+ new_event.set("type", "alert_freq")
2009
+ new_event.set("ruleid", f_rule['id'].to_s)
2010
+ new_event.set("time", tnow.to_s)
2011
+ end
2012
+ @db_freq[f_rule['id']]['varia_max'] = varia_cour
2013
+ end
2014
+ if @db_freq[f_rule['id']]['varia_min'] > varia_cour
2015
+ #CREATE ALERT
2016
+ if f_rule['wait_after_reset'] < @db_freq[f_rule['id']]['num_time']
2017
+ new_event = LogStash::Event.new
2018
+ new_event.set("message", "ALERT FREQ -- rule id:" + f_rule['id'].to_s + " -- count " + v_cour.to_s + "events for 60s -- VARIA : " + varia_cour.to_s + "(varia courant) -- The value change old varia min: " + @db_freq[f_rule['id']]['varia_min'])
2019
+ new_event.set("type", "alert_freq")
2020
+ new_event.set("ruleid", f_rule['id'].to_s)
2021
+ new_event.set("time", tnow.to_s)
2022
+ end
2023
+ db_freq[f_rule['id']]['varia_min'] = varia_cour
2024
+ end
2025
+ #calculate varia_avg
2026
+ @db_freq[f_rule['id']]['varia_avg'] = db_freq[f_rule['id']]['varia_glob'] / @db_freq[f_rule['id']]['num_time']
2027
+ #incremente num time of calculate
2028
+ @db_freq[f_rule['id']]['num_time'] = @db_freq[f_rule['id']]['num_time'] + 1
2029
+ #check if varia is more than v_cour
2030
+ if varia_cour > @db_freq[f_rule['id']]['varia_avg']
2031
+ #CREATE ALERT
2032
+ if f_rule['wait_after_reset'] < @db_freq[f_rule['id']]['num_time']
2033
+ new_event = LogStash::Event.new
2034
+ new_event.set("message", "ALERT FREQ -- rule id:" + f_rule['id'].to_s + " -- count " + v_cour.to_s + "events for 60s -- VARIA morest : " + varia_cour.to_s + "(varia courant) > " + @db_freq[f_rule['id']]['varia_avg'].to_s + "(varia global)")
2035
+ new_event.set("type", "alert_freq")
2036
+ new_event.set("ruleid", f_rule['id'].to_s)
2037
+ new_event.set("time", tnow.to_s)
2038
+ end
2039
+ end
2040
+ @db_freq[f_rule['id']]['status_acces'] = true
2041
+ end
2042
+ end
2043
+ end
2044
+ end
2045
+ end
2046
+ ##### NOT CREATE ALERTE ON EVENT BECAUSE EVENT MAYBE NOT ORIGIN FREQ INCREASE ###
2047
+ ######################
2048
+
2049
+ filter_matched(event)
2050
+ end
2051
+ ########## LOAD/REFRESH/SAVE CONF & DB ################
2052
+ private
2053
+ def load_rules_freq
2054
+ if !File.exists?(@conf_freq)
2055
+ @logger.warn("DB file read failure, stop loading", :path => @conf_freq)
2056
+ exit -1
2057
+ end
2058
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_freq
2059
+ if not tmp_hash == @hash_conf_freq
2060
+ @hash_conf_freq = tmp_hash
2061
+ begin
2062
+ tmp_db = JSON.parse( IO.read(@conf_freq, encoding:'utf-8') )
2063
+ unless tmp_db.nil?
2064
+ if tmp_db['rules'].is_a?(Array)
2065
+ @freq_rules = tmp_db['rules']
2066
+ #CREATE DB with ID
2067
+ for rulex in @freq_rules
2068
+ if @db_freq[rulex['id']].nil?
2069
+ @db_freq[rulex['id']]={}
2070
+ @db_freq[rulex['id']]['num_time']=0
2071
+ @db_freq[rulex['id']]['count_cour']=0
2072
+ @db_freq[rulex['id']]['reset_time']=0
2073
+ @db_freq[rulex['id']]['status_acces']=true
2074
+ end
2075
+ end
2076
+ end
2077
+ end
2078
+ @logger.info("loading/refreshing REFERENCES conf rules")
2079
+ rescue
2080
+ @logger.error("JSON CONF SIG -- FREQ RULES-- PARSE ERROR")
2081
+ end
2082
+ end
2083
+ end
2084
+ def load_db_pattern
2085
+ if !File.exists?(@db_pattern)
2086
+ @logger.warn("DB file read failure, stop loading", :path => @db_pattern)
2087
+ exit -1
2088
+ end
2089
+ tmp_hash = Digest::SHA256.hexdigest File.read @db_pattern
2090
+ if not tmp_hash == @hash_dbpattern
2091
+ @hash_dbpattern = tmp_hash
2092
+ File.readlines(@db_pattern).each do |line|
2093
+ elem1, elem2 = line.split(/=>>/)
2094
+ elem2.delete!("\n")
2095
+ @pattern_db[elem1] = elem2
2096
+ end
2097
+ end
2098
+ end
2099
+ def load_db_ref
2100
+ if !File.exists?(@db_ref)
2101
+ @logger.warn("DB file read failure, stop loading", :path => @db_ref)
2102
+ exit -1
2103
+ end
2104
+ tmp_hash = Digest::SHA256.hexdigest File.read @db_ref
2105
+ if not tmp_hash == @hash_dbref
2106
+ @hash_dbref = tmp_hash
2107
+ begin
2108
+ tmp_db = JSON.parse( IO.read(@db_ref, encoding:'utf-8') )
2109
+ unless tmp_db.nil?
2110
+ @ref_db = tmp_db
2111
+ end
2112
+ @logger.info("loading/refreshing REFERENCES DB")
2113
+ rescue
2114
+ end
2115
+ end
2116
+ #CONF
2117
+ if !File.exists?(@conf_ref)
2118
+ @logger.warn("DB file read failure, stop loading", :path => @conf_ref)
2119
+ exit -1
2120
+ end
2121
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_ref
2122
+ if not tmp_hash == @hash_conf_ref
2123
+ @hash_conf_ref = tmp_hash
2124
+ begin
2125
+ tmp_db = JSON.parse( IO.read(@conf_ref, encoding:'utf-8') )
2126
+ unless tmp_db.nil?
2127
+ unless tmp_db['rules'].nil?
2128
+ if tmp_db['rules'].is_a?(Array)
2129
+ @ref_rules= tmp_db['rules']
2130
+ end
2131
+ end
2132
+ end
2133
+ @logger.info("loading/refreshing REFERENCES conf rules")
2134
+ rescue
2135
+ @logger.error("JSON CONF SIG -- DB REF -- PARSE ERROR")
2136
+ end
2137
+ end
2138
+ end
2139
+ def load_conf_bl
2140
+ #load file
2141
+ for f in @file_bl
2142
+ if !File.exists?(f)
2143
+ @logger.warn("DB file read failure, stop loading", :path => f)
2144
+ exit -1
2145
+ end
2146
+ tmp_hash = Digest::SHA256.hexdigest File.read f
2147
+ if @hash_dbbl[f]
2148
+ if not tmp_hash == @hash_dbioc[f]
2149
+ #change
2150
+ @bl_db[File.basename(f)].clear
2151
+ @hash_dbbl[f] = tmp_hash
2152
+ File.readlines(f).each do |line|
2153
+ line=line.strip
2154
+ ip = ""
2155
+ @bl_db[File.basename(f)].push(ip) if ip = IPAddr.new(line) rescue false
2156
+ end
2157
+ end
2158
+ else
2159
+ #unknown
2160
+ @bl_db[File.basename(f)] = []
2161
+ @hash_dbbl[f] = tmp_hash
2162
+ File.readlines(f).each do |line|
2163
+ line=line.strip
2164
+ ip = ""
2165
+ @bl_db[File.basename(f)].push(ip) if ip = IPAddr.new(line) rescue false
2166
+ end
2167
+ end
2168
+ @logger.info("loading/refreshing DB BL REPUTATION file(s): #{File.basename(f)}")
2169
+ end
2170
+ #load conf
2171
+ if !File.exists?(@conf_bl)
2172
+ @logger.warn("DB file read failure, stop loading", :path => @conf_bl)
2173
+ exit -1
2174
+ end
2175
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_bl
2176
+ if not tmp_hash == @hash_conf_bl
2177
+ @hash_conf_bl = tmp_hash
2178
+ begin
2179
+ tmp_db = JSON.parse( IO.read(@conf_bl, encoding:'utf-8') )
2180
+ unless tmp_db.nil?
2181
+ #{fieldx: {dbs: [file_name,...], catergory: , note: X, id: X}}
2182
+ #verify dbs filename exist
2183
+ tmp_db.each do |fkey,fval|
2184
+ if fval['dbs'].is_a?(Array)
2185
+ for fn in fval['dbs']
2186
+ if @bl_db[fn].nil?
2187
+ @logger.error("You use a file name not exist in conf BL REPUTATION!!!")
2188
+ exit -1
2189
+ end
2190
+ end
2191
+ else
2192
+ @logger.error("DBS field not exist in JSON conf BL REPUTATION!!")
2193
+ exit -1
2194
+ end
2195
+ end
2196
+ @bl_rules = tmp_db
2197
+ end
2198
+ @logger.info("loading/refreshing Conf BL REPUTATION #{@bl_db}")
2199
+ rescue
2200
+ @logger.error("JSON CONF SIG -- CONF BL -- PARSE ERROR")
2201
+ end
2202
+ end
2203
+ end
2204
+
2205
+ def load_conf_rules_sig
2206
+ if !File.exists?(@conf_rules_sig)
2207
+ @logger.warn("DB file read failure, stop loading", :path => @conf_rules_sig)
2208
+ exit -1
2209
+ end
2210
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_rules_sig
2211
+ if not tmp_hash == @hash_conf_rules_sig
2212
+ @hash_conf_rules_sig = tmp_hash
2213
+ begin
2214
+ @sig_db = JSON.parse( IO.read(@conf_rules_sig, encoding:'utf-8') )
2215
+ @sig_db_array.clear
2216
+ @sig_db_array_false.clear
2217
+ keyF = Array.new
2218
+ keyT = Array.new
2219
+ #order sig_db by type (1 or 2)
2220
+ if @sig_db['rules'].is_a?(Array)
2221
+ tmp = *@sig_db['rules']
2222
+ j=0
2223
+ (0..@sig_db['rules'].length-1).each do |i|
2224
+ @sig_db['rules'][i].each do |nkey,nval|
2225
+ if nval['type'].is_a?(Numeric)
2226
+ if nval['type'] == 2
2227
+ #puts 'find at'+i.to_s+' -> '+j.to_s+' -- '+tmp[i-j].to_s
2228
+ tmp=tmp.insert(-1,tmp.delete_at(i-j))
2229
+ j=j+1
2230
+ break
2231
+ end
2232
+ end
2233
+ end
2234
+ end
2235
+ #create Field True & false
2236
+ @sig_db['rules'] = *tmp
2237
+ for rule in tmp
2238
+ keyF.clear
2239
+ keyT.clear
2240
+ rule.each do |nkey,nval|
2241
+ if nval.has_key?('false')
2242
+ keyF.push(nkey)
2243
+ else
2244
+ keyT.push(nkey)
2245
+ end
2246
+ end
2247
+ @sig_db_array.push([*keyT])
2248
+ @sig_db_array_false.push([*keyF])
2249
+ @sig_db_array_len=@sig_db_array.length-1
2250
+ end
2251
+ keyF.clear
2252
+ keyT.clear
2253
+ end
2254
+ @logger.info("loading/refreshing SIG conf rules")
2255
+ rescue
2256
+ @logger.error("JSON CONF SIG -- SIG RULES -- PARSE ERROR")
2257
+ end
2258
+ end
2259
+ end
2260
+ def load_conf_rules_note
2261
+ if !File.exists?(@conf_rules_note)
2262
+ @logger.warn("DB file read failure, stop loading", :path => @conf_rules_note)
2263
+ exit -1
2264
+ end
2265
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_rules_note
2266
+ if not tmp_hash == @hash_conf_rules_note
2267
+ @hash_conf_rules_note = tmp_hash
2268
+ begin
2269
+ tmp_db = JSON.parse( IO.read(@conf_rules_note, encoding:'utf-8') )
2270
+ unless tmp_db.nil?
2271
+ unless tmp_db['rules'].nil?
2272
+ if tmp_db['rules'].is_a?(Array)
2273
+ @note_db = tmp_db['rules']
2274
+ end
2275
+ end
2276
+ end
2277
+ @logger.info("loading/refreshing NOTE conf rules")
2278
+ rescue
2279
+ @logger.error("JSON CONF SIG -- NOTE/SCORE RULES -- PARSE ERROR")
2280
+ end
2281
+ end
2282
+ end
2283
+ def load_conf_ioc
2284
+ if !File.exists?(@conf_ioc)
2285
+ @logger.warn("DB file read failure, stop loading", :path => @conf_ioc)
2286
+ exit -1
2287
+ end
2288
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_ioc
2289
+ if not tmp_hash == @hash_conf_ioc
2290
+ @hash_conf_ioc = tmp_hash
2291
+ begin
2292
+ tmp_db = JSON.parse( IO.read(@conf_ioc, encoding:'utf-8') )
2293
+ @ioc_rules = tmp_db
2294
+ @logger.info("loading/refreshing IOC conf rules")
2295
+ rescue
2296
+ @logger.error("JSON CONF SIG -- IOC DB -- PARSE ERROR")
2297
+ end
2298
+ end
2299
+ end
2300
+ def load_db_ioc
2301
+ #if one file change reload all file
2302
+ change = false
2303
+ @db_ioc.sort.each do |f|
2304
+ if !File.exists?(f)
2305
+ @logger.warn("DB file read failure, stop loading", :path => f)
2306
+ exit -1
2307
+ end
2308
+ tmp_hash = Digest::SHA256.hexdigest File.read f
2309
+ if @hash_dbioc[f]
2310
+ if not tmp_hash == @hash_dbioc[f]
2311
+ #load
2312
+ @hash_dbioc[f] = tmp_hash
2313
+ change = true
2314
+ end
2315
+ else
2316
+ #load
2317
+ @hash_dbioc[f] = tmp_hash
2318
+ change = true
2319
+ end
2320
+ end
2321
+ if change == true
2322
+ @ioc_db = {}
2323
+ @db_ioc.sort.each do |f|
2324
+ begin
2325
+ db_tmp = JSON.parse( IO.read(f, encoding:'utf-8') )
2326
+ @ioc_db = @ioc_db.merge(db_tmp) {|key, first, second| first.is_a?(Array) && second.is_a?(Array) ? first | second : second }
2327
+ rescue
2328
+ @logger.error("JSON CONF SIG -- IOC DB -- PARSE ERROR")
2329
+ end
2330
+ end
2331
+ @logger.info("loading/refreshing DB IOC file(s)")
2332
+ end
2333
+ end
2334
+ def load_conf_nv
2335
+ if !File.exists?(@conf_nv)
2336
+ @logger.warn("DB file read failure, stop loading", :path => @conf_nv)
2337
+ exit -1
2338
+ end
2339
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_nv
2340
+ if not tmp_hash == @hash_conf_nv
2341
+ @hash_conf_nv = tmp_hash
2342
+ begin
2343
+ tmp_db = JSON.parse( IO.read(@conf_nv, encoding:'utf-8') )
2344
+ @nv_rules = tmp_db
2345
+ if @nv_rules['rules']
2346
+ for rule in @nv_rules['rules']
2347
+ if not @nv_db[rule.to_s]
2348
+ @nv_db[rule.to_s] = []
2349
+ end
2350
+ end
2351
+ end
2352
+ @logger.info("refreshing DB NewValue file")
2353
+ rescue
2354
+ @logger.error("JSON CONF SIG -- CONF NV -- PARSE ERROR")
2355
+ end
2356
+ end
2357
+ end
2358
+ def save_db_nv
2359
+ begin
2360
+ File.open(@db_nv,"w+") do |f|
2361
+ f.write(JSON.pretty_generate(@nv_db))
2362
+ end
2363
+ rescue
2364
+ @logger.error("JSON SAVE SIG -- SAVE NV-- PARSE/WRITE ERROR")
2365
+ end
2366
+ end
2367
+ def save_db_ioclocal
2368
+ begin
2369
+ File.open(@file_save_localioc,"w+") do |f|
2370
+ f.write(JSON.pretty_generate(@ioc_db_local))
2371
+ end
2372
+ rescue
2373
+ @logger.error("JSON SAVE SIG -- SAVE IOC LOCAL -- PARSE/WRITE ERROR")
2374
+ end
2375
+ end
2376
+
2377
+ def load_db_enr
2378
+ if !File.exists?(@conf_enr)
2379
+ @logger.warn("DB file read failure, stop loading", :path => @conf_enr)
2380
+ exit -1
2381
+ end
2382
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_enr
2383
+ if not tmp_hash == @hash_conf_enr
2384
+ @hash_conf_enr = tmp_hash
2385
+ begin
2386
+ tmp_db = JSON.parse( IO.read(@conf_enr, encoding:'utf-8') )
2387
+ @db_enr = tmp_db
2388
+ #open all db file
2389
+ @db_enr.each do |ekey,eval|
2390
+ ofile=eval["file"]
2391
+ if !File.exists?(ofile)
2392
+ @logger.warn("DB file read failure, stop loading", :path => ofile)
2393
+ exit -1
2394
+ end
2395
+ tmp_hash = Digest::SHA256.hexdigest File.read ofile
2396
+ if not tmp_hash == @hash_dbfile_enr[ofile]
2397
+ @hash_dbfile_enr[ofile] = tmp_hash
2398
+ @db_enr[ekey]["db"] = JSON.parse( IO.read(ofile, encoding:'utf-8') )
2399
+ sha1db=Digest::SHA1.hexdigest @db_enr[ekey]["db"].to_s
2400
+ @hash_db_enr[ofile] = sha1db
2401
+ end
2402
+ end
2403
+ rescue
2404
+ @logger.error("JSON CONF SIG -- DB ENR -- PARSE ERROR")
2405
+ end
2406
+ end
2407
+ end
2408
+ def save_dbs_enr
2409
+ #load db conf fp
2410
+ @db_enr.each do |ekey,eval|
2411
+ ofile=eval["file"]
2412
+ if !File.exists?(ofile)
2413
+ @logger.warn("DB file read failure, stop loading", :path => ofile)
2414
+ exit -1
2415
+ end
2416
+ tmp_sha1db = Digest::SHA1.hexdigest @db_enr[ekey]["db"].to_s
2417
+ if not tmp_sha1db == @hash_db_enr[ofile]
2418
+ File.open(ofile,"w+") do |f|
2419
+ begin
2420
+ f.write(JSON.pretty_generate(@db_enr[ekey]["db"]))
2421
+ rescue
2422
+ @logger.error("JSON SAVE SIG -- SAVE ENR -- PARSE/WRITE ERROR")
2423
+ end
2424
+ end
2425
+ @hash_db_enr[ofile] = tmp_sha1db
2426
+ tmp_hash = Digest::SHA256.hexdigest File.read ofile
2427
+ @hash_dbfile_enr[ofile] = tmp_hash
2428
+ end
2429
+ end
2430
+ =begin
2431
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_enr
2432
+ if not tmp_hash == @hash_conf_enr
2433
+ @hash_conf_enr = tmp_hash
2434
+ db_enr_tmp = JSON.parse( IO.read(@conf_enr, encoding:'utf-8') )
2435
+ #TODO verify if it works
2436
+ @db_enr=@db_enr.deep_merge(db_enr_tmp)
2437
+ File.open(@conf_enr,"w+") do |f|
2438
+ f.write(JSON.pretty_generate(@db_enr))
2439
+ end
2440
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_enr
2441
+ @hash_conf_enr = tmp_hash
2442
+ else
2443
+ File.open(@conf_enr,"w+") do |f|
2444
+ f.write(JSON.pretty_generate(@db_enr))
2445
+ end
2446
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_enr
2447
+ @hash_conf_enr = tmp_hash
2448
+ end
2449
+ =end
2450
+ end
2451
+
2452
+ def load_conf_fp
2453
+ #load db conf fp
2454
+ if !File.exists?(@conf_fp)
2455
+ @logger.warn("DB file read failure, stop loading", :path => @conf_fp)
2456
+ exit -1
2457
+ end
2458
+ tmp_hash = Digest::SHA256.hexdigest File.read @conf_fp
2459
+ if not tmp_hash == @hash_conf_fp
2460
+ @hash_conf_fp = tmp_hash
2461
+ begin
2462
+ tmp_db = JSON.parse( IO.read(@conf_fp, encoding:'utf-8') )
2463
+ @fp_rules = tmp_db
2464
+ rescue
2465
+ @logger.error("JSON CONF SIG -- CONF FP -- PARSE ERROR")
2466
+ end
2467
+ end
2468
+ end
2469
+ def load_db_dropfp
2470
+ #load fp
2471
+ if !File.exists?(@db_dropfp)
2472
+ @logger.warn("DB file read failure, stop loading", :path => @db_dropfp)
2473
+ exit -1
2474
+ end
2475
+ tmp_hash = Digest::SHA256.hexdigest File.read @db_dropfp
2476
+ if not tmp_hash == @hash_dropfp
2477
+ @hash_dropfp = tmp_hash
2478
+ begin
2479
+ tmp_db = JSON.parse( IO.read(@db_dropfp, encoding:'utf-8') )
2480
+ @fp_db = tmp_db
2481
+ rescue
2482
+ @logger.error("JSON CONF SIG -- DROPFP -- PARSE ERROR")
2483
+ end
2484
+ end
2485
+ end
2486
+ def load_db_drop
2487
+ #load drop db
2488
+ if !File.exists?(@db_drop)
2489
+ @logger.warn("DB file read failure, stop loading", :path => @db_drop)
2490
+ exit -1
2491
+ end
2492
+ tmp_hash = Digest::SHA256.hexdigest File.read @db_drop
2493
+ if not tmp_hash == @hash_dropdb
2494
+ @hash_dropdb = tmp_hash
2495
+ begin
2496
+ tmp_db = JSON.parse( IO.read(@db_drop, encoding:'utf-8') )
2497
+ @drop_db = tmp_db
2498
+ rescue
2499
+ @logger.error("JSON CONF SIG -- DROPDB -- PARSE ERROR")
2500
+ end
2501
+ end
2502
+ end
2503
+ #clean db special
2504
+ def clean_db_sigfreq(date)
2505
+ @sig_db_freq.each do |nkey,nval|
2506
+ if nval[delay] < date
2507
+ @sig_db_freq.delete(nkey)
2508
+ end
2509
+ end
2510
+ end
2511
+ end