diff --git a/CHANGELOG.md b/CHANGELOG.md index 45ef237ce..8f755b86b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ # Change Log All notable changes to this project will be documented in this file. +## [v1.06] - 2016-02-12 +### Added +- Rules for Amazon VPC +- USB Decoder and Rules +- PCI Tagging for SSH rootchecks + +### Changed +- *ossec_ruleset.py*: New interface. +- Directory structure of Rootcheck +- Netscreen Firewall decoder + +### Fixed +- Syntax error in rootchecks. + + ## [v1.05] - 2016-01-27 ### Fixed - *ossec_ruleset.py*: diff --git a/README.md b/README.md index ad31385f3..a4479d608 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,7 @@ The ruleset includes compliance mapping with PCI DSS v3.1, CIS and additional de ## Directory structure ├── ossec-rules - │ ├── rootcheck - │ ├── ossec # OSSEC Rootchecks updated by Wazuh - │ ├── # New rootchecks + │ ├── rootcheck # OSSEC Rootchecks created/updated by Wazuh | │ ├── rules-decoders │ ├── ossec # OSSEC Decoders & Rules updated by Wazuh diff --git a/VERSION b/VERSION index 993f09564..d510f05a9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.05 +1.06 diff --git a/ossec_ruleset.py b/ossec_ruleset.py index 5b42189bf..68b5d61a1 100755 --- a/ossec_ruleset.py +++ b/ossec_ruleset.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -# OSSEC Ruleset Installer and Updater +# OSSEC Ruleset Update -# v2.2 2016/01/27 +# v2.3 2016/02/12 # Created by Wazuh, Inc. . # jesus@wazuh.com # This program is a free software; you can redistribute it and/or modify it under the terms of GPLv2 @@ -12,10 +12,7 @@ # root privileges # Instructions: -# sudo mkdir /var/ossec/updater/ruleset && cd /var/ossec/updater/ruleset -# sudo wget https://raw.githubusercontent.com/wazuh/ossec-rules/master/ossec_ruleset.py -# sudo chmod +x ossec_ruleset.py -# sudo ./ossec_ruleset.py --help +# http://wazuh-documentation.readthedocs.org/en/latest/ossec_ruleset.html#automatic-installation import os import sys @@ -43,38 +40,67 @@ # Log class class LogFile(object): - """Print to stdout and file""" def __init__(self, name=None, tag="my_log"): self.__stdout = True - self.__log_file = True + self.__file = True + self.__debug_mode = False self.__tag = tag + try: self.__logger = open(name, 'a') except: print("Error opening log '{0}'".format(name)) sys.exit(2) - def set_ouput(self, stdout=True, log_file=True): - self.__stdout = stdout - self.__log_file = log_file + def set_ouput(self, log_stdout=True, log_file=True, log_debug=False): + self.__stdout = log_stdout + self.__file = log_file + self.__debug_mode = log_debug + + def set_debug(self, debug_mode): + self.__debug_mode = debug_mode def log(self, message): + """ + Print to STDOUT and FILE + :param message: text + """ self.__write_stdout(message) - self.__write_log(message) + self.__write_file(message) - def logfile(self, message): - self.__write_log(message) + def file(self, message): + self.__write_file(message) - def logstdout(self, message): + def stdout(self, message): self.__write_stdout(message) + def debug(self, message): + if self.__debug_mode: + count_init = 0 + char_init = "" + + try: + if message[0] == '\t' or message[0] == '\n': + special_char = message[0] + + for c in message: + if c == special_char: + count_init += 1 + else: + break + char_init = special_char * count_init + except: + char_init = "" + + print("{0}Debug: {1}".format(char_init, message[count_init:])) + def __write_stdout(self, message): if self.__stdout: print(message) - def __write_log(self, message): - if self.__log_file: + def __write_file(self, message): + if self.__file: timestamp = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S') new_msg = re.sub('[\n\t]', '', message) log = "{0}:{1}={2}".format(self.__tag, timestamp, new_msg) @@ -95,31 +121,6 @@ def regex_in_file(regex, filepath): return False -def replace_text_in_file(old_text_init, old_text_end, new_text, filepath): - replace = False - - f = open(filepath) - text = f.read() - f.close() - - if old_text_init in text and old_text_end in text: - for line in fileinput.input(filepath, inplace=True): - if old_text_init in line.strip(): - replace = True - elif old_text_end in line.strip(): - replace = False - print(new_text) - continue - - if not replace: - print(line.rstrip("\n")) - fileinput.close() - - return True - else: - return False - - def write_before_line(line_search, new_text, filepath): for line in fileinput.input(filepath, inplace=True): if line_search in line.strip(): @@ -184,33 +185,6 @@ def remove_line(line_search, filepath): fileinput.close() -def signal_handler(n_signal, frame): - sys.exit(0) - - -def get_item_between_label(label, filepath): - f = open(filepath) - - label_s = "<{0}>".format(label) - label_e = "".format(label) - lines = [] - save_lines = False - for line in f.readlines(): - if save_lines: - match = re.search(r'\s*<.+>(.+)', line) - if match: - lines.append(match.group(1)) - - if label_s in line: - save_lines = True - elif label_e in line: - break - - f.close() - - return lines - - def download_file(url, output_file): try: f = urlopen(url) @@ -289,8 +263,22 @@ def compare_folders(folder1, folder2, pattern_files): return same +def get_stdin(msg): + try: + stdin = raw_input(msg) + except: + # Python 3 + stdin = input(msg) + return stdin + + # Ruleset functions + +def signal_handler(n_signal, frame): + sys.exit(0) + + def get_ossec_version(): try: ossec_v = "old" @@ -298,7 +286,7 @@ def get_ossec_version(): for line in f_ossec.readlines(): if "WAZUH_VERSION" in line: - ossec_v = line + ossec_v = line.strip("\n") break f_ossec.close() except: @@ -318,296 +306,128 @@ def get_ruleset_version(): return rs_version -def get_ruleset_from_menu(type_ruleset): - """ - :param type_ruleset: rules, rootchecks, all - :return: ruleset to install - """ - directories = [] - - ruleset_menu = {"rules": [], "rootchecks": []} - - if type_ruleset == "rules" or type_ruleset == "all": - directories.append(new_rules_path) - if type_ruleset == "rootchecks" or type_ruleset == "all": - directories.append(new_rootchecks_path) - - for directory in directories: - if not os.path.exists(directory): - logger.log("\nError: No folder {0}".format(directory)) - sys.exit(2) - - last_path = directory.split("/")[-1] - if last_path == "rootcheck": - type_directory = "rootchecks" - else: - type_directory = "rules" - - ruleset_select = [] - - # Get name of the new rules/rootchecks - menu_ruleset_dir = ["Select ALL"] - for name in os.listdir(directory): - if os.path.isdir(os.path.join(directory, name)): - menu_ruleset_dir.append(name) - - # OSSEC is already installed -> remove from menu_ruleset - if "ossec" in menu_ruleset_dir: - menu_ruleset_dir.remove("ossec") - - str_msg_show = "\nPress any key to show the available {0}...".format(type_directory) - try: - raw_input(str_msg_show) - except: - # Python 3 - input(str_msg_show) - - title_str = "OSSEC Wazuh Ruleset, {0}\n\nUse ENTER key to select/unselect {1}:\n".format(today_date, - type_directory) - - menu_ruleset = sorted(menu_ruleset_dir) - if menu_ruleset: - toggle = [] - for i in range(len(menu_ruleset)): - toggle.append(' ') - - read_input = True - while read_input: - os.system("clear") - print(title_str) - - i = 1 - for rule in sorted(menu_ruleset): - print("{0}. [{1}] {2}".format(i, toggle[i - 1], rule)) - i += 1 - print("{0}. Confirm and continue.".format(i)) - - str_option = "\nOption [1-{0}]: ".format(i) - try: - ans = raw_input(str_option) - except: - # Python 3 - ans = input(str_option) - try: - option = int(ans) - 1 - except Exception: - continue - - if 0 <= option < len(menu_ruleset): - if toggle[option] == "X": - toggle[option] = " " - if option == 0: # Unselect ALL - for j in range(len(toggle)): - toggle[j] = " " - else: - toggle[option] = "X" - if option == 0: # Select ALL - for j in range(len(toggle)): - toggle[j] = "X" - elif option == (i - 1): # Option Done - read_input = False - - for i in range(len(toggle)): - if toggle[i] == "X": - ruleset_select.append(menu_ruleset[i]) - if "Select ALL" in ruleset_select: - ruleset_select.remove("Select ALL") - - ruleset_menu[type_directory] = ruleset_select - - print("") - return ruleset_menu - - -def get_ruleset_from_file(filename, type_r): - """ - :param filename: File with ruleset to install. Format: - # comment - \n - rules:name_rule - rootchecks:name_rootcheck - :param type_r: rules (get rules) rootchecks (get rootchecks) - :return: ruleset to install - """ - - logger.log("\nReading configuration file '{0}'.".format(filename)) +def do_backups(): - ruleset_file = {"rules": [], "rootchecks": []} - rules_file = [] - rootchecks_file = [] try: - file_config = open(filename) - i = 1 - for line in file_config: - if re.match("(^rootchecks|rules):.+", line) is not None: - if "rules" in line: - rules_file.append(line.split(":")[1].rstrip('\n').strip()) - elif "rootchecks" in line: - rootchecks_file.append(line.split(":")[1].rstrip('\n').strip()) - elif re.match("^#.*", line) is not None or re.match("^\s*\n", line) is not None: - continue - else: - logger.log("\tSyntax Error in line [{0}]: ->{1}<-".format(i, line)) - sys.exit(2) - i += 1 - file_config.close() - except Exception as e: - logger.log("\tError reading config file: '{0}'.\nExit.".format(e)) - sys.exit(2) - - if rules_file: - if "ossec" in rules_file: - logger.log("\tError reading config file: \"ossec\" item found. \t\tIt is assumed that the default rootchecks are installed.\t\tIf you want to update it, please use the option -u") - sys.exit(2) - - if not os.path.exists(new_rules_path): - logger.log("\tError: No folder '{0}' found".format(new_rules_path)) - sys.exit(2) - new_ruleset = os.listdir(new_rules_path) - - for rs_f in rules_file: - if rs_f not in new_ruleset: - logger.log("\tError: '{0}' not in folder '{1}'".format(rs_f, new_rules_path)) - sys.exit(2) - - if rootchecks_file: - if "ossec" in rootchecks_file: - logger.log("\tError reading config file: \"ossec\" item found. \t\tIt is assumed that the default rootchecks are installed. \t\tIf you want to update it, please use the option -u") - sys.exit(2) - - if not os.path.exists(new_rootchecks_path): - logger.log("\tError: No folder '{0}'".format(new_rootchecks_path)) - sys.exit(2) - new_ruleset = os.listdir(new_rootchecks_path) - - for rs_f in rootchecks_file: - if rs_f not in new_ruleset: - logger.log("\tError: '{0}' not in folder '{1}'".format(rs_f, new_rootchecks_path)) - sys.exit(2) - - if type_r == "rules" or type_r == "all": - ruleset_file["rules"] = rules_file - if type_r == "rootchecks" or type_r == "all": - ruleset_file["rootchecks"] = rootchecks_file - - logger.log("\t[Done]") - return ruleset_file + # Create folder backups + if not os.path.exists(bk_directory): + os.makedirs(bk_directory) + # # Create folder /backups/YYYYMMDD_i + sub_bk_directories = sorted(os.listdir(bk_directory)) + if "old" in sub_bk_directories: + sub_bk_directories.remove("old") -def get_ruleset_from_update(type_ruleset): - ruleset_update = {"rules": [], "rootchecks": []} + if len(sub_bk_directories) >= MAX_BACKUPS: + logger.log("\tLimit of backups ({0}) reached. Removing old backups.".format(MAX_BACKUPS)) + for old_bk in sub_bk_directories[0:-1]: + path = os.path.join(bk_directory, old_bk) + shutil.rmtree(path) - logger.log("\nDownloading new ruleset.") + bk_old = "{0}/{1}".format(bk_directory, "old") + if os.path.exists(bk_old): + shutil.rmtree(bk_old) + os.makedirs(bk_old) - # Download new ruleset and extract all files + path_last_bk = "{0}/{1}".format(bk_directory, sub_bk_directories[-1]) + new_path_lat_bk = "{0}/{1}".format(bk_old, sub_bk_directories[-1]) + logger.log("\tMoving last backup: {0} -> old/{0}".format(sub_bk_directories[-1])) + shutil.move(path_last_bk, new_path_lat_bk) - output = "{0}/ruleset.zip".format(downloads_directory) + i = 1 # Reset + else: + if sub_bk_directories: + i = int(sub_bk_directories[-1].split("_")[-1]) + 1 # Next + else: + i = 1 # First - if not os.path.exists(downloads_directory): - os.makedirs(downloads_directory) + bk_subdirectory = "{0}/{1}_{2}".format(bk_directory, today_date, str(i).zfill(3)) + os.makedirs(bk_subdirectory) - download_file(url_ruleset, output) + # Backup etc + src_dir = "{0}/etc".format(ossec_path) + dest_dir = "{0}/etc".format(bk_subdirectory) + if os.path.exists(dest_dir): + shutil.rmtree(dest_dir) + shutil.copytree(src_dir, dest_dir) - old_extracted_files = "{0}/ossec-rules/".format(downloads_directory) - if os.path.exists(old_extracted_files): - shutil.rmtree(old_extracted_files) + # Backup rules + src_dir = "{0}/rules".format(ossec_path) + dest_dir = "{0}/rules".format(bk_subdirectory) + if os.path.exists(dest_dir): + shutil.rmtree(dest_dir) + shutil.copytree(src_dir, dest_dir) - try: - with contextlib.closing(zipfile.ZipFile(output)) as z: - z.extractall(downloads_directory) except Exception as e: - logger.log("\tError extracting file '{0}': {1}.".format(output, e)) + logger.log("Error - Backup:{0}.\nExit.".format(e)) sys.exit(2) - # Get ruleset to update - rules_update = [] - rootchecks_update = [] - global restart_ossec + return bk_subdirectory - if type_ruleset == "rules" or type_ruleset == "all": - download_rules_path = "{0}/ossec-rules/rules-decoders".format(downloads_directory) - for new_rule in os.listdir(download_rules_path): - if new_rule == "ossec": - download_decoders_dir = "{0}/{1}/decoders".format(download_rules_path, new_rule) - decoders_dir = "{0}/etc/ossec_decoders".format(ossec_path) - decoders_equal = compare_folders(download_decoders_dir, decoders_dir, "*_decoders.xml") - - download_rules_dir = "{0}/{1}/rules".format(download_rules_path, new_rule) - rules_dir = "{0}/rules".format(ossec_path) - rules_equal = compare_folders(download_rules_dir, rules_dir, "*_rules.xml") - - # print("{0}: d {1} r {2}".format(new_rule, decoders_equal, rules_equal)) - if not decoders_equal or not rules_equal: - rules_update.append(new_rule) - restart_ossec = True - else: - download_decoders_dir = "{0}/{1}/{1}_decoders.xml".format(download_rules_path, new_rule) - decoders_dir = "{0}/etc/wazuh_decoders/{1}_decoders.xml".format(ossec_path, new_rule) - decoders_equal = compare_files(download_decoders_dir, decoders_dir) - - download_rules_dir = "{0}/{1}/{1}_rules.xml".format(download_rules_path, new_rule) - rules_dir = "{0}/rules/{1}_rules.xml".format(ossec_path, new_rule) - rules_equal = compare_files(download_rules_dir, rules_dir) - - # print("{0}: d {1} r {2}".format(new_rule, decoders_equal, rules_equal)) - if not decoders_equal or not rules_equal: - rules_update.append(new_rule) - if regex_in_file("\s*{0}_rules.xml".format(new_rule), ossec_conf): - restart_ossec = True - if type_ruleset == "rootchecks" or type_ruleset == "all": - download_rootchecks_path = "{0}/ossec-rules/rootcheck".format(downloads_directory) - for new_rc in os.listdir(download_rootchecks_path): - if new_rc == "ossec": - download_rootchecks_dir = "{0}/{1}".format(download_rootchecks_path, new_rc) - rootchecks_dir = "{0}/etc/shared".format(ossec_path) - rootchecks_equal = compare_folders(download_rootchecks_dir, rootchecks_dir, "*.txt") - - # print("{0}: rc ossec {1} ".format(new_rc, rootchecks_equal)) - if not rootchecks_equal: - rootchecks_update.append(new_rc) - restart_ossec = True - else: - download_rootchecks_dir = "{0}/{1}".format(download_rootchecks_path, new_rc) - rootchecks_dir = "{0}/etc/shared/{1}".format(ossec_path, new_rc) - rootchecks_equal = compare_folders(download_rootchecks_dir, rootchecks_dir, "*.*") +def restore_backups(backup_id): - # print("{0}: rc {1} ".format(new_rc, rootchecks_equal)) - if not rootchecks_equal: - rootchecks_update.append(new_rc) + if not os.path.exists(bk_directory): + logger.log("\tNo backups to restore.") + logger.file("Ending ossec_ruleset.py") + sys.exit() - if regex_in_file("\s*<.+>{0}/.+".format(rootchecks_dir), ossec_conf): - restart_ossec = True + if backup_id == "0": + all_backups = sorted(os.listdir(bk_directory)) - # Save ruleset - ruleset_update["rules"] = rules_update - ruleset_update["rootchecks"] = rootchecks_update + i = 0 + print("\tList of current backups:") + for subdir_bk in all_backups: + print("\t\t{0}: {1}".format(i, subdir_bk)) + i += 1 + last_item = i - 1 - # Update main directory and remove Downloads - src_dir = "{0}/ossec-rules/rules-decoders".format(downloads_directory) - if os.path.exists(new_rules_path): - shutil.rmtree(new_rules_path) - shutil.copytree(src_dir, new_rules_path) + get_input = True + str_ans = "\n\tPlease, choose which backup you want to restore [0 - {0}]: ".format(last_item) + str_error = "\t\tSelect an option between 0 and {0}.".format(last_item) + while get_input: + ans = get_stdin(str_ans) + try: + option = int(ans) + if 0 <= option <= last_item: + get_input = False + else: + print(str_error) + except ValueError: + print(str_error) - src_dir = "{0}/ossec-rules/rootcheck".format(downloads_directory) - if os.path.exists(new_rootchecks_path): - shutil.rmtree(new_rootchecks_path) - shutil.copytree(src_dir, new_rootchecks_path) + bk_restore = all_backups[option] + else: + bk_restore_dir = "{0}/{1}".format(bk_directory, backup_id) + if not os.path.exists(bk_restore_dir): + logger.log("\tError: No backups with name '{0}'.".format(backup_id)) + sys.exit(2) - shutil.copyfile("{0}/ossec-rules/VERSION".format(downloads_directory), version_path) + bk_restore = backup_id - new_python_script = "{0}/ossec-rules/ossec_ruleset.py".format(downloads_directory) - if os.path.isfile(new_python_script): - shutil.copyfile(new_python_script, script_path) + logger.log("\n\tThe backup '{0}' will be restored.".format(bk_restore)) - if os.path.exists(downloads_directory): - shutil.rmtree(downloads_directory) + etc_restore = "{0}/{1}/etc".format(bk_directory, bk_restore) + rules_restore = "{0}/{1}/rules".format(bk_directory, bk_restore) + if not os.path.exists(etc_restore) or not os.path.exists(rules_restore): + logger.log("\t\tError: Folder '{0}' or '{1}' not found.".format(etc_restore, rules_restore)) + sys.exit(2) - global ruleset_version - ruleset_version = get_ruleset_version() + etc_dest = "{0}/etc".format(ossec_path) + logger.log("\t\tRestoring folder: '{0}' -> '{1}'".format(etc_restore, etc_dest)) + if os.path.exists(etc_dest): + shutil.rmtree(etc_dest) + shutil.copytree(etc_restore, etc_dest) + chown_r(etc_dest, root_uid, ossec_gid) + logger.log("\t\t\t[Done]") - logger.log("\t[Done]\n") - return ruleset_update + rules_dest = "{0}/rules".format(ossec_path) + logger.log("\t\tRestoring folder: '{0}' -> '{1}'".format(rules_restore, rules_dest)) + if os.path.exists(rules_dest): + shutil.rmtree(rules_dest) + shutil.copytree(rules_restore, rules_dest) + chown_r(rules_dest, root_uid, ossec_gid) + logger.log("\t\t\t[Done]") def setup_wazuh_directory_structure(): @@ -739,6 +559,11 @@ def setup_wazuh_directory_structure(): write_before_line("", " {0}".format(local_rules), ossec_conf) logger.log("\tNew line in ossec.conf: '{0}'".format(local_rules)) + # Remove etc/shared/ssh (old version of ssh rootcheck) + old_ssh_rootcheck = "{0}/etc/shared/ssh".format(ossec_path) + if os.path.exists(old_ssh_rootcheck): + shutil.rmtree(old_ssh_rootcheck) + # OSSEC.CONF os.chown(ossec_conf, root_uid, ossec_gid) @@ -747,6 +572,212 @@ def setup_wazuh_directory_structure(): sys.exit(2) +def download_ruleset(): + output = "{0}/ruleset.zip".format(downloads_directory) + + if not os.path.exists(downloads_directory): + os.makedirs(downloads_directory) + + download_file(url_ruleset, output) + + old_extracted_files = "{0}/ossec-rules/".format(downloads_directory) + if os.path.exists(old_extracted_files): + shutil.rmtree(old_extracted_files) + + try: + with contextlib.closing(zipfile.ZipFile(output)) as z: + z.extractall(downloads_directory) + except Exception as e: + logger.log("\tError extracting file '{0}': {1}.".format(output, e)) + sys.exit(2) + + # Update main directory + shutil.copyfile("{0}/ossec-rules/VERSION".format(downloads_directory), version_path) + + new_python_script = "{0}/ossec-rules/ossec_ruleset.py".format(downloads_directory) + if os.path.isfile(new_python_script): + shutil.copyfile(new_python_script, script_path) + + global ruleset_version + ruleset_version = get_ruleset_version() + + +def get_ruleset_to_update(no_checks=False): + ruleset_update = {"rules": [], "rootchecks": []} + rules_update = [] + rootchecks_update = [] + global restart_ossec + + if type_ruleset == "rules" or type_ruleset == "all": + + if not os.path.exists(new_rules_path): + logger.log("\tError: No rules found. Maybe failed download.") + sys.exit(2) + + for new_rule in os.listdir(new_rules_path): + if no_checks: + rules_update.append(new_rule) + else: # Compare: New / Changed files + if new_rule == "ossec": + new_decoders_dir = "{0}/{1}/decoders".format(new_rules_path, new_rule) + decoders_dir = "{0}/etc/ossec_decoders".format(ossec_path) + decoders_equal = compare_folders(new_decoders_dir, decoders_dir, "*_decoders.xml") + + new_rules_dir = "{0}/{1}/rules".format(new_rules_path, new_rule) + rules_dir = "{0}/rules".format(ossec_path) + rules_equal = compare_folders(new_rules_dir, rules_dir, "*_rules.xml") + + logger.debug("\tRule '{0}': DecoderOK: {1} | RulesOK: {2}".format(new_rule, decoders_equal, rules_equal)) + if not decoders_equal or not rules_equal: + rules_update.append(new_rule) + restart_ossec = True + logger.debug("\t\tAdding rule '{0}'. *Restart OSSEC*".format(new_rule)) + else: + new_decoders_dir = "{0}/{1}/{1}_decoders.xml".format(new_rules_path, new_rule) + decoders_dir = "{0}/etc/wazuh_decoders/{1}_decoders.xml".format(ossec_path, new_rule) + decoders_equal = compare_files(new_decoders_dir, decoders_dir) + + new_rules_dir = "{0}/{1}/{1}_rules.xml".format(new_rules_path, new_rule) + rules_dir = "{0}/rules/{1}_rules.xml".format(ossec_path, new_rule) + rules_equal = compare_files(new_rules_dir, rules_dir) + + logger.debug("\tRule '{0}': DecoderOK: {1} | RulesOK: {2}".format(new_rule, decoders_equal, rules_equal)) + if not decoders_equal or not rules_equal: + rules_update.append(new_rule) + if regex_in_file("\s*{0}_rules.xml".format(new_rule), ossec_conf): + restart_ossec = True + logger.debug("\t\tAdding rule '{0}'. *Restart OSSEC*".format(new_rule)) + + if type_ruleset == "rootchecks" or type_ruleset == "all": + + if not os.path.exists(new_rootchecks_path): + logger.log("\tError: No rootchecks found. Maybe failed download.") + sys.exit(2) + + for new_rc in os.listdir(new_rootchecks_path): + if no_checks: + rootchecks_update.append(new_rc) + else: # Compare: New / Changed files + new_rootchecks_file = "{0}/{1}".format(new_rootchecks_path, new_rc) + rootchecks_file = "{0}/etc/shared/{1}".format(ossec_path, new_rc) + rootchecks_equal = compare_files(new_rootchecks_file, rootchecks_file) + + if not rootchecks_equal: + rootchecks_update.append(new_rc) + if regex_in_file("\s*<.+>{0}".format(rootchecks_file), ossec_conf): + restart_ossec = True + logger.debug("\t\tAdding rootcheck '{0}'. *Restart OSSEC*".format(new_rc)) + + # Save ruleset + ruleset_update["rules"] = sorted(rules_update) + ruleset_update["rootchecks"] = sorted(rootchecks_update) + + return ruleset_update + + +def activate_from_menu(ruleset_show): + update_ruleset = {'rules': [], 'rootchecks': []} + + for type_r in ruleset_show: + if ruleset_show[type_r] and (type_ruleset == type_r or type_ruleset == "all"): + + menu = sorted(ruleset_show[type_r]) + if "ossec" in menu: + menu.remove("ossec") + menu.insert(0, "Select ALL") + + get_stdin("\nPress any key to show the {0} to activate...".format(type_r)) + + title_str = "OSSEC Wazuh Ruleset, {0}\n\nSelect {1} to activate.\nUse ENTER key to select/unselect {1}:\n".format(today_date, type_r) + + toggle = [] + for i in range(len(menu)): + toggle.append(' ') + + read_input = True + while read_input: + os.system("clear") + print(title_str) + + i = 1 + for rule in sorted(menu): + print("{0}. [{1}] {2}".format(i, toggle[i - 1], rule)) + i += 1 + print("{0}. Confirm and continue.".format(i)) + + ans = get_stdin("\nOption [1-{0}]: ".format(i)) + + try: + option = int(ans) - 1 + except Exception: + continue + + if 0 <= option < len(menu): + if toggle[option] == "X": + toggle[option] = " " + if option == 0: # Unselect ALL + for j in range(len(toggle)): + toggle[j] = " " + else: + toggle[option] = "X" + if option == 0: # Select ALL + for j in range(len(toggle)): + toggle[j] = "X" + elif option == (i - 1): # Option Done + read_input = False + + for i in range(len(toggle)): + if toggle[i] == "X": + update_ruleset[type_r].append(menu[i]) + if "Select ALL" in update_ruleset[type_r]: + update_ruleset[type_r].remove("Select ALL") + + return update_ruleset + + +def activate_from_file(new_ruleset): + update_ruleset = {'rules': [], 'rootchecks': []} + + if new_ruleset['rules'] or new_ruleset['rootchecks']: + logger.log("\nReading configuration file '{0}'.".format(activate_file)) + + rules_file = [] + rootchecks_file = [] + try: + file_config = open(activate_file) + i = 1 + for line in file_config: + if re.match("(^rootchecks|rules):.+", line) is not None: + if "rules" in line: + rules_file.append(line.split(":")[1].rstrip('\n').strip()) + elif "rootchecks" in line: + rootchecks_file.append(line.split(":")[1].rstrip('\n').strip()) + elif re.match("^#.*", line) is not None or re.match("^\s*\n", line) is not None: + continue + else: + logger.log("\tSyntax Error in line [{0}]: ->{1}<-".format(i, line.rstrip("\n"))) + sys.exit(2) + i += 1 + file_config.close() + except Exception as e: + logger.log("\tError reading config file: '{0}'.\nExit.".format(e)) + sys.exit(2) + + for rule_file in rules_file: + for rule in new_ruleset['rules']: + if rule_file == rule: + update_ruleset['rules'].append(rule_file) + + for rootcheck_file in rootchecks_file: + for rootcheck in new_ruleset['rootchecks']: + if rootcheck_file == rootcheck: + update_ruleset['rootchecks'].append(rootcheck_file) + + logger.log("\t[Done]") + + return update_ruleset + + def setup_decoders(decoder): if decoder == "ossec": new_decoders_path = "{0}/ossec/decoders/*_decoders.xml".format(new_rules_path) @@ -795,21 +826,10 @@ def setup_rules(rule): def setup_roochecks(rootcheck): - src_dir = "{0}/{1}".format(new_rootchecks_path, rootcheck) - - if rootcheck == "ossec": - for new_ossec_rc in os.listdir(src_dir): - if os.path.isfile("{0}/{1}".format(src_dir, new_ossec_rc)): - src_file = "{0}/{1}".format(src_dir, new_ossec_rc) - dest_file = "{0}/etc/shared/{1}".format(ossec_path, new_ossec_rc) - shutil.copyfile(src_file, dest_file) - os.chown(dest_file, root_uid, ossec_gid) - else: - dest_dir = "{0}/etc/shared/{1}".format(ossec_path, rootcheck) - if os.path.exists(dest_dir): - shutil.rmtree(dest_dir) - shutil.copytree(src_dir, dest_dir) - chown_r(dest_dir, root_uid, ossec_gid) + new_rootcheck = "{0}/{1}".format(new_rootchecks_path, rootcheck) + old_rootcheck = "{0}/etc/shared/{1}".format(ossec_path, rootcheck) + shutil.copyfile(new_rootcheck, old_rootcheck) + os.chown(old_rootcheck, root_uid, ossec_gid) def setup_ossec_conf(item, type_item): @@ -820,195 +840,62 @@ def setup_ossec_conf(item, type_item): return if type_item == "rule": - # General if not regex_in_file("\s*{0}_rules.xml".format(item), ossec_conf): logger.log("\t\tNew rule in ossec.conf: '{0}'.".format(item)) write_before_line("local_rules.xml", ' {0}_rules.xml'.format(item), ossec_conf) elif type_item == "rootcheck": - types_rc = ["rootkit_files", "rootkit_trojans", "system_audit", "win_applications", "win_audit", - "win_malware"] - - dest_dir = "{0}/etc/shared/{1}".format(ossec_path, item) - - for new_rc in os.listdir(dest_dir): - new_rc = "{0}/{1}".format(dest_dir, new_rc) - # logger.log("\t\t{0}".format(new_rc)) - - rc_include = None - for type_rc in types_rc: - if type_rc in new_rc: - rc_include = "<{0}>{1}".format(type_rc, new_rc) - break - - if not rc_include: - logger.log("\t\tError in file {0}: Wrong filename.".format(new_rc)) - logger.log("\t\tFilename must start with:") - for t_rc in types_rc: - logger.log("\t\t\t{0}".format(t_rc)) - sys.exit(2) - - rc_include_search = "\s*{0}".format(rc_include) - rc_include_new = " {0}".format(rc_include) - - if not regex_in_file(rc_include_search, ossec_conf): - logger.log("\t\tNew rootcheck in ossec.conf: '{0}'.".format(new_rc)) - write_before_line("", rc_include_new, ossec_conf) - - os.chown(ossec_conf, root_uid, ossec_gid) - - -def do_backups(): - - try: - # Create folder backups - if not os.path.exists(bk_directory): - os.makedirs(bk_directory) - - # Create folder /backups/YYYYMMDD_i - last_bk = sorted(os.listdir(bk_directory)) - if last_bk: - i = int(last_bk[-1].split("_")[-1]) + 1 - else: - i = 0 - bk_subdirectory = "{0}/{1}_{2}".format(bk_directory, today_date, str(i).zfill(2)) - os.makedirs(bk_subdirectory) - - # Backup etc - src_dir = "{0}/etc".format(ossec_path) - dest_dir = "{0}/etc".format(bk_subdirectory) - if os.path.exists(dest_dir): - shutil.rmtree(dest_dir) - shutil.copytree(src_dir, dest_dir) - - # Backup rules - src_dir = "{0}/rules".format(ossec_path) - dest_dir = "{0}/rules".format(bk_subdirectory) - if os.path.exists(dest_dir): - shutil.rmtree(dest_dir) - shutil.copytree(src_dir, dest_dir) - - # Remove old backups - sub_bk_directories = sorted(os.listdir(bk_directory)) - n_bk = len(sub_bk_directories) - - if n_bk >= MAX_BACKUPS: - n_remove = n_bk - MAX_BACKUPS - for old_bk in sub_bk_directories[0:n_remove]: - path = os.path.join(bk_directory, old_bk) - shutil.rmtree(path) - - except Exception as e: - logger.log("Error - Backup:{0}.\nExit.".format(e)) - sys.exit(2) - - return bk_subdirectory - - -def restore_backups(backup_id): - - if not os.path.exists(bk_directory): - logger.log("\tNo backups to restore.") - logger.logfile("Ending ossec_ruleset.py") - sys.exit() - - if backup_id == "0": - all_backups = sorted(os.listdir(bk_directory)) - - i = 0 - print("\tList of current backups:") - for subdir_bk in all_backups: - print("\t\t{0}: {1}".format(i, subdir_bk)) - i += 1 - last_item = i-1 - - get_input = True - str_ans = "\n\tPlease, choose which backup you want to restore [0 - {0}]: ".format(last_item) - str_error = "\t\tSelect an option between 0 and {0}.".format(last_item) - while get_input: - try: - ans = raw_input(str_ans) - except: - # Python 3 - ans = input(str_ans) - - try: - option = int(ans) - if 0 <= option <= last_item: - get_input = False - else: - print(str_error) - except ValueError: - print(str_error) + if not regex_in_file("", ossec_conf) or regex_in_file("\s*\s*\n\s*\s*yes", ossec_conf): + logger.log("\t\tRootchecks disabled in ossec.conf -> no activate rootchecks.") + return + + types_rc = ["rootkit_files", "rootkit_trojans", "system_audit", "windows_malware", "windows_audit", "windows_apps"] + types_rc_files = ["win_malware_", "win_audit_", "win_applications_", "cis_"] + types_all = types_rc + types_rc_files + + new_rc = "{0}/etc/shared/{1}".format(ossec_path, item) + + rc_include = None + for type_rc in types_all: + if item.startswith(type_rc): + # special case (default rootcheck files) + if type_rc == "win_malware_": + type_rc = "windows_malware" + elif type_rc == "win_audit_": + type_rc = "windows_audit" + elif type_rc == "win_applications_": + type_rc = "windows_apps" + elif type_rc == "cis_": + type_rc = "system_audit" + + rc_include = "<{0}>{1}".format(type_rc, new_rc) + break - bk_restore = all_backups[option] - else: - bk_restore_dir = "{0}/{1}".format(bk_directory, backup_id) - if not os.path.exists(bk_restore_dir): - logger.log("\tError: No backups with name '{0}'.".format(backup_id)) + if not rc_include: + logger.log("\t\tError in file {0}: Wrong filename.".format(new_rc)) + logger.log("\t\tFilename must start with:") + for t_rc in types_rc: + logger.log("\t\t\t{0}".format(t_rc)) sys.exit(2) - bk_restore = backup_id + rc_include_search = "\s*{0}".format(rc_include) + rc_include_new = " {0}".format(rc_include) - logger.log("\n\tThe backup '{0}' will be restored.".format(bk_restore)) + if not regex_in_file(rc_include_search, ossec_conf): + logger.log("\t\tNew rootcheck in ossec.conf: '{0}'.".format(new_rc)) + write_before_line("", rc_include_new, ossec_conf) - etc_restore = "{0}/{1}/etc".format(bk_directory, bk_restore) - rules_restore = "{0}/{1}/rules".format(bk_directory, bk_restore) - if not os.path.exists(etc_restore) or not os.path.exists(rules_restore): - logger.log("\t\tError: Folder '{0}' or '{1}' not found.".format(etc_restore, rules_restore)) - sys.exit(2) - - etc_dest = "{0}/etc".format(ossec_path) - logger.log("\t\tRestoring folder: '{0}' -> '{1}'".format(etc_restore, etc_dest)) - if os.path.exists(etc_dest): - shutil.rmtree(etc_dest) - shutil.copytree(etc_restore, etc_dest) - chown_r(etc_dest, root_uid, ossec_gid) - logger.log("\t\t\t[Done]") - - rules_dest = "{0}/rules".format(ossec_path) - logger.log("\t\tRestoring folder: '{0}' -> '{1}'".format(rules_restore, rules_dest)) - if os.path.exists(rules_dest): - shutil.rmtree(rules_dest) - shutil.copytree(rules_restore, rules_dest) - chown_r(rules_dest, root_uid, ossec_gid) - logger.log("\t\t\t[Done]") - - -def get_ruleset(type_ruleset, r_action): - """ - :param type_ruleset: "rules" or "rootchecks" - :param r_action: "manual", "file:filepath.ext" or "update" - :return: List of ruleset to install / update - """ - if r_action == "manual": - n_ruleset = get_ruleset_from_menu(type_ruleset) - elif "file:" in r_action: - filename = r_action.split(":")[1].rstrip('\n') - n_ruleset = get_ruleset_from_file(filename, type_ruleset) - elif r_action == "update": - n_ruleset = get_ruleset_from_update(type_ruleset) - else: - n_ruleset = [] - - return n_ruleset - - -def setup_ruleset_r(target_rules, r_action): - """ - :param r_action: manual, file, update - :param target_rules: rules to install - :rtype: list - """ + os.chown(ossec_conf, root_uid, ossec_gid) - str_title = "updated" if r_action == "update" else "installed" - logger.log("\nThe following rules will be {0}:".format(str_title)) +def setup_ruleset_r(target_rules, activated_rules): + logger.log("\nThe following rules will be updated:") for rule in target_rules: logger.log("\t{0}".format(rule)) - logger.logstdout("") + logger.stdout("") instructions = [] for item in target_rules: + activating_shown = False logger.log("{0}:".format(item)) # Decoders @@ -1022,47 +909,39 @@ def setup_ruleset_r(target_rules, r_action): logger.log("\t\t[Done]") # ossec.conf - if r_action != "update": + if item in activated_rules: logger.log("\tActivating rules in ossec.conf.") + activating_shown = True setup_ossec_conf(item, "rule") + + # special case: auditd, usb + if item == "ossec": + special_cases = ["auditd", "usb"] + for special_case in special_cases: + if not regex_in_file("\s*{0}_rules.xml".format(special_case), "{0}/etc/ossec.conf".format(ossec_path)): + if not activating_shown: + logger.log("\tActivating rules in ossec.conf.") + activating_shown = True + setup_ossec_conf(special_case, "rule") + + if activating_shown: logger.log("\t\t[Done]") - # special case: update auditd - if r_action == "update" and item == "ossec": - if not regex_in_file("\s*auditd_rules.xml", "{0}/etc/ossec.conf".format(ossec_path)): - logger.log("\tActivating rules in ossec.conf.") - setup_ossec_conf("auditd", "rule") - logger.log("\t\t[Done]") # Info - if r_action != "update": - if item == "puppet": - msg = "The rules of Puppet are installed but you need to perform a manual step. You will find detailed information in file \"./rules-decoders/puppet/puppet_instructions.md\"" - logger.log("\t**Manual steps**:\n\t\t{0}".format(msg)) - instructions.append("{0}: {1}".format(item, msg)) + if item == "puppet": + msg = "The rules of Puppet are installed but you need to perform a manual step. You will find detailed information in our documentation: http://wazuh-documentation.readthedocs.org/en/latest/ossec_ruleset.html#puppet" + logger.log("\t**Manual steps**:\n\t\t{0}".format(msg)) + instructions.append("{0}: {1}".format(item, msg)) return instructions -def setup_ruleset_rc(target_rootchecks, r_action): - """ - :param r_action: manual, file, update - :param target_rootchecks: rootchecks to install - Important: Filenames must contain the following strings at the beginning: - rootkit_files - rootkit_trojans - system_audit - win_applications - win_audit - win_malware - - *except for default ossec rootchecks - """ +def setup_ruleset_rc(target_rootchecks, activated_rootchecks): - str_title = "updated" if r_action == "update" else "installed" - logger.log("\nThe following rootchecks will be {0}:".format(str_title)) + logger.log("\nThe following rootchecks will be updated:") for t_rootcheck in target_rootchecks: logger.log("\t{0}".format(t_rootcheck)) - logger.logstdout("") + logger.stdout("") for item in target_rootchecks: logger.log("{0}:".format(item)) @@ -1073,7 +952,7 @@ def setup_ruleset_rc(target_rootchecks, r_action): logger.log("\t\t[Done]") # ossec.conf - if r_action != "update": + if item in activated_rootchecks: logger.log("\tActivating rootchecks in ossec.conf.") setup_ossec_conf(item, "rootcheck") logger.log("\t\t[Done]") @@ -1088,48 +967,48 @@ def compatibility_with_old_versions(): shutil.copyfile(src_file, dest_file) +def clean_directory(): + if os.path.exists(downloads_directory): + shutil.rmtree(downloads_directory) + + # Main def usage(): msg = """ -OSSEC Wazuh Ruleset installer & updater v2.2 +OSSEC Wazuh Ruleset Update v2.3 Github repository: https://github.com/wazuh/ossec-rules Full documentation: http://documentation.wazuh.com/en/latest/ossec_ruleset.html -Usage: ./ossec_ruleset.py -r [-u | -f conf.txt] [-s] # Rules - ./ossec_ruleset.py -c [-u | -f conf.txt] [-s] # Rootchecks - ./ossec_ruleset.py -a [-u | -f conf.txt] [-s] # All: Rules & Rootchecks - ./ossec_ruleset.py -b [list | backup_name] # Restore backup +Usage: ./ossec_ruleset.py # Update Rules & Rootchecks + ./ossec_ruleset.py -a # Update and prompt menu to activate new Rules & Rootchecks + ./ossec_ruleset.py -s # Update Rules & Rootchecks - Silent Mode + ./ossec_ruleset.py -b 20160201_000 # Restore specific backup Select ruleset: -\t-r, --rules -\t-c, --rootchecks -\t-a, --all +\t-r, --rules\tUpdate rules +\t-c, --rootchecks\tUpdate rootchecks +\t*If not -r or -c indicated, rules and rootchecks will be updated. + +Activate: +\t-a, --activate\tPrompt a interactive menu for selection of rules and rootchecks to activate. +\t-A, --activate-file\tUse a configuration file to select rules and rootchecks to activate. +\t*If not -a or -A indicated, NEW rules and rootchecks will NOT activated. -Select action: -\tno arguments\tInteractive menu for selection of rules and rootchecks to install. -\t-f, --file\tUse a configuration file to select rules and rootchecks to install. -\t-u, --update\tUpdate existing ruleset. +Restart: +\t-s, --restart\tRestart OSSEC when required. +\t-S, --no-restart\tDo not restart OSSEC when required. -Additional params: -\t-s, --silent\tForce OSSEC restart when required. +Backups: \t-b, --backups\tRestore backups. Use 'list' to show the backups list available. -Configuration file syntax using option -f: +Additional Params: +\t-f, --force-update\tForce to update all rules and rootchecks. By default, only it is updated the new/changed rules/rootchecks. + +Configuration file syntax using option -A: \t# Commented line -\trules:new_rule_name -\trootchecks:new_rootcheck_name - -############################################################################################## -Examples: -Manually choose rules to install: ./ossec_ruleset.py -r -Update rules: ./ossec_ruleset.py -r -u -Use a configuration file to select rules to install: ./ossec_ruleset.py -r -f new_rules.conf -\tnew_rules.conf content example:\n\trules:puppet\n\trules:netscaler - -Show backups list and select backup to restore: ./ossec_ruleset.py -b list -Restore a specific backup: ./ossec_ruleset.py -b 20151203_00 -############################################################################################## +\trules:rule_name +\trootchecks:rootcheck_name """ print(msg) @@ -1139,28 +1018,31 @@ def usage(): MAX_BACKUPS = 50 url_ruleset = "http://ossec.wazuh.com/ruleset/ruleset.zip" # url_ruleset = "http://ossec.wazuh.com/ruleset/ruleset_development.zip" - - # Vars ossec_path = "/var/ossec" ossec_conf = "{0}/etc/ossec.conf".format(ossec_path) updater_path = "{0}/update/ruleset".format(ossec_path) - # updater_path = "." bk_directory = "{0}/backups".format(updater_path) log_path = "{0}/ossec_ruleset.log".format(updater_path) version_path = "{0}/VERSION".format(updater_path) script_path = "{0}/ossec_ruleset.py".format(updater_path) - new_rules_path = "{0}/rules-decoders".format(updater_path) - new_rootchecks_path = "{0}/rootcheck".format(updater_path) downloads_directory = "{0}/downloads".format(updater_path) + new_rules_path = "{0}/ossec-rules/rules-decoders".format(downloads_directory) + new_rootchecks_path = "{0}/ossec-rules/rootcheck".format(downloads_directory) + + # Vars today_date = date.today().strftime('%Y%m%d') - ruleset_version = "0.100" # Default - ruleset_type = "" - action = "manual" manual_steps = [] - silent = False - mandatory_args = 0 restart_ossec = False - backups = False + type_ruleset = "all" # rules, rootchecks, all + backup_name = "N/A" + activate_file = "N/A" + activate_args = 0 + mandatory_args = 0 + action_activate = "no-activate" # no-activate, menu, file + action_restart = "ask-restart" # ask-restart, restart, no-restart + restart_args = 0 + action_backups = False + action_force = False # Capture Cntrl + C signal.signal(signal.SIGINT, signal_handler) @@ -1172,10 +1054,10 @@ def usage(): # Check arguments try: - opts, args = getopt.getopt(sys.argv[1:], "rcauhsb:f:", - ["rules", "rootchecks", "all", "update", "help", "silent", "backups=", "file="]) - if not opts or not (1 <= len(opts) <= 3): - print("Incorrect number of arguments. Expected 1 or 2 arguments.\nTry './ossec_ruleset.py --help' for more information.") + opts, args = getopt.getopt(sys.argv[1:], "rcb:aA:sSfh", + ["rules", "rootchecks", "backups=", "activate", "activate-file=", "restart", "no-restart", "force-update", "help"]) + if len(opts) > 4: + print("Incorrect number of arguments.\nTry './ossec_ruleset.py --help' for more information.") sys.exit() except getopt.GetoptError as err: print(str(err)) @@ -1184,42 +1066,40 @@ def usage(): for o, a in opts: if o in ("-r", "--rules"): - ruleset_type = "rules" + type_ruleset = "rules" mandatory_args += 1 elif o in ("-c", "--rootchecks"): - ruleset_type = "rootchecks" + type_ruleset = "rootchecks" mandatory_args += 1 - elif o in ("-a", "--all"): - ruleset_type = "all" + elif o in ("-b", "--backups"): + action_backups = "backups" + backup_name = a mandatory_args += 1 - elif o in ("-u", "--update"): - action = "update" + elif o in ("-a", "--activate"): + action_activate = "menu" + activate_args += 1 + elif o in ("-A", "--activate-file"): + action_activate = "file" + activate_file = a + activate_args += 1 + elif o in ("-s", "--restart"): + action_restart = "restart" + restart_args += 1 + elif o in ("-S", "--no-restart"): + action_restart = "no-restart" + restart_args += 1 + elif o in ("-f", "--force-update"): + action_force = True elif o in ("-h", "--help"): usage() sys.exit() - elif o in ("-s", "--silent"): - silent = True - elif o in ("-b", "--backups"): - backups = True - action = a - mandatory_args += 1 - elif o in ("-f", "--file"): - action = "file:{0}".format(a) else: usage() sys.exit() - if backups and not (len(opts) == 1 or silent): - print("Try with: ./ossec_ruleset.py -b list or ./ossec_ruleset.py -b backup_name") - print("Try './ossec_ruleset.py --help' for more information.") - sys.exit() - - if mandatory_args != 1: - print("Mandatory arguments: -r | -c | -a | -b") - usage() - sys.exit() - - str_mode = "updated" if action == "update" else "installed" + if mandatory_args > 1 or restart_args > 1 or activate_args > 1: + print("Bad arguments combination.\nTry './ossec_ruleset.py --help' for more information.") + sys.exit(2) # Create folder updater_path if not os.path.exists(updater_path): @@ -1227,8 +1107,11 @@ def usage(): # Log logger = LogFile(log_path, "wazuh_ossec_ruleset") + # logger.set_debug(True) - logger.logfile("Starting ossec_ruleset.py") + logger.debug("Args:") + logger.debug("\ttype_ruleset: '{0}'\n\taction_backups: '{1}'\n\tbackup_name: '{2}'\n\tmandatory_args: '{3}'\n\taction_activate: '{4}'\n\tactivate_file: '{5}'\n\tactivate_args: '{6}'\n\taction_restart: '{7}'\n\trestart_args: '{8}'\n\taction_force: '{9}'".format(type_ruleset, action_backups, backup_name, mandatory_args, action_activate, activate_file, activate_args, action_restart, restart_args, action_force)) + logger.file("Starting ossec_ruleset.py") # Get uid:gid = root:ossec try: @@ -1244,14 +1127,10 @@ def usage(): # Get OSSEC Version ossec_version = get_ossec_version() - # Restart ossec when install ruleset. - # When it is an update -> restart_ossec is changed in get_rulset_from_update() - if action != "update": - restart_ossec = True + logger.debug("\nRuleset version: '{0}'\tOSSEC Version: '{1}'".format(ruleset_version, ossec_version)) # Title - logger.log("\nOSSEC Wazuh Ruleset [{0}], {1}\n".format(ruleset_version, today_date)) - logger.log("Note: All necessary files will be saved at '{0}'".format(updater_path)) + logger.log("\nOSSEC Wazuh Ruleset [{0}], {1}".format(ruleset_version, today_date)) # Backups logger.log("\nCreating a backup for folders '{0}/etc' and '{0}/rules'.".format(ossec_path)) @@ -1259,10 +1138,10 @@ def usage(): logger.log("\tBackup folder: {0}\n\t[Done]".format(dir_bk)) # Restore backups - if backups: + if action_backups: logger.log("\nRestore Tool:") - if action != "list": - restore_backups(action) + if backup_name != "list": + restore_backups(backup_name) else: restore_backups("0") logger.log("\t[Done]") @@ -1272,64 +1151,79 @@ def usage(): setup_wazuh_directory_structure() logger.log("\t[Done]") - # Get new ruleset - if ruleset_type != "all": - ruleset = get_ruleset(ruleset_type, action)[ruleset_type] + # Download ruleset + logger.log("\nDownloading new ruleset.") + download_ruleset() + logger.log("\t[Done]") + + # Checks + logger.log("\nChecking new ruleset.") + ruleset_to_update = get_ruleset_to_update(action_force) + if action_force: + restart_ossec = True + logger.debug("\t*Ruleset to update*: {0}".format(ruleset_to_update)) + logger.log("\t[Done]") - if not ruleset: - logger.log("\nNo new {0} to be {1}.".format(ruleset_type, str_mode)) - logger.logfile("Ending ossec_ruleset.py") - sys.exit() - else: - ruleset = get_ruleset("all", action) - rules = ruleset["rules"] - rootchecks = ruleset["rootchecks"] - - if not rules: - logger.log("\nNo new rules to be {0}.".format(str_mode)) - if not rootchecks: - logger.log("\nNo new rootchecks to be {0}.".format(str_mode)) - - if not rules and not rootchecks: - logger.logfile("Ending ossec_ruleset.py") - sys.exit() - - # Setup ruleset - if ruleset_type == "all": - if rules: - manual_steps = setup_ruleset_r(rules, action) - if rootchecks: - setup_ruleset_rc(rootchecks, action) - elif ruleset_type == "rules": - manual_steps = setup_ruleset_r(ruleset, action) - elif ruleset_type == "rootchecks": - setup_ruleset_rc(ruleset, action) + if not ruleset_to_update['rules'] and not ruleset_to_update['rootchecks']: + # Clean directory + logger.log("\nCleaning directory.") + clean_directory() + logger.log("\t[Done]") + + logger.log("\n*Your ruleset is up to date.*") + logger.log("\n\nWazuh.com") + logger.file("Ending ossec_ruleset.py") + sys.exit() + if not ruleset_to_update['rules'] and type_ruleset != "rootchecks": + logger.log("\n*Your rules are up to date.*") + if not ruleset_to_update['rootchecks'] and type_ruleset != "rules": + logger.log("\n*Your rootchecks are up to date.*") + + # Activate ruleset (no-activate, menu, file) + if action_activate == "menu": + activated_ruleset = activate_from_menu(ruleset_to_update) + elif action_activate == "file": + activated_ruleset = activate_from_file(ruleset_to_update) + else: # no-activate + activated_ruleset = {'rules': [], 'rootchecks': []} + + if activated_ruleset['rules'] or activated_ruleset['rootchecks']: + restart_ossec = True + + # Update + logger.debug("\tActivated ruleset: {0}".format(activated_ruleset)) + if ruleset_to_update['rules']: + setup_ruleset_r(ruleset_to_update['rules'], activated_ruleset['rules']) + if ruleset_to_update['rootchecks']: + setup_ruleset_rc(ruleset_to_update['rootchecks'], activated_ruleset['rootchecks']) # PATCH for OSSEC != Wazuh - if ossec_version == "old" and action == "update" and ruleset_type != "rootchecks": + if ossec_version == "old" and type_ruleset != "rootchecks": compatibility_with_old_versions() + # Clean directory + logger.log("\nCleaning directory.") + clean_directory() + logger.log("\t[Done]") + # Restart ossec if restart_ossec: - if not silent: + if action_restart == "ask-restart": logger.log("\nOSSEC requires a restart to apply changes.") - str_msg = "Do you want to restart OSSEC now? [y/N]: " - try: - ans_restart = raw_input(str_msg) - except: - # Python 3 - ans_restart = input(str_msg) - else: + ans_restart = get_stdin("Do you want to restart OSSEC now? [y/N]: ") + elif action_restart == "restart": ans_restart = "y" + elif action_restart == "no-restart": + ans_restart = "n" else: ans_restart = "n" # Messages ret = 0 - if backups: + if action_backups == "backups": success_msg = "\n\n**Backup successfully**" else: - success_msg = "\n\n**Ruleset({0}) {1} successfully**".format(ruleset_version, str_mode) + success_msg = "\n\n**Ruleset({0}) updated successfully**".format(ruleset_version) if ans_restart == "y" or ans_restart == "Y": logger.log("\nRestarting OSSEC.") @@ -1340,7 +1234,7 @@ def usage(): logger.log("\n\n**Ruleset error**") else: logger.log(success_msg) - else: + else: # n if restart_ossec: logger.log("\nDo not forget to restart OSSEC to apply changes.") logger.log(success_msg) @@ -1351,4 +1245,4 @@ def usage(): logger.log("\t{0}".format(step)) logger.log("\n\nWazuh.com") - logger.logfile("Ending ossec_ruleset.py") + logger.file("Ending ossec_ruleset.py") diff --git a/rootcheck/ossec/cis_debian_linux_rcl.txt b/rootcheck/cis_debian_linux_rcl.txt similarity index 97% rename from rootcheck/ossec/cis_debian_linux_rcl.txt rename to rootcheck/cis_debian_linux_rcl.txt index aa1e8786b..f773a207b 100644 --- a/rootcheck/ossec/cis_debian_linux_rcl.txt +++ b/rootcheck/cis_debian_linux_rcl.txt @@ -161,7 +161,7 @@ f:/proc/sys/net/ipv6/ip_forward -> 1; [CIS - Debian Linux - 7.1 - Partition /var without 'nodev' set {CIS: 7.1 Debian Linux} {PCI_DSS: 2.2.4}] [any] [http://www.ossec.net/wiki/index.php/CIS_DebianLinux] f:/etc/fstab -> !r:^# && r:ext2|ext3 && r:/var && !r:nodev; -[CIS - Debian Linux - 7.1 - Partition /tmp without 'nodev' set {CIS: 7.1 Debian Linux}] {PCI_DSS: 2.2.4} [any] [http://www.ossec.net/wiki/index.php/CIS_DebianLinux] +[CIS - Debian Linux - 7.1 - Partition /tmp without 'nodev' set {CIS: 7.1 Debian Linux} {PCI_DSS: 2.2.4}] [any] [http://www.ossec.net/wiki/index.php/CIS_DebianLinux] f:/etc/fstab -> !r:^# && r:ext2|ext3 && r:/tmp && !r:nodev; [CIS - Debian Linux - 7.1 - Partition /opt without 'nodev' set {CIS: 7.1 Debian Linux} {PCI_DSS: 2.2.4}] [any] [http://www.ossec.net/wiki/index.php/CIS_DebianLinux] @@ -181,7 +181,7 @@ f:/etc/fstab -> !r:^# && r:/media && r:user; # Section 8 - Access and authentication -[CIS - Debian Linux - 8.8 - LILO Password not set {CIS: 8.8 Debian Linux} {PCI_DSS: 2.2.4}] [any] [http://www.ossec.net/wiki/index.php/CIS_DebianLinux] +[CIS - Debian Linux - 8.8 - LILO Password not set {CIS: 8.8 Debian Linux} {PCI_DSS: 2.2.4}] [any] [http://www.ossec.net/wiki/index.php/CIS_DebianLinux] f:/etc/lilo.conf -> !r:^# && !r:restricted; f:/etc/lilo.conf -> !r:^# && !r:password=; @@ -191,5 +191,5 @@ f:/boot/grub/menu.lst -> !r:^# && !r:password; [CIS - Debian Linux - 9.2 - Account with empty password present {CIS: 9.2 Debian Linux} {PCI_DSS: 10.2.5}] [any] [http://www.ossec.net/wiki/index.php/CIS_DebianLinux] f:/etc/shadow -> r:^\w+::; -[CIS - Debian Linux - 13.11 - Non-root account with uid 0 {CIS: 13.11 Debian Linux} {PCI_DSS: 10.2.5}] [any] [http://www.ossec.net/wiki/index.php/CIS_DebianLinux] +[CIS - Debian Linux - 13.11 - Non-root account with uid 0 {CIS: 13.11 Debian Linux} {PCI_DSS: 10.2.5}] [any] [http://www.ossec.net/wiki/index.php/CIS_DebianLinux] f:/etc/passwd -> !r:^# && !r:^root: && r:^\w+:\w+:0:; diff --git a/rootcheck/ossec/cis_rhel5_linux_rcl.txt b/rootcheck/cis_rhel5_linux_rcl.txt similarity index 99% rename from rootcheck/ossec/cis_rhel5_linux_rcl.txt rename to rootcheck/cis_rhel5_linux_rcl.txt index 634abdeac..15bc00118 100644 --- a/rootcheck/ossec/cis_rhel5_linux_rcl.txt +++ b/rootcheck/cis_rhel5_linux_rcl.txt @@ -422,7 +422,7 @@ f:/proc/sys/net/ipv4/conf/default/send_redirects -> 0; f:/proc/sys/net/ipv4/conf/all/accept_source_route -> 1; # 4.2.2 Disable ICMP Redirect Acceptance (Scored) -CIS - RHEL5 - 4.2.2 - Network parameters - ICMP redirects accepted {CIS: 4.2.2 RHEL5} {PCI_DSS: 2.2.4}] [any] [http://www.ossec.net/wiki/index.php/CIS_RHEL5 -] +[CIS - RHEL5 - 4.2.2 - Network parameters - ICMP redirects accepted {CIS: 4.2.2 RHEL5} {PCI_DSS: 2.2.4}] [any] [http://www.ossec.net/wiki/index.php/CIS_RHEL5 -] f:/proc/sys/net/ipv4/conf/all/accept_redirects -> 1; f:/proc/sys/net/ipv4/conf/default/accept_redirects -> 1; diff --git a/rootcheck/ossec/cis_rhel6_linux_rcl.txt b/rootcheck/cis_rhel6_linux_rcl.txt similarity index 99% rename from rootcheck/ossec/cis_rhel6_linux_rcl.txt rename to rootcheck/cis_rhel6_linux_rcl.txt index aa6a0cec7..e4814a71e 100644 --- a/rootcheck/ossec/cis_rhel6_linux_rcl.txt +++ b/rootcheck/cis_rhel6_linux_rcl.txt @@ -388,7 +388,7 @@ f:/proc/sys/net/ipv4/conf/default/send_redirects -> 0; f:/proc/sys/net/ipv4/conf/all/accept_source_route -> 1; # 4.2.2 Disable ICMP Redirect Acceptance (Scored) -#CIS - RHEL6 - 4.2.2 - Network parameters - ICMP redirects accepted {CIS: 1.1.1 RHEL6} {PCI_DSS: 2.2.4}] [any] [http://www.ossec.net/wiki/index.php/CIS_RHEL6 -] +#[CIS - RHEL6 - 4.2.2 - Network parameters - ICMP redirects accepted {CIS: 1.1.1 RHEL6} {PCI_DSS: 2.2.4}] [any] [http://www.ossec.net/wiki/index.php/CIS_RHEL6 -] #f:/proc/sys/net/ipv4/conf/all/accept_redirects -> 1; #f:/proc/sys/net/ipv4/conf/default/accept_redirects -> 1; diff --git a/rootcheck/ossec/cis_rhel_linux_rcl.txt b/rootcheck/cis_rhel_linux_rcl.txt similarity index 100% rename from rootcheck/ossec/cis_rhel_linux_rcl.txt rename to rootcheck/cis_rhel_linux_rcl.txt diff --git a/rootcheck/ossec/rootkit_files.txt b/rootcheck/rootkit_files.txt similarity index 100% rename from rootcheck/ossec/rootkit_files.txt rename to rootcheck/rootkit_files.txt diff --git a/rootcheck/ossec/rootkit_trojans.txt b/rootcheck/rootkit_trojans.txt similarity index 100% rename from rootcheck/ossec/rootkit_trojans.txt rename to rootcheck/rootkit_trojans.txt diff --git a/rootcheck/ossec/system_audit_rcl.txt b/rootcheck/system_audit_rcl.txt similarity index 100% rename from rootcheck/ossec/system_audit_rcl.txt rename to rootcheck/system_audit_rcl.txt diff --git a/rootcheck/ssh/system_audit_ssh.txt b/rootcheck/system_audit_ssh.txt similarity index 85% rename from rootcheck/ssh/system_audit_ssh.txt rename to rootcheck/system_audit_ssh.txt index 411b6fc38..a4d8e4254 100644 --- a/rootcheck/ssh/system_audit_ssh.txt +++ b/rootcheck/system_audit_ssh.txt @@ -13,14 +13,14 @@ $sshd_file=/etc/ssh/sshd_config; # Listen PORT != 22 # The option Port specifies on which port number ssh daemon listens for incoming connections. # Changing the default port you may reduce the number of successful attacks from zombie bots, an attacker or bot doing port-scanning can quickly identify your SSH port. -[SSH Hardening - 1: Port 22] [any] [1] +[SSH Hardening - 1: Port 22 {PCI_DSS: 2.2.4}] [any] [1] f:$sshd_file -> !r:^# && r:Port\.+22; # Protocol 2 # The Protocol parameter dictates which version of the SSH communication and encryption protocols are in use. # Version 1 of the SSH protocol has weaknesses. -[SSH Hardening - 2: Protocol 1] [any] [2] +[SSH Hardening - 2: Protocol 1 {PCI_DSS: 2.2.4}] [any] [2] f:$sshd_file -> !r:^# && r:Protocol\.+1; @@ -35,7 +35,7 @@ f:$sshd_file -> r:^#\s*PermitRootLogin; # PubkeyAuthentication yes # Access only by public key # Generally people will use weak passwords and have poor password practices. Keys are considered stronger than password. -[SSH Hardening - 4: No Public Key autentication] [any] [4] +[SSH Hardening - 4: No Public Key autentication {PCI_DSS: 2.2.4}] [any] [4] f:$sshd_file -> !r:^# && r:PubkeyAuthentication\.+no; f:$sshd_file -> r:^#\s*PubkeyAuthentication; @@ -43,7 +43,7 @@ f:$sshd_file -> r:^#\s*PubkeyAuthentication; # PasswordAuthentication no # The option PasswordAuthentication specifies whether we should use password-based authentication. # Use public key authentication instead of passwords -[SSH Hardening - 5: Password Authentication] [any] [5] +[SSH Hardening - 5: Password Authentication {PCI_DSS: 2.2.4}] [any] [5] f:$sshd_file -> !r:^# && r:PasswordAuthentication\.+yes; f:$sshd_file -> r:^#\s*PasswordAuthentication; @@ -51,7 +51,7 @@ f:$sshd_file -> r:^#\s*PasswordAuthentication; # PermitEmptyPasswords no # The option PermitEmptyPasswords specifies whether the server allows logging in to accounts with a null password # Accounts with null passwords are a bad practice. -[SSH Hardening - 6: Empty passwords allowed] [any] [6] +[SSH Hardening - 6: Empty passwords allowed {PCI_DSS: 2.2.4}] [any] [6] f:$sshd_file -> !r:^# && r:PermitEmptyPasswords\.+yes; f:$sshd_file -> r:^#\s*PermitEmptyPasswords; @@ -59,7 +59,7 @@ f:$sshd_file -> r:^#\s*PermitEmptyPasswords; # IgnoreRhosts yes # The option IgnoreRhosts specifies whether rhosts or shosts files should not be used in authentication. # For security reasons it is recommended to no use rhosts or shosts files for authentication. -[SSH Hardening - 7: Rhost or shost used for authentication] [any] [7] +[SSH Hardening - 7: Rhost or shost used for authentication {PCI_DSS: 2.2.4}] [any] [7] f:$sshd_file -> !r:^# && r:IgnoreRhosts\.+no; f:$sshd_file -> r:^#\s*IgnoreRhosts; @@ -67,7 +67,7 @@ f:$sshd_file -> r:^#\s*IgnoreRhosts; # LoginGraceTime 30 # The option LoginGraceTime specifies how long in seconds after a connection request the server will wait before disconnecting if the user has not successfully logged in. # 30 seconds is the recommended time for avoiding open connections without authenticate -[SSH Hardening - 8: Wrong Grace Time] [any] [8] +[SSH Hardening - 8: Wrong Grace Time {PCI_DSS: 2.2.4}] [any] [8] f:$sshd_file -> !r:^# && r:LoginGraceTime && !r:30\s*$; f:$sshd_file -> r:^#\s*LoginGraceTime; @@ -75,7 +75,7 @@ f:$sshd_file -> r:^#\s*LoginGraceTime; # MaxAuthTries 3 # The MaxAuthTries parameter specifices the maximum number of authentication attempts permitted per connection. Once the number of failures reaches half this value, additional failures are logged. # This should be set to 3. -[SSH Hardening - 9: Wrong Maximum number of authentication attempts] [any] [9] +[SSH Hardening - 9: Wrong Maximum number of authentication attempts {PCI_DSS: 2.2.4}] [any] [9] f:$sshd_file -> !r:^# && r:MaxAuthTries && !r:3\s*$; f:$sshd_file -> r:^#\s*MaxAuthTries; f:$sshd_file -> !r:MaxAuthTries; diff --git a/rootcheck/ossec/win_applications_rcl.txt b/rootcheck/win_applications_rcl.txt similarity index 100% rename from rootcheck/ossec/win_applications_rcl.txt rename to rootcheck/win_applications_rcl.txt diff --git a/rootcheck/ossec/win_audit_rcl.txt b/rootcheck/win_audit_rcl.txt similarity index 100% rename from rootcheck/ossec/win_audit_rcl.txt rename to rootcheck/win_audit_rcl.txt diff --git a/rootcheck/ossec/win_malware_rcl.txt b/rootcheck/win_malware_rcl.txt similarity index 99% rename from rootcheck/ossec/win_malware_rcl.txt rename to rootcheck/win_malware_rcl.txt index 9d0aa6f21..02fb8bb59 100644 --- a/rootcheck/ossec/win_malware_rcl.txt +++ b/rootcheck/win_malware_rcl.txt @@ -37,7 +37,7 @@ f:%WINDIR%\System32\wgareg.exe; r:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\wgareg; # http://www.f-prot.com/virusinfo/descriptions/sober_j.html -[Sober Worm] {PCI_DSS: 11.4} [any] [] +[Sober Worm {PCI_DSS: 11.4}] [any] [] f:%WINDIR%\System32\nonzipsr.noz; f:%WINDIR%\System32\clonzips.ssc; f:%WINDIR%\System32\clsobern.isc; diff --git a/rules-decoders/amazon-ec2/amazon-ec2_rules.xml b/rules-decoders/amazon-ec2/amazon-ec2_rules.xml index 215f2de5f..e0c0cc42a 100644 --- a/rules-decoders/amazon-ec2/amazon-ec2_rules.xml +++ b/rules-decoders/amazon-ec2/amazon-ec2_rules.xml @@ -514,42 +514,42 @@ 80300 CreateTags - Amazon-ec2: Create Tags + Amazon-ec2-vpc: Create Tags amazon, 80384 "errorCode":"Client.UnauthorizedOperation" - Amazon-ec2: Create Tags Unauthorized + Amazon-ec2-vpc: Create Tags Unauthorized amazon,pci_dss_10.6.1, 80384 "errorCode":" - Amazon-ec2: Create Tags error + Amazon-ec2-vpc: Create Tags error amazon, 80300 DeleteTags - Amazon-ec2: Delete Tags + Amazon-ec2-vpc: Delete Tags amazon, 80388 "errorCode":"Client.UnauthorizedOperation" - Amazon-ec2: Delete Tags Unauthorized + Amazon-ec2-vpc: Delete Tags Unauthorized amazon,pci_dss_10.6.1, 80388 "errorCode":" - Amazon-ec2: Delete Tags error + Amazon-ec2-vpc: Delete Tags error amazon, @@ -938,5 +938,189 @@ amazon, + + 80300 + AssociateAddress + Amazon-ec2: Associate Elastic IP's Address + amazon,pci_dss_10.6.1, + + + + 80445 + "errorCode":"AccessDenied" + Amazon-ec2: Associate Elastic IP's Address Access Denied + amazon,pci_dss_10.2.4, + + + + 80445 + "errorCode":" + Amazon-ec2: Associate Elastic IP's Address error + amazon, + + + + + + 80300 + CreateVpc + Amazon-vpc: Vpc Created + amazon,pci_dss_10.6.1, + + + + 81000 + "errorCode":"Client.UnauthorizedOperation" + Amazon-Vpc: Vpc Created Unauthorized Operation + amazon,pci_dss_10.6.1, + + + + 81000 + "errorCode":"Client.VpcLimitExceeded" + Amazon-Vpc: Vpc Limit Exceeded + amazon,pci_dss_10.6.1, + + + + 81000 + "errorCode":" + Amazon-vpc: Vpc create error + amazon, + + + + 80300 + AssociateDhcpOptions + Amazon-vpc: Asssociate Dhcp Options + amazon,pci_dss_10.6.1, + + + + 81004 + "errorCode":"Client.UnauthorizedOperation" + Amazon-Vpc: Associate Dhcp Options Unauthorized Operation + amazon,pci_dss_10.6.1, + + + + 81004 + "errorCode":" + Amazon-vpc: Associate Dhcp Options error + amazon, + + + + 80300 + CreateSubnet + Amazon-vpc: Crete Subnet + amazon,pci_dss_10.6.1, + + + + 81007 + "errorCode":"Client.UnauthorizedOperation" + Amazon-Vpc: Crete Subnet Unauthorized Operation + amazon,pci_dss_10.6.1, + + + + 81007 + "errorCode":"Client.InvalidSubnet.Range" + Amazon-Vpc: Crete Subnet Invalid Subnet range + amazon,pci_dss_10.6.1, + + + + 81007 + "errorCode":" + Amazon-vpc: Crete Subnet error + amazon, + + + + 80300 + ModifySubnetAttribute + Amazon-vpc: Modify Subnet Attribute + amazon,pci_dss_10.6.1, + + + + 81011 + "errorCode":"Client.UnauthorizedOperation" + Amazon-Vpc: Crete Subnet Unauthorized Operation + amazon,pci_dss_10.6.1, + + + + 81011 + "errorCode":" + Amazon-vpc: Modify Subnet Attribute error + amazon, + + + + 80300 + CreateRouteTable + Amazon-vpc: Create Route Table + amazon,pci_dss_10.6.1, + + + + 81014 + "errorCode":"Client.UnauthorizedOperation" + Amazon-Vpc: Create Route Table Unauthorized Operation + amazon,pci_dss_10.6.1, + + + + 81014 + "errorCode":" + Amazon-vpc: Create Route Table error + amazon, + + + + 80300 + AssociateRouteTable + Amazon-vpc: Associate Route Table + amazon,pci_dss_10.6.1, + + + + 81017 + "errorCode":"Client.UnauthorizedOperation" + Amazon-Vpc: Associate Route Table Unauthorized Operation + amazon,pci_dss_10.6.1, + + + + 81017 + "errorCode":" + Amazon-vpc: Create Route Table error + amazon, + + + + 80300 + DisassociateRouteTable + Amazon-vpc: Disassociate Route Table + amazon,pci_dss_10.6.1, + + + + 81020 + "errorCode":"Client.UnauthorizedOperation" + Amazon-Vpc: Disassociate Route Table Unauthorized Operation + amazon,pci_dss_10.6.1, + + + + 81020 + "errorCode":" + Amazon-vpc: Create Route Table error + amazon, + + diff --git a/rules-decoders/ossec/decoders/kernel-iptables_apparmor_decoders.xml b/rules-decoders/ossec/decoders/kernel-iptables_apparmor_decoders.xml index 192e62bd9..17af42072 100644 --- a/rules-decoders/ossec/decoders/kernel-iptables_apparmor_decoders.xml +++ b/rules-decoders/ossec/decoders/kernel-iptables_apparmor_decoders.xml @@ -1,153 +1,165 @@ - - - - - - - - - ^kernel - - - - iptables - firewall - ^[\d+.\d+] \S+ IN= - - ^[\d+.\d+] (\S+) \.+ SRC=(\S+) DST=(\S+) - \.+ PROTO=(\w+) - action,srcip,dstip,protocol - - - - iptables - firewall - ^SPT=(\d+) DPT=(\d+) - srcport,dstport - - - - iptables - firewall - ^\S+ IN= - - ^(\S+) \.+ SRC=(\S+) DST=(\S+) \.+ - PROTO=(\w+) - action,srcip,dstip,protocol - - - - iptables - firewall - ^SPT=(\d+) DPT=(\d+) - srcport,dstport - - - - iptables - firewall - ^Shorewall:\S+: - - ^(\S+):\.+ SRC=(\S+) DST=(\S+) \.+ - PROTO=(\w+) - action,srcip,dstip,protocol - - - - iptables - firewall - ^SPT=(\d+) DPT=(\d+) - srcport,dstport - - - - iptables - firewall - ^\p\S+\p Shorewall:\S+: - ^(\S+):\.+ SRC=(\S+) DST=(\S+) \.+ - PROTO=(\w+) - action,srcip,dstip,protocol - - - - - - - iptables - apparmor= - apparmor="(\S+)" operation="(\S+)" - status, extra_data - - - - - - iptables - ^[\s\d+.\d+] mptscsih: - ^[\s\d+.\d+] (\w+): (\w+): task abort: (\w+) - id,data,status - - - - iptables - ^[\s\d+.\d+] mptbase: - ^[\s\d+.\d+] (\w+): (\w+):\s+\w+ is now (\w+)\p\s(\D+)$ - id,data,action,status - \ No newline at end of file + + + + + + + + + ^kernel + + + + iptables + firewall + ^[\d+.\d+] \S+ IN= + + ^[\d+.\d+] (\S+) \.+ SRC=(\S+) DST=(\S+) + \.+ PROTO=(\w+) + action,srcip,dstip,protocol + + + + iptables + firewall + ^SPT=(\d+) DPT=(\d+) + srcport,dstport + + + + iptables + firewall + ^\S+ IN= + + ^(\S+) \.+ SRC=(\S+) DST=(\S+) \.+ + PROTO=(\w+) + action,srcip,dstip,protocol + + + + iptables + firewall + ^SPT=(\d+) DPT=(\d+) + srcport,dstport + + + + iptables + firewall + ^Shorewall:\S+: + + ^(\S+):\.+ SRC=(\S+) DST=(\S+) \.+ + PROTO=(\w+) + action,srcip,dstip,protocol + + + + iptables + firewall + ^SPT=(\d+) DPT=(\d+) + srcport,dstport + + + + iptables + firewall + ^\p\S+\p Shorewall:\S+: + ^(\S+):\.+ SRC=(\S+) DST=(\S+) \.+ + PROTO=(\w+) + action,srcip,dstip,protocol + + + + + + + iptables + apparmor= + apparmor="(\S+)" operation="(\S+)" + status, extra_data + + + + + + iptables + ^[\s\d+.\d+] mptscsih: + ^[\s\d+.\d+] (\w+): (\w+): task abort: (\w+) + id,data,status + + + + iptables + ^[\s\d+.\d+] mptbase: + ^[\s\d+.\d+] (\w+): (\w+):\s+\w+ is now (\w+)\p\s(\D+)$ + id,data,action,status + + + + + + iptables + ^(usb) + id + diff --git a/rules-decoders/ossec/decoders/netscreen_decoders.xml b/rules-decoders/ossec/decoders/netscreen_decoders.xml index 1463b71bb..76f7ebbdb 100644 --- a/rules-decoders/ossec/decoders/netscreen_decoders.xml +++ b/rules-decoders/ossec/decoders/netscreen_decoders.xml @@ -28,15 +28,22 @@ - Will extract the action,srcip,dstip,protocol,srcport,dstport - Examples: - Jan 1 10:02:11 xx ns5gt: NetScreen device_id=ns5gt [No Name]system-notification-00257(traffic): start_time="2006-01-01 10:09:38" duration=0 policy_id=310101 service=tcp/port:1526 proto=6 src zone=Null dst zone=self action=Deny sent=0 rcvd=38 src=10.1.2.3 dst=10.1.1.1 src_port=51350 dst_port=1426 - - <13>Mar 16 15:27:56 192.168.2.1 ns5gt: NetScreen device_id=ns5gt [No Name]system-notification-00257(traffic): start_time=\"2004-03-16 16:31:22\" duration=0 policy_id=310001 service=tcp/port:120 proto=6 src zone=Null dst zone=self action=Deny sent=0 rcvd=60 src=10.1.1.1 dst=10.1.2.1 src_port=32047 dst_port=22 + - Mar 16 15:27:56 192.168.2.1 ns5gt: NetScreen device_id=ns5gt [No Name]system-notification-00257(traffic): start_time=\"2004-03-16 16:31:22\" duration=0 policy_id=310001 service=tcp/port:120 proto=6 src zone=Null dst zone=self action=Deny sent=0 rcvd=60 src=10.1.1.1 dst=10.1.2.1 src_port=32047 dst_port=22 - Jun 2 11:24:16 fire00 sav00: NetScreen device_id=sav00 [Root]system-critical-00436: Large ICMP packet! From 210.232.20.7 to 148.100.114.126, proto 1 (zone Untrust, int ethernet1/2). Occurred 1 times. (2006-06-02 11:24:16) - - NetScreen device_id=ns5gt [Root]system-critical-00027: Multiple login failures occurred for user netscreen from IP address 1.2.3.4:1567 (2004-10-07) + - ... NetScreen device_id=ns5gt [Root]system-critical-00027: Multiple login failures occurred for user netscreen from IP address 1.2.3.4:1567 (2004-10-07) + - + - 10.10.10.10 Host: NetScreen device_id=Text - - ** Program name for netscreen is empty, since it is the hostname. --> + + + ^\S+ \S+: NetScreen device_id + + - - ^NetScreen device_id + + ^NetScreen device_id diff --git a/rules-decoders/ossec/rules/syslog_rules.xml b/rules-decoders/ossec/rules/syslog_rules.xml index 9fd96cc33..78727e2f7 100644 --- a/rules-decoders/ossec/rules/syslog_rules.xml +++ b/rules-decoders/ossec/rules/syslog_rules.xml @@ -493,7 +493,7 @@ - + sudo Initial group for sudo messages diff --git a/rules-decoders/ossec/rules/usb_rules.xml b/rules-decoders/ossec/rules/usb_rules.xml new file mode 100644 index 000000000..837d5a9f7 --- /dev/null +++ b/rules-decoders/ossec/rules/usb_rules.xml @@ -0,0 +1,29 @@ + + + + + + iptables + usb + USB messages grouped. + + + + + 81100 + New USB device found + Attached USB Storage + + + + +