Skip to content

Commit 8e71e5e

Browse files
committed
feat(suricata): enhance logstash filter for Suricata event types and actions
1 parent b9ec9bf commit 8e71e5e

1 file changed

Lines changed: 378 additions & 1 deletion

File tree

backend/src/main/resources/config/liquibase/changelog/20250814001_adding_suricata.xml

Lines changed: 378 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,384 @@
164164
<sql dbms="postgresql" splitStatements="true" stripComments="true">
165165
<![CDATA[
166166
INSERT INTO utm_logstash_filter (id, logstash_filter, filter_name, filter_group_id, system_owner, module_name, is_active, filter_version)
167-
VALUES (1528, '', 'suricata', null, true, 'SURICATA', false, '2.0.0');
167+
VALUES (1528, 'filter {
168+
169+
# Suricata filter version 1.0.0
170+
# Based on https://suricata.readthedocs.io/en/latest/output/eve/eve-json-format.html (latest 8.0.0) (august 2025)
171+
# and real events log provided
172+
# Support json format
173+
split {
174+
field => "message"
175+
terminator => "<utm-log-separator>"
176+
}
177+
178+
#Looking for datasource generated by an agent and parse original message
179+
if [message]=~/\[utm_stack_agent_ds=(.+)\]-(.+)/ {
180+
grok {
181+
match => {
182+
"message" => [ "\[utm_stack_agent_ds=%{DATA:dataSource}\]-%{GREEDYDATA:original_log_message}" ]
183+
}
184+
}
185+
}
186+
if [original_log_message] {
187+
mutate {
188+
update => { "message" => "%{[original_log_message]}" }
189+
}
190+
}
191+
192+
if ![dataType] {
193+
if [path] and [path] == "/var/log/suricata/eve.json" {
194+
if [message] {
195+
json { source => "message" }
196+
}
197+
if [event_type] and ([event_type] == "anomaly" or [event_type] == "tls" or [event_type] == "flow"
198+
or [event_type] == "alert" or [event_type] == "dns" or [event_type] == "ssh"
199+
or [event_type] == "http" or [event_type] == "ftp" or [event_type] == "ftp_data"
200+
or [event_type] == "tftp" or [event_type] == "smb" or [event_type] == "initial_request"
201+
or [event_type] == "initial_response" or [event_type] == "connect_request" or [event_type] == "connect_response"
202+
or [event_type] == "tls_handshake" or [rdp] or [event_type] == "rfb" or [event_type] == "mqtt"
203+
or [event_type] == "http2" or [event_type] == "pgsql" or [event_type] == "ike"
204+
or [event_type] == "ikev1" or [event_type] == "ikev2"
205+
or [event_type] == "modbus" or [event_type] == "quic" or [event_type] == "snmp"
206+
or [event_type] == "fileinfo" or [event_type] == "sip" or [event_type] == "dhcp") {
207+
mutate {
208+
rename => ["dest_ip", "[logx][suricata][dest_ip]"]
209+
rename => ["dest_port", "[logx][suricata][dest_port]"]
210+
rename => ["flow_id", "[logx][suricata][flow_id]"]
211+
rename => ["host", "[logx][suricata][host]"]
212+
rename => ["in_iface", "[logx][suricata][in_iface]"]
213+
rename => ["proto", "[logx][suricata][proto]"]
214+
rename => ["src_ip", "[logx][suricata][src_ip]"]
215+
rename => ["src_port", "[logx][suricata][src_port]"]
216+
rename => ["tx_id", "[logx][suricata][tx_id]"]
217+
}
218+
}
219+
if (![dataSource]){
220+
mutate {
221+
add_field => { "dataSource" => "%{host}" }
222+
}
223+
}
224+
225+
mutate {
226+
add_field => {
227+
"dataType" => "suricata"
228+
}
229+
remove_field => [ "timestamp", "type", "path"]
230+
rename => ["event_type", "[logx][suricata][event_type]"]
231+
}
232+
if [tls] {
233+
mutate {
234+
rename => ["tls", "[logx][suricata][tls]"]
235+
}
236+
}
237+
if [ssh] {
238+
mutate {
239+
rename => ["ssh", "[logx][suricata][ssh]"]
240+
}
241+
}
242+
if [stats] {
243+
mutate {
244+
rename => ["stats", "[logx][suricata][stats]"]
245+
}
246+
}
247+
if [flow] {
248+
mutate {
249+
rename => ["flow", "[logx][suricata][flow]"]
250+
}
251+
}
252+
if [tcp] {
253+
mutate {
254+
rename => ["tcp", "[logx][suricata][tcp]"]
255+
}
256+
}
257+
if [dns] {
258+
mutate {
259+
rename => ["dns", "[logx][suricata][dns]"]
260+
}
261+
}
262+
if [app_proto] {
263+
mutate {
264+
rename => ["app_proto", "[logx][suricata][app_proto]"]
265+
}
266+
}
267+
if [anomaly] {
268+
mutate {
269+
rename => ["anomaly", "[logx][suricata][anomaly]"]
270+
}
271+
}
272+
if [alert] {
273+
mutate {
274+
rename => ["alert", "[logx][suricata][alert]"]
275+
}
276+
if [logx][suricata][alert][severity] {
277+
if [logx][suricata][alert][severity] >= 3 {
278+
mutate {
279+
add_field => {
280+
"[logx][suricata][severity_label]" => "Low"
281+
"[logx][suricata][severity]" => 1
282+
}
283+
}
284+
}
285+
if [logx][suricata][alert][severity] == 2 {
286+
mutate {
287+
add_field => {
288+
"[logx][suricata][severity_label]" => "Medium"
289+
"[logx][suricata][severity]" => 2
290+
}
291+
}
292+
}
293+
if [logx][suricata][alert][severity] == 1 {
294+
mutate {
295+
add_field => {
296+
"[logx][suricata][severity_label]" => "High"
297+
"[logx][suricata][severity]" => 3
298+
}
299+
}
300+
}
301+
mutate {
302+
remove_field => [ "[logx][suricata][alert][severity]" ]
303+
}
304+
}
305+
}
306+
#.......................................................................
307+
# Add new event_types to logx structure, detected in real logs, present in suricata 7.0.0
308+
309+
mutate {
310+
rename => ["http", "[logx][suricata][http]"]
311+
rename => ["ftp", "[logx][suricata][ftp]"]
312+
rename => ["ftp_data", "[logx][suricata][ftp_data]"]
313+
rename => ["tftp", "[logx][suricata][tftp]"]
314+
rename => ["smb", "[logx][suricata][smb]"]
315+
316+
# RDP event_type
317+
rename => ["rdp", "[logx][suricata][rdp]"]
318+
# End RDP event_type
319+
320+
rename => ["rfb", "[logx][suricata][rfb]"]
321+
rename => ["mqtt", "[logx][suricata][mqtt]"]
322+
rename => ["http2", "[logx][suricata][http2]"]
323+
rename => ["pgsql", "[logx][suricata][pgsql]"]
324+
rename => ["ike", "[logx][suricata][ike]"]
325+
rename => ["ikev1", "[logx][suricata][ike]"]
326+
rename => ["ikev2", "[logx][suricata][ike]"]
327+
rename => ["modbus", "[logx][suricata][modbus]"]
328+
rename => ["quic", "[logx][suricata][quic]"]
329+
330+
# New fields from real logs, not present in suricata docs
331+
rename => ["snmp", "[logx][suricata][snmp]"]
332+
rename => ["fileinfo", "[logx][suricata][fileinfo]"]
333+
rename => ["sip", "[logx][suricata][sip]"]
334+
rename => ["dhcp", "[logx][suricata][dhcp]"]
335+
336+
# This field isnt an event_type but appear in alert real logs
337+
rename => ["files", "[logx][suricata][alert][files]"]
338+
}
339+
340+
#.......................................................................
341+
# Add fields to logx structure, detected outside th event_type, present in suricata 7.0.0
342+
if [logx][suricata][event_type] == "mqtt" {
343+
mutate {
344+
rename => ["pcap_cnt", "[logx][suricata][mqtt][pcap_cnt]"]
345+
}
346+
} else if [logx][suricata][event_type] == "pgsql" {
347+
mutate {
348+
rename => ["pcap_cnt", "[logx][suricata][pgsql][pcap_cnt]"]
349+
}
350+
} else if [logx][suricata][event_type] == "fileinfo" {
351+
if [logx][suricata][http] {
352+
mutate {
353+
rename => ["fileinfo", "[logx][suricata][http][fileinfo]"]
354+
}
355+
} else if [logx][suricata][http2] {
356+
mutate {
357+
rename => ["fileinfo", "[logx][suricata][http2][fileinfo]"]
358+
}
359+
} else {
360+
mutate {
361+
rename => ["fileinfo", "[logx][suricata][fileinfo]"]
362+
}
363+
}
364+
} else if [logx][suricata][event_type] == "anomaly" {
365+
mutate {
366+
rename => ["pcap_cnt", "[logx][suricata][anomaly][pcap_cnt]"]
367+
rename => ["packet", "[logx][suricata][anomaly][packet]"]
368+
rename => ["packet_info", "[logx][suricata][anomaly][packet_info]"]
369+
}
370+
} else if [logx][suricata][event_type] == "flow" {
371+
mutate {
372+
rename => ["icmp_type", "[logx][suricata][flow][icmp_type]"]
373+
rename => ["icmp_code", "[logx][suricata][flow][icmp_code]"]
374+
rename => ["response_icmp_code", "[logx][suricata][flow][response_icmp_code]"]
375+
rename => ["response_icmp_type", "[logx][suricata][flow][response_icmp_type]"]
376+
}
377+
}
378+
379+
#.......................................................................
380+
# Implementing logx.utm.action field used for established connections
381+
if [logx][suricata][event_type] == "tls" {
382+
if ![logx][suricata][tls][session_resumed] {
383+
mutate {
384+
add_field => { "[logx][utm][action]" => "Success" }
385+
}
386+
}
387+
} else if [logx][suricata][event_type] == "dns" {
388+
if [logx][suricata][dns][type] and [logx][suricata][dns][type] == "answer" {
389+
mutate {
390+
add_field => { "[logx][utm][action]" => "Success" }
391+
}
392+
}
393+
} else if [logx][suricata][event_type] == "flow" {
394+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
395+
([logx][suricata][flow][bytes_toserver] and [logx][suricata][flow][bytes_toserver] > 0) and
396+
([logx][suricata][flow][bytes_toclient] and [logx][suricata][flow][bytes_toclient] > 0) {
397+
mutate {
398+
add_field => { "[logx][utm][action]" => "Success" }
399+
}
400+
}
401+
} else if [logx][suricata][event_type] == "ssh" {
402+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
403+
[logx][suricata][ssh][server] and [logx][suricata][ssh][client] {
404+
mutate {
405+
add_field => { "[logx][utm][action]" => "Success" }
406+
}
407+
}
408+
} else if [logx][suricata][event_type] == "alert" {
409+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and [logx][suricata][alert][action] == "allowed" and
410+
([logx][suricata][flow][bytes_toserver] and [logx][suricata][flow][bytes_toserver] > 0) and
411+
([logx][suricata][flow][bytes_toclient] and [logx][suricata][flow][bytes_toclient] > 0) {
412+
mutate {
413+
add_field => { "[logx][utm][action]" => "Success" }
414+
}
415+
}
416+
} else if [logx][suricata][event_type] == "http" {
417+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and [logx][suricata][http][status] {
418+
mutate {
419+
add_field => { "[logx][utm][action]" => "Success" }
420+
}
421+
}
422+
} else if [logx][suricata][event_type] == "ftp" {
423+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and [logx][suricata][ftp][completion_code] {
424+
ruby {
425+
code => "
426+
event.get(''[logx][suricata][ftp][completion_code]'').each_with_index do |value,key|
427+
if value =~ /(2\d\d)|(125)/
428+
event.set(''[logx][utm][action]'', ''Success'')
429+
end
430+
end
431+
"
432+
}
433+
}
434+
} else if [logx][suricata][event_type] == "tftp" {
435+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
436+
([logx][suricata][tftp][packet] and [logx][suricata][tftp][packet] != "error") {
437+
mutate {
438+
add_field => { "[logx][utm][action]" => "Success" }
439+
}
440+
}
441+
} else if [logx][suricata][event_type] == "smb" {
442+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
443+
( [logx][suricata][smb][command] and "NEGOTIATE" in [logx][suricata][smb][command] ) and
444+
[logx][suricata][smb][status] and ( "SUCCESS" in [logx][suricata][smb][status] or
445+
"GRANTED" in [logx][suricata][smb][status] or "CONNECTED" in [logx][suricata][smb][status]) {
446+
mutate {
447+
add_field => { "[logx][utm][action]" => "Success" }
448+
}
449+
}
450+
} else if [logx][suricata][event_type] == "rdp"
451+
or ([logx][suricata][rdp][event_type] and ([logx][suricata][rdp][event_type] == "initial_response"
452+
or [logx][suricata][rdp][event_type] == "initial_request" or [logx][suricata][rdp][event_type] == "connect_request"
453+
or [logx][suricata][rdp][event_type] == "connect_response" or [logx][suricata][rdp][event_type] == "tls_handshake") ) {
454+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
455+
([logx][suricata][rdp][event_type] == "connect_response" or [logx][suricata][rdp][event_type] == "tls_handshake") {
456+
mutate {
457+
add_field => { "[logx][utm][action]" => "Success" }
458+
}
459+
}
460+
} else if [logx][suricata][event_type] == "rfb" {
461+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
462+
([logx][suricata][rfb][authentication][security-result] and [logx][suricata][rfb][authentication][security-result] == "OK") {
463+
mutate {
464+
add_field => { "[logx][utm][action]" => "Success" }
465+
}
466+
}
467+
} else if [logx][suricata][event_type] == "mqtt" {
468+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
469+
([logx][suricata][mqtt][connack][return_code] and
470+
([logx][suricata][mqtt][connack][return_code] == 0 or [logx][suricata][mqtt][connack][return_code] == "0x00")) {
471+
mutate {
472+
add_field => { "[logx][utm][action]" => "Success" }
473+
}
474+
}
475+
} else if [logx][suricata][event_type] == "http2" {
476+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
477+
([logx][suricata][http2][response][headers] ) {
478+
ruby {
479+
code => "
480+
event.get(''[logx][suricata][http2][response][headers]'').each_with_index do |value,key|
481+
if (value[''name''] == ''status'' or value[''name''] == '':status'')
482+
event.set(''[logx][utm][action]'', ''Success'')
483+
end
484+
end
485+
"
486+
}
487+
}
488+
} else if [logx][suricata][event_type] == "pgsql" {
489+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
490+
([logx][suricata][pgsql][request][simple_query] or [logx][suricata][pgsql][response][command_completed] or
491+
([logx][suricata][pgsql][response][ssl_accepted] and [logx][suricata][pgsql][response][ssl_accepted] == "true") or
492+
([logx][suricata][pgsql][response][accepted] and [logx][suricata][pgsql][response][accepted] == "true") or
493+
[logx][suricata][pgsql][response][authentication_md5_password] ) {
494+
mutate {
495+
add_field => { "[logx][utm][action]" => "Success" }
496+
}
497+
}
498+
} else if [logx][suricata][event_type] == "ike" or [logx][suricata][event_type] == "ikev1" or [logx][suricata][event_type] == "ikev2" {
499+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] {
500+
mutate {
501+
add_field => { "[logx][utm][action]" => "Success" }
502+
}
503+
}
504+
} else if [logx][suricata][event_type] == "modbus" {
505+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] {
506+
mutate {
507+
add_field => { "[logx][utm][action]" => "Success" }
508+
}
509+
}
510+
} else if [logx][suricata][event_type] == "sip" {
511+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] {
512+
mutate {
513+
add_field => { "[logx][utm][action]" => "Success" }
514+
}
515+
}
516+
} else if [logx][suricata][event_type] == "quic" {
517+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] {
518+
mutate {
519+
add_field => { "[logx][utm][action]" => "Success" }
520+
}
521+
}
522+
} else if [logx][suricata][event_type] == "fileinfo" {
523+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] {
524+
mutate {
525+
add_field => { "[logx][utm][action]" => "Success" }
526+
}
527+
}
528+
} else if [logx][suricata][event_type] == "snmp" {
529+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] {
530+
mutate {
531+
add_field => { "[logx][utm][action]" => "Success" }
532+
}
533+
}
534+
} else if [logx][suricata][event_type] == "dhcp" {
535+
if [logx][suricata][src_ip] and [logx][suricata][dest_ip] and
536+
([logx][suricata][dhcp][assigned_ip] and [logx][suricata][dhcp][assigned_ip] != "0") {
537+
mutate {
538+
add_field => { "[logx][utm][action]" => "Success" }
539+
}
540+
}
541+
}
542+
}
543+
}
544+
}', 'suricata', null, true, 'SURICATA', false, '2.0.0');
168545
]]>
169546
</sql>
170547
<sql dbms="postgresql" splitStatements="true" stripComments="true">

0 commit comments

Comments
 (0)