Skip to content
Snippets Groups Projects
Commit 07e96211 authored by Pavel Eis's avatar Pavel Eis Committed by Pavel Kácha
Browse files

Suricata connector - remake of IDEA categories conversion, added list of...

Suricata connector - remake of IDEA categories conversion, added list of CVE's, which pairs CVE to certain suricata alert. Added logging option and some refractoring.
parent baa347b7
Branches
No related tags found
No related merge requests found
This diff is collapsed.
...@@ -10,8 +10,8 @@ import resource ...@@ -10,8 +10,8 @@ import resource
import os.path as pth import os.path as pth
import atexit import atexit
import time import time
from collections import OrderedDict
import logging import logging
import logging.handlers
class FileWatcher(object): class FileWatcher(object):
...@@ -145,38 +145,48 @@ class Filer(object): ...@@ -145,38 +145,48 @@ class Filer(object):
class IdeaGen(object): class IdeaGen(object):
idea_categories = {'Intrusion.Botnet': re.compile("A Network Trojan was detected, signature: ET CNC"), idea_categories = {'Other': re.compile("(Misc Attack|Executable code|Protocol Command Decode)"),
'Malware.Trojan': re.compile("A Network Trojan was detected, signature: ET (?!CNC)"), 'Attempt.Exploit': re.compile("(Attempted(?! login)|Unsuccessful User|Web Application Attack| RPC Query)"),
'Recon.Scanning': re.compile("signature: (ET|GPL) (SCAN|DNS Query|CURRENT_EVENTS DNS Query)"), 'Information.UnauthorizedAccess': re.compile("(?<!Attempted )Information Leak"),
'Availability.DoS': re.compile("signature: ET DOS"), 'Availability.DoS': re.compile("(?<!Attempted )Denial of Service"),
'Abusive.Spam': re.compile("signature:.*?Spam(?!cop.net)"), 'Intrusion.UserCompromise': re.compile("Successful User"),
'Attempt.Exploit': re.compile("category: Web Application Attack")} 'Intrusion.AdminCompromise': re.compile("Successful Admin"),
other_a_re = re.compile("signature: (GPL SNMP|GPL WEB_SERVER|ET DROP Dshield|ET WEB_CLIENT Hex Obfuscation|GPL TELNET)") 'Anomaly.System': re.compile("system call"),
other_b_re = re.compile("Potential Corporate Privacy Violation, signature: ET (?!POLICY)") 'Malware': re.compile("Trojan"),
'Recon.Scanning': re.compile("Network Scan"),
'Anomaly.Traffic': re.compile("(?:Bad Traffic|non-standard|port)"),
'Abusive.Sexual': re.compile("lotion"),
'Attempt.Login': re.compile("login"),
'Anomaly.Application': re.compile("web application(?! Attack)")}
vulnerability_re = re.compile("vulnerability|vulnerable")
confidence_re = re.compile("(?i)(?:suspicious|possible|potential)")
confidence_likely_re = re.compile("(?i)most likely")
cve_list_file = open("CVE_list.txt")
def __init__(self, name, test): def __init__(self, name, test):
self.name = name self.name = name
self.test = test self.test = test
def convert_category(self, category, signature): def convert_category(self, category, signature):
if not (category and signature): if not (category and signature) or "SURICATA" in signature:
return None return None
suricata_category = "category: " + category + ", signature: " + signature if IdeaGen.vulnerability_re.search(signature):
if IdeaGen.other_a_re.search(suricata_category) or IdeaGen.other_b_re.search(suricata_category): return "Vulnerable"
return "Other" for idea_category, pattern in IdeaGen.idea_categories.items():
for category, pattern in IdeaGen.idea_categories.items(): if pattern.search(category):
if pattern.search(suricata_category): return idea_category
return category
return None return None
def gen_event_idea(self, timestamp, category, src_ip, src_port, proto, dest_ip, dest_port, orig_data, def gen_event_idea(self, timestamp, category, src_ip, src_port, proto, dest_ip, dest_port, orig_data,
incident_desription): incident_desription, signature_id, signature):
event = { event = {
'Format': "IDEA0", 'Format': "IDEA0",
'ID': str(uuid4()), 'ID': str(uuid4()),
'DetectTime': timestamp, 'DetectTime': timestamp,
'Category': [category] + (["Test"] if self.test else []), 'Category': [category] + (["Test"] if self.test else []),
'Note': incident_desription 'Note': incident_desription,
} }
source = {} source = {}
target = {} target = {}
...@@ -200,12 +210,26 @@ class IdeaGen(object): ...@@ -200,12 +210,26 @@ class IdeaGen(object):
attachment = {'Handle': "att1", attachment = {'Handle': "att1",
'Note': "original data", 'Note': "original data",
'Content': orig_data} 'Content': orig_data}
event['Attach'] = attachment event['Attach'] = [attachment]
event['Node'] = [{ event['Node'] = [{
'Name': self.name, 'Name': self.name,
'Type': ["Connection", "Honeypot", "Recon"], 'Type': ["Connection", "Honeypot", "Recon"],
'SW': ["HP Tipping Point"], 'SW': ["Suricata"],
}] }]
# if signature_id in alert, check if it has CVE reference
for line in IdeaGen.cve_list_file:
if str(signature_id) in line:
event['Ref'] = "cve: " + line[24:]
break
# fill confidence according to probability of alert
if IdeaGen.confidence_re.search(signature):
if IdeaGen.confidence_likely_re.search(signature):
event['Confidence'] = 0.85
else:
event['Confidence'] = 0.5
return event return event
...@@ -248,7 +272,7 @@ def daemonize( ...@@ -248,7 +272,7 @@ def daemonize(
os.close(fd) os.close(fd)
except Exception: except Exception:
pass pass
# Redirect stdin, stdout, stderr to /dev/null # Redirect stdin, stdout, stderr to /dev/nulla
devnull = os.open(os.devnull, os.O_RDWR) devnull = os.open(os.devnull, os.O_RDWR)
for fd in range(3): for fd in range(3):
os.dup2(devnull, fd) os.dup2(devnull, fd)
...@@ -330,6 +354,18 @@ def get_args(): ...@@ -330,6 +354,18 @@ def get_args():
dest="origdata", dest="origdata",
action="store_true", action="store_true",
help="Store original report to IDEA message") help="Store original report to IDEA message")
optp.add_option(
"-v", "--verbose",
dest="verbose",
action="store_true",
help="turn on debug logging")
optp.add_option(
"--log",
default="local7",
dest="log",
type="string",
action="store",
help="syslog facility or log file name (default:%default)")
return optp return optp
...@@ -356,19 +392,13 @@ def reload_me(signum, frame): ...@@ -356,19 +392,13 @@ def reload_me(signum, frame):
def main(): def main():
global reload_flag global reload_flag
global running_flag global running_flag
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG, filename='suricataDaemonLog.log', filemode='w')
optp = get_args() optp = get_args()
# win opts, args = optp.parse_args()
'''opts, args = optp.parse_args(["--origdata", "-d", "C:\\Users\\Aisik\\PycharmProjects\\SuricataToIdea\\IdeaLogTest.txt", "-n",
"cz.cesnet.server.suricata", "C:\\Users\\Aisik\\PycharmProjects\\SuricataToIdea\\"
"var\\log\\suricata\\suricataJsonLog.txt"])'''
# linux
opts, args = optp.parse_args(["--origdata", "-d", "/root/Dokumenty/PycharmProjects/SuricataToIdea/IdeaLogTest", "-n",
"cz.cesnet.server.suricata", "/root/Dokumenty/PycharmProjects/SuricataToIdea/"
"var/log/suricata/suricataJsonLog.txt"])
if not args or opts.name is None or opts.dir is None: if not args or opts.name is None or opts.dir is None:
optp.print_help() optp.print_help()
sys.exit() sys.exit()
if opts.oneshot: if opts.oneshot:
signal.signal(signal.SIGINT, terminate_me) signal.signal(signal.SIGINT, terminate_me)
signal.signal(signal.SIGTERM, terminate_me) signal.signal(signal.SIGTERM, terminate_me)
...@@ -386,29 +416,42 @@ def main(): ...@@ -386,29 +416,42 @@ def main():
files = [FileWatcher(arg) for arg in args] files = [FileWatcher(arg) for arg in args]
filer = Filer(opts.dir) filer = Filer(opts.dir)
idea_gen = IdeaGen(opts.name, opts.test) idea_gen = IdeaGen(opts.name, opts.test)
log_format = "%(message)s"
logger = logging.getLogger()
if opts.oneshot:
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(asctime)s - " + log_format))
else:
if "/" in opts.log:
handler = logging.handlers.WatchedFileHandler(opts.log)
handler.setFormatter(logging.Formatter("%(asctime)s - " + log_format))
else:
handler = logging.handlers.SysLogHandler(address="/dev/log", facility=opts.log)
handler.setFormatter(logging.Formatter(log_format))
logger.addHandler(handler)
logger.setLevel(logging.DEBUG if opts.verbose else logging.INFO)
while running_flag: while running_flag:
for log_file in files: for log_file in files:
while True: while True:
try: line = log_file.readline()
line = log_file.readline() if line is None or not line.strip():
if line is None or not line.strip(): break
logging.info("no line") log = json.loads(line)
break category = idea_gen.convert_category(category=log.get('alert').get('category'),
log = json.loads(line) signature=log.get('alert').get('signature'))
logging.info("readline") if category and log.get('timestamp'):
category = idea_gen.convert_category(category=log.get('alert').get('category'), idea_event = idea_gen.gen_event_idea(timestamp=log['timestamp'], category=category,
signature=log.get('alert').get('signature')) src_ip=log.get('src_ip'),
if category and log.get('timestamp'): src_port=log.get('src_port'), proto=log.get('proto'),
idea_event = idea_gen.gen_event_idea(timestamp=log['timestamp'], category=category, dest_ip=log.get('dest_ip'),
src_ip=log.get('src_ip'), dest_port=log.get('dest_port'),
src_port=log.get('src_port'), proto=log.get('proto'), orig_data=str(log) if opts.origdata else False,
dest_ip=log.get('dest_ip'), incident_desription=log['alert']['signature'],
dest_port=log.get('dest_port'), signature_id=log.get('alert')['signature_id'],
orig_data=str(log) if opts.origdata else False, signature=log.get('alert')['signature'])
incident_desription=log['alert']['signature']) save_events(idea_event, filer)
save_events(idea_event, filer)
except Exception as e:
logging.debug(e)
if not running_flag: if not running_flag:
break break
if reload_flag: if reload_flag:
...@@ -423,4 +466,4 @@ def main(): ...@@ -423,4 +466,4 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
main() main()
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment