#!/usr/bin/env python3 # filename: generate_guidance.py # description: Process a given keyword, and output a baseline file import sys import os import os.path import yaml import glob import re import warnings from pathlib import Path from datetime import datetime import shutil from time import sleep import argparse warnings.filterwarnings("ignore", category=DeprecationWarning) def replace_ocil(xccdf, x): regex = r'''([\r\n].*?)(?:=?\r|\n)(.*?(?:def:{}\").*)'''.format(x) substr = '''''' result = re.sub(regex, substr, xccdf, 0, re.MULTILINE) return result def create_args(): parser = argparse.ArgumentParser( description="Easily generate xccdf, oval, or scap datastream. If no option is defined, it will generate an scap datastream file.") parser.add_argument("-x", "--xccdf", default=None, help="Generate an xccdf file.", action="store_true") parser.add_argument("-o", "--oval", default=None, help="Generate an oval file of the checks.", action="store_true") parser.add_argument("-l", "--list_tags", default=None, help="List the available keyword tags to search for.", action="store_true") parser.add_argument("-b", "--baseline", default="None", help="Choose a baseline to generate an xml file for, if none is specified it will generate for every rule found.", action="store") return parser.parse_args() def generate_scap(all_rules, all_baselines, args): export_as = "" if args.xccdf: export_as = "xccdf" if args.oval: export_as = "oval" if args.oval == None and args.xccdf == None: export_as = "scap" version_file = "../VERSION.yaml" with open(version_file) as r: version_yaml = yaml.load(r, Loader=yaml.SafeLoader) now = datetime.now() date_time_string = now.strftime("%Y-%m-%dT%H:%M:%S") filenameversion = version_yaml['version'].split(",")[1].replace(" ", "_")[1:] output = "../build/macOS_{0}_Security_Compliance_Benchmark-{1}".format(version_yaml['os'],filenameversion) if export_as == "xccdf": output = output + "_xccdf.xml" if export_as == "oval": output = output + "_oval.xml" if export_as == "scap": output = output + ".xml" oval_definition = str() oval_test = str() oval_object = str() oval_state = str() oval_variable = str() xccdf_profiles = str() total_scap = str() scap_groups = str() xccdf_rules = str() x = 1 d = 1 ovalPrefix = ''' 5.11.2 {0} Copyright (c) 2020, NIST. macOS Security Compliance Project '''.format(date_time_string) xccdfPrefix = ''' draft macOS {1}: Security Configuration macOS {1}: Security Configuration Security Content Automation Protocol National Institute of Standards and Technology {2} National Institute of Standards and Technology National Institute of Standards and Technology https://github.com/usnistgov/macos_security/releases/latest Bob Gendler - National Institute of Standards and Technology Dan Brodjieski - National Aeronautics and Space Administration Allen Golbig - Jamf '''.format(date_time_string, version_yaml['os'], version_yaml['version'],date_time_string.split("T")[0] + "Z") scapPrefix = ''' draft macOS {1}: Security Configuration macOS {1}: Security Configuration Security Content Automation Protocol National Institute of Standards and Technology platform-cpe-dictionary platform-cpe-oval {3} National Institute of Standards and Technology National Institute of Standards and Technology https://github.com/usnistgov/macos_security/releases/latest Bob Gendler - National Institute of Standards and Technology Dan Brodjieski - National Aeronautics and Space Administration Allen Golbig - Jamf '''.format(date_time_string, version_yaml['os'], version_yaml['cpe'], version_yaml['version'],date_time_string.split("T")[0] + "Z") generated_baselines = {} for rule in all_rules: if glob.glob('../custom/rules/**/{}.yaml'.format(rule),recursive=True): rule_file = glob.glob('../custom/rules/**/{}.yaml'.format(rule),recursive=True)[0] custom=True elif glob.glob('../rules/*/{}.yaml'.format(rule)): rule_file = glob.glob('../rules/*/{}.yaml'.format(rule))[0] custom=False odv_label = str() og_rule_yaml = get_rule_yaml(rule_file, custom) loop = 1 if "odv" in og_rule_yaml: loop = len(og_rule_yaml['odv']) if args.baseline != "None": loop = 1 for a in range(0, loop): rule_yaml = get_rule_yaml(rule_file, custom) try: # # odv_label = list(rule_yaml['odv'].keys())[a] # # odv_label.remove('hint') if args.baseline != "None": odv_label = args.baseline if args.baseline not in list(rule_yaml['odv'].keys())[a]: odv_label = "recommended" # if args.baseline not in list(rule_yaml['odv'].keys())[a]: # odv_label = "recommended" else: odv_label = list(rule_yaml['odv'].keys())[a] # if odv_label == "hint": # continue odv_value = str(rule_yaml['odv'][odv_label]) rule_yaml['title'] = rule_yaml['title'].replace("$ODV",str(odv_value)) rule_yaml['discussion'] = rule_yaml['discussion'].replace("$ODV",odv_value) rule_yaml['check'] = rule_yaml['check'].replace("$ODV",odv_value) rule_yaml['fix'] = rule_yaml['fix'].replace("$ODV",odv_value) for result_value in rule_yaml['result']: if "$ODV" == rule_yaml['result'][result_value]: rule_yaml['result'][result_value] = rule_yaml['result'][result_value].replace("$ODV",odv_value) if rule_yaml['mobileconfig_info']: for mobileconfig_type in rule_yaml['mobileconfig_info']: if isinstance(rule_yaml['mobileconfig_info'][mobileconfig_type], dict): for mobileconfig_value in rule_yaml['mobileconfig_info'][mobileconfig_type]: if "$ODV" in str(resulting_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value]): resulting_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value] = rule_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value].replace("$ODV",odv_value) except: odv_label = "recommended" for baseline in all_baselines: found_rules = [] for tag in rule_yaml['tags']: if tag == baseline: if odv_label != "recommended" and odv_label == tag or odv_label == "custom": if baseline in generated_baselines: generated_baselines[baseline].append(rule_yaml['id'] + "_" + odv_label) else: generated_baselines[baseline] = [rule_yaml['id'] + "_" + odv_label] continue elif odv_label == "recommended" or odv_label == "custom": if "odv" in rule_yaml: if baseline not in rule_yaml['odv']: if baseline in generated_baselines: generated_baselines[baseline].append(rule_yaml['id'] + "_" + odv_label) else: generated_baselines[baseline] = [rule_yaml['id'] + "_" + odv_label] else: if baseline in generated_baselines: generated_baselines[baseline].append(rule_yaml['id'] + "_" + odv_label) else: generated_baselines[baseline] = [rule_yaml['id'] + "_" + odv_label] if odv_label == "hint": continue result = str() if "result" in rule_yaml: result = "\nResult: {}".format(rule_yaml['result']) else: result = "" severity = str() if "severity" in rule_yaml: severity = rule_yaml['severity'] else: severity = "unknown" check_rule = str() if "inherent" in rule_yaml['tags'] or "n_a" in rule_yaml['tags'] or "permenant" in rule_yaml['tags']: check_rule = ''' ''' else: check_rule = ''' '''.format(x) references = str() if "800-53r5" in rule_yaml['references'] and rule_yaml['references']['800-53r5'][0] != "N/A": references = references + "NIST SP 800-53r5: " for nist80053 in rule_yaml['references']['800-53r5']: references = references + nist80053 + ", " references = references[:-2] + "" if "800-53r4" in rule_yaml['references'] and rule_yaml['references']['800-53r4'][0] != "N/A": references = references + "NIST SP 800-53r4: " for nist80053 in rule_yaml['references']['800-53r4']: references = references + nist80053 + ", " references = references[:-2] + "" if "800-171r2" in rule_yaml['references'] and rule_yaml['references']['800-171r2'][0] != "N/A": references = references + "NIST SP 800-171r2: " for nist800171 in rule_yaml['references']['800-171r2']: references = references + nist800171 + ", " references = references[:-2] + "" if "disa_stig" in rule_yaml['references'] and rule_yaml['references']['disa_stig'][0] != "N/A": references = references + "DISA STIG(s): " for disa_stig in rule_yaml['references']['disa_stig']: references = references + disa_stig + ", " references = references[:-2] + "" if "cis" in rule_yaml['references']: if "benchmark" in rule_yaml['references']['cis'] and rule_yaml['references']['cis']['benchmark'][0] != "N/A": references = references + "CIS Benchmark: " for benchmark in rule_yaml['references']['cis']['benchmark']: references = references + benchmark + ", " references = references[:-2] + "" if "controls v8" in rule_yaml['references']['cis'] and rule_yaml['references']['cis']['controls v8'][0] != "N/A": references = references + "CIS Controls V8: " for v8controls in rule_yaml['references']['cis']['controls v8']: references = references + str(v8controls) + ", " references = references[:-2] + "" for k,v in rule_yaml['references'].items(): if k == "cci" or k == "srg": continue if k == "custom": for i,u in rule_yaml['references']['custom'].items(): references = references + '{0}: '.format(i) for refs in rule_yaml['references']['custom'][i]: references = references + '{0}, '.format(str(refs)) references = references[:-2] + "" cce = str() if "cce" not in rule_yaml['references'] or rule_yaml['references']['cce'] == "N/A": cce = "CCE-11111-1" else: cce = rule_yaml['references']['cce'][0] if export_as == "scap": xccdf_rules = xccdf_rules + ''' {2} {3} {4} {5}{9} {6} {7} {8} '''.format(rule_yaml['id'] + "_" + odv_label, severity, rule_yaml['title'], rule_yaml['discussion'].replace("<","<").replace(">",">").replace("&","&").rstrip(), rule_yaml['check'].replace("<","<").replace(">",">").replace("&","&").rstrip(), result, cce,rule_yaml['fix'].replace("<","<").replace(">",">").replace("&","&"), check_rule, references) if export_as == "xccdf": xccdf_rules = xccdf_rules + ''' {2} {3} {4} {5}{8} {6} {7} '''.format(rule_yaml['id'] + "_" + odv_label, severity, rule_yaml['title'], rule_yaml['discussion'].replace("<","<").replace(">",">").replace("&","&").rstrip(), rule_yaml['check'].replace("<","<").replace(">",">").replace("&","&").rstrip(), result, cce,rule_yaml['fix'].replace("<","<").replace(">",">").replace("&","&"), references) if "inherent" in rule_yaml['tags'] or "n_a" in rule_yaml['tags'] or "permanent" in rule_yaml['tags']: xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "time_machine" in rule_yaml['id'] and "encrypted" in rule_yaml['id']: print(rule_yaml['id'] + " - Manual Check Required") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "bluetooth" in rule_yaml['id'] and "unpaired" in rule_yaml['id']: print(rule_yaml['id'] + " - Manual Check Required") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if rule_yaml['check'][0] != "/" and "[source,bash]" not in rule_yaml['fix']: print(rule_yaml['id'] + " - Manual Check") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "hint" in rule_yaml['check'] and "dscl" in rule_yaml['check']: print(rule_yaml['id'] + " - no relevant oval") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "manual" in rule_yaml['tags']: print(rule_yaml['id'] + " - Manual Check") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "eficheck" in rule_yaml['check']: print(rule_yaml['id'] + " - eficheck - no relevant oval") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "newsyslog.conf" in rule_yaml['check'] or "asl.conf" in rule_yaml['check'] or "aslmanager" in rule_yaml['check']: print(rule_yaml['id'] + " - Manual Check Required") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "/usr/bin/pwpolicy getaccountpolicies" in rule_yaml['check']: print(rule_yaml['id'] + " - pwpolicy getaccountpolicies - no relevant oval") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "find" in rule_yaml['check'].split(" ")[0] and rule_yaml['id'] != "os_home_folders_secure": print(rule_yaml['id'] + " - no relevant oval") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "/usr/sbin/firmwarepasswd" in rule_yaml['check']: print(rule_yaml['id'] + " - no relevant oval") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "os_home_folders_secure" in rule_yaml['id']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label, rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' .* oval:mscp:ste:{} '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x+999,x+999) oval_state = oval_state + ''' true true true false false false false false false ^[^_\s].* 0 0 /usr/bin/false '''.format(rule_yaml['id'] + "_" + odv_label,x,x+999) oval_variable = oval_variable + ''' '''.format(x,x+999) x = x + 1 continue if rule_yaml['mobileconfig']: if "spctl" in rule_yaml['check']: if "verbose" in rule_yaml['check']: xccdf_rules = replace_ocil(xccdf_rules,x) x = x + 1 continue else: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' '''.format(x,rule_yaml['id']) oval_state = oval_state + ''' true '''.format(rule_yaml['id'] + "_" + odv_label,x) x += 1 continue for payload_type, info in rule_yaml['mobileconfig_info'].items(): if payload_type == "com.apple.systempolicy.control": continue if payload_type == "com.apple.ManagedClient.preferences": for payload_domain, settings in info.items(): oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip()) if len(settings) > 1: oval_definition = oval_definition + '''''' else: oval_definition = oval_definition + '''''' for key, value in settings.items(): state_kind = "" if type(value) == bool: state_kind = "boolean" elif type(value) == int: state_kind = "int" elif type(value) == str: state_kind = "string" dz = d + 5000 oval_definition = oval_definition + ''''''.format(rule_yaml['id'] + '_' + odv_label + "_" + str(d), dz) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label + "_" + str(d),dz,dz,dz) if payload_domain == "com.apple.dock": oval_object = oval_object + ''' /Library/Preferences/com.apple.loginwindow.plist /plist/dict/key[string()="lastUserName"]/following-sibling::*[1]/text() //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(x+1999,key,dz,x,key) oval_variable = oval_variable + ''' /Library/Managed Preferences/ /com.apple.dock.plist '''.format(x,x+1999) else: oval_object = oval_object + ''' /Library/Managed Preferences/{}.plist //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(rule_yaml['id'] + "_" + odv_label,dz,payload_domain,key) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,dz,state_kind,value) d += 1 x += 1 oval_definition = oval_definition + ''' ''' continue for key, value in info.items(): if key == "familyControlsEnabled": xpath_search = "" if len(info) > 1: xpath_search = info['pathBlackList'] oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' /Library/Managed Preferences/com.apple.applicationaccess.new.plist boolean(plist/dict/array/string/text() = "{}") '''.format(rule_yaml['id'] + "_" + odv_label,x,str(xpath_search).replace('[',"").replace(']',"").replace("'","")) oval_state = oval_state + ''' true '''.format(rule_yaml['id'] + "_" + odv_label,x) x = x + 1 continue else: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' /Library/Managed Preferences/{}.plist'''.format(rule_yaml['id'] + "_" + odv_label,x,payload_type) state_kind = "" if type(value) == bool: oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) state_kind = "boolean" elif type(value) == int: state_kind = "int" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) elif type(value) == str: state_kind = "string" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,state_kind,value) x = x + 1 continue if payload_type == "com.apple.finder": oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' /Library/Preferences/com.apple.loginwindow.plist /plist/dict/key[string()="lastUserName"]/following-sibling::*[1]/text() '''.format(x+1999,rule_yaml['id'] + "_" + odv_label,x,x) state_kind = "" if type(value) == bool: oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) state_kind = "boolean" elif type(value) == int: state_kind = "int" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) elif type(value) == str: state_kind = "string" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,state_kind,value) oval_variable = oval_variable + ''' /Library/Managed Preferences/ /com.apple.finder.plist '''.format(x,x+1999) x += 1 continue if payload_type == "com.apple.DiscRecording": oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' /Library/Preferences/com.apple.loginwindow.plist /plist/dict/key[string()="lastUserName"]/following-sibling::*[1]/text() '''.format(x+1999,rule_yaml['id'] + "_" + odv_label,x,x) state_kind = "" if type(value) == bool: oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) state_kind = "boolean" elif type(value) == int: state_kind = "int" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) elif type(value) == str: state_kind = "string" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,state_kind,value) oval_variable = oval_variable + ''' /Library/Managed Preferences/ /com.apple.DiscRecording.plist '''.format(x,x+1999) x += 1 continue if payload_type == "com.apple.Safari" and key == "AutoOpenSafeDownloads": oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' /Library/Preferences/com.apple.loginwindow.plist /plist/dict/key[string()="lastUserName"]/following-sibling::*[1]/text() '''.format(x+1999,rule_yaml['id'] + "_" + odv_label,x,x) state_kind = "" if type(value) == bool: oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) state_kind = "boolean" elif type(value) == int: state_kind = "int" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) elif type(value) == str: state_kind = "string" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,state_kind,value) oval_variable = oval_variable + ''' /Library/Managed Preferences/ /com.apple.Safari.plist '''.format(x,x+1999) x += 1 continue if payload_type == "com.apple.systempreferences" and key == "DisabledPreferencePanes" or payload_type == "com.apple.systempreferences" and key == "HiddenPreferencePanes" or payload_type == "com.apple.systempreferences" and key == "DisabledSystemSettings": oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' /Library/Preferences/com.apple.loginwindow.plist /plist/dict/key[string()="lastUserName"]/following-sibling::*[1]/text() /plist/dict/key[string()="{}"]/following-sibling::*[1]/string[string()="{}"]/text() '''.format(x+1999,rule_yaml['id'] + "_" + odv_label,x,x,key,str(value).strip('[]').strip("'")) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,str(value).strip('[]').strip("'")) oval_variable = oval_variable + ''' /Library/Managed Preferences/ /com.apple.systempreferences.plist '''.format(x,x+1999) x += 1 continue state_kind = "" if type(value) == bool: state_kind = "boolean" elif type(value) == int: state_kind = "int" elif type(value) == str: state_kind = "string" else: continue oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' /Library/Managed Preferences/{}.plist'''.format(rule_yaml['id'] + "_" + odv_label,x,payload_type) if state_kind == "boolean": oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) else: oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,state_kind,value) x += 1 continue else: command = rule_yaml['check'].split("/") if "sntp" in rule_yaml['check']: print(rule_yaml['id'] + " - No relevant oval test") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "SPStorageDataType" in rule_yaml['check']: print(rule_yaml['id'] + " - No relevant oval test") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "fdesetup" in command[3]: print(rule_yaml['id'] + " - No relevant oval test") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "profiles" in command[3]: if "/usr/bin/profiles status -type enrollment" in rule_yaml['check']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],x,x+899,x+799) oval_test = oval_test + ''' '''.format(x,x,x+899,x+899,x+799,x+799) oval_object = oval_object + ''' /Library/Managed Preferences/com.apple.extensiblesso.plist /Library/Managed Preferences/com.apple.syspolicy.kernel-extension-policy.plist /Library/Managed Preferences/com.apple.TCC.configuration-profile-policy.plist '''.format(x,x+899,x+799) x += 1 continue if "csrutil" in command[3]: if "authenticated-root" in command[3]: print(rule_yaml['id'] + " - No relevant oval test") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' SPSoftwareDataType //*[contains(text(), "system_integrity")]/following-sibling::string[position()=1]/text() '''.format(rule_yaml['id'] + "_" + odv_label,x) oval_state = oval_state + ''' SPSoftwareDataType //*[contains(text(), "system_integrity")]/following-sibling::string[position()=1]/text() integrity_enabled '''.format(rule_yaml['id'] + "_" + odv_label,x) x += 1 continue if "pfctl" in rule_yaml['check']: print(rule_yaml['id'] + " - No relevant oval test") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "dump-keychain" in rule_yaml['check']: print(rule_yaml['id'] + " - No relevant oval test") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "mdmclient" in command[3]: print(rule_yaml['id'] + " - No relevant oval test") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "nvram" in command[3]: print(rule_yaml['id'] + " - No relevant oval test") xccdf_rules = replace_ocil(xccdf_rules,x) x += 1 continue if "pmset" in command[3] and "standby" in rule_yaml['check']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] +"_standbydelayhigh",x, rule_yaml['id'] +"_standbydelaylow",x+877, rule_yaml['id'] +"_highstandbythreshold",x+888) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_standbydelayhigh",x,x,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_standbydelaylow",x+877,x+877,x+877) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_highstandbythreshold",x+888,x+888,x+888) standbydelayhigh = str() standbydelaylow = str() highstandbythreshold = str() for line in rule_yaml['fix'].split("----")[1].split("\n"): if line == "": continue if "standbydelayhigh" in line: standbydelayhigh = line.split(" ")[-1].rstrip() if "standbydelaylow" in line: standbydelaylow = line.split(" ")[-1].rstrip() if "highstandbythreshold" in line: highstandbythreshold = line.split(" ")[-1].rstrip() oval_object = oval_object + ''' SPHardwareDataType //*[contains(text(), "platform_UUID")]/following-sibling::string[position()=1]/text() '''.format("hardware UUID",x+999) oval_variable = oval_variable + ''' /Library/Preferences/com.apple.PowerManagement. .plist '''.format(x,x+999) oval_object = oval_object + ''' '''.format(rule_yaml['id'] + "_standbydelayhigh",x,x) oval_object = oval_object + ''' boolean(plist/dict[key="AC Power"]/dict[key="{}"]/integer/text() = "{}") '''.format("High Standby Delay",standbydelayhigh) oval_object = oval_object + ''' '''.format(rule_yaml['id'] + "_standbydelaylow",x+877, x) oval_object = oval_object + ''' boolean(plist/dict[key="AC Power"]/dict[key="{}"]/integer/text() = "{}") '''.format("Standby Delay",standbydelaylow) oval_object = oval_object + ''' '''.format(rule_yaml['id'] + "_highstandbythreshold",x+888, x) oval_object = oval_object + ''' boolean(plist/dict[key="AC Power"]/dict[key="{}"]/integer/text() = "{}") '''.format("Standby Battery Threshold",highstandbythreshold) oval_state = oval_state + ''' true '''.format(rule_yaml['id'] + "_standbydelayhigh",x) oval_state = oval_state + ''' true '''.format(rule_yaml['id'] + "_standbydelaylow",x+877) oval_state = oval_state + ''' true '''.format(rule_yaml['id'] + "_highstandbythreshold",x+888) x += 1 continue if "sudo -V" in rule_yaml['check']: if "grep" in rule_yaml['check'].split("|")[1]: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label, x, rule_yaml['id'] + "_" + odv_label,x+5051) oval_test = oval_test + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label, x) oval_test = oval_test + ''' '''.format(x+5051, rule_yaml['id'] + "_" + odv_label, x+5051) check_string = rule_yaml['fix'].split("echo")[1].split('"')[1] oval_object = oval_object + ''' /etc/sudoers {} 1 '''.format(x, rule_yaml['id'] + "_" + odv_label, check_string) oval_object = oval_object + ''' /etc/sudoers.d/ * {} 1 '''.format(x+5051, rule_yaml['id'] + "_" + odv_label, check_string) x = x + 1 continue if "awk" in rule_yaml['check'].split("|")[1]: if "timestamp_type" in rule_yaml['fix'] and rule_yaml['result']['string'] == "tty": oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label, x+8000, rule_yaml['id'] + "_" + odv_label,x+8001, rule_yaml['id'] + "_" + odv_label,x+8002,rule_yaml['id'] + "_" + odv_label,x+8003) oval_test = oval_test + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label, x) oval_test = oval_test + ''' '''.format(x+8000, rule_yaml['id'] + "_" + odv_label, x+8000) oval_test = oval_test + ''' '''.format(x+8001, rule_yaml['id'] + "_" + odv_label, x+8001) oval_test = oval_test + ''' '''.format(x+8002, rule_yaml['id'] + "_" + odv_label, x+8002) oval_object = oval_object + ''' /etc/sudoers timestamp_type 1 '''.format(x, rule_yaml['id'] + "_" + odv_label) oval_object = oval_object + ''' /etc/sudoers.d/ * timestamp_type 1 '''.format(x+8000, rule_yaml['id'] + "_" + odv_label) oval_object = oval_object + ''' /etc/sudoers.d/ * !tty_tickets 1 '''.format(x+8001, rule_yaml['id'] + "_" + odv_label) oval_object = oval_object + ''' /etc/sudoers.d/ * !tty_tickets 1 '''.format(x+8002, rule_yaml['id'] + "_" + odv_label) x = x + 1 continue else: check_string = "Defaults.*.timestamp_type={}".format(rule_yaml['result']['string']) oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label, x+8000, rule_yaml['id'] + "_" + odv_label,x+8001, rule_yaml['id'] + "_" + odv_label,x+8002,rule_yaml['id'] + "_" + odv_label,x+8003) oval_test = oval_test + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label, x) oval_test = oval_test + ''' '''.format(x+5000, rule_yaml['id'] + "_" + odv_label, x+7000) oval_object = oval_object + ''' /etc/sudoers {} 1 '''.format(x, rule_yaml['id'] + "_" + odv_label, check_string) oval_object = oval_object + ''' /etc/sudoers.d/ * {} 1 '''.format(x+7000, rule_yaml['id'] + "_" + odv_label, check_string) x = x + 1 continue if "ssh_config" in rule_yaml['discussion'] and "dscl" in rule_yaml['check']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label, x+5000, rule_yaml['id'] + "_" + odv_label,x+5001) oval_test = oval_test + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label, x) oval_test = oval_test + ''' '''.format(x+5000, rule_yaml['id'] + "_" + odv_label, x+5000) oval_test = oval_test + ''' '''.format(x+5001, rule_yaml['id'] + "_" + odv_label, x+5001) regex = r"(?<=grep).*$" matches = re.finditer(regex, rule_yaml['check'], re.MULTILINE) matchy_match = "" for matchNum, match in enumerate(matches, start=1): matchy_match = match.group() ssh_config_pattern = matchy_match.split('"')[1] oval_object = oval_object + ''' /etc/ssh/ssh_config {} 1 '''.format(x, rule_yaml['id'] + "_" + odv_label, ssh_config_pattern) oval_object = oval_object + ''' /etc/ssh/ssh_config.d/ * {} 1 '''.format(x+5000, rule_yaml['id'] + "_" + odv_label, ssh_config_pattern) oval_object = oval_object + ''' {} 1 .* oval:mscp:ste:{} '''.format(x+5001,rule_yaml['id'] + "_" + odv_label,x,ssh_config_pattern,x+999,x+999) oval_state = oval_state + ''' ^[^_\s].* 0 0 /usr/bin/false '''.format(x+999) oval_variable = oval_variable + ''' /.ssh/config '''.format(x,x+999) x = x + 1 continue if "sshd -T" in rule_yaml['check'] and "fips" in rule_yaml['check']: fipslist = rule_yaml['check'].split("\n")[0].split("(")[1].replace(")","").replace('" "',"\n").replace('"',"") oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label, x+5000, rule_yaml['id'] + "_" + odv_label,x+5001) oval_test = oval_test + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label, x) oval_test = oval_test + ''' '''.format(x+5000, rule_yaml['id'] + "_" + odv_label, x+5000) oval_object = oval_object + ''' /etc/ssh/sshd_config {} 1 '''.format(x, rule_yaml['id'] + "_" + odv_label, fipslist) oval_object = oval_object + ''' /etc/ssh/sshd_config.d/ * {} 1 '''.format(x+5000, rule_yaml['id'] + "_" + odv_label, fipslist) x = x + 1 continue if "sshd -T" in rule_yaml['check']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label, x+5000, rule_yaml['id'] + "_" + odv_label,x+5001) oval_test = oval_test + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label, x) oval_test = oval_test + ''' '''.format(x+5000, rule_yaml['id'] + "_" + odv_label, x+5000) sshd_config_pattern = "" if "grep" in rule_yaml['check']: regex = r"(?<=grep).*$" matches = re.finditer(regex, rule_yaml['check'], re.MULTILINE) matchy_match = "" for matchNum, match in enumerate(matches, start=1): matchy_match = match.group() sshd_config_pattern = "" if '"' in matchy_match: sshd_config_pattern = matchy_match.split('"')[1] elif "'" in matchy_match: sshd_config_pattern = matchy_match.split("'")[1] if "awk" in rule_yaml['check']: matchy_match = rule_yaml['check'].split("'")[1].split("/")[1] for item in rule_yaml['result']: sshd_config_pattern = matchy_match + " " + str(rule_yaml['result'][item]) oval_object = oval_object + ''' /etc/ssh/sshd_config {} 1 '''.format(x, rule_yaml['id'] + "_" + odv_label, sshd_config_pattern) oval_object = oval_object + ''' /etc/ssh/sshd_config.d/ * {} 1 '''.format(x+5000, rule_yaml['id'] + "_" + odv_label, sshd_config_pattern) x = x + 1 continue if "pmset" in command[3]: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' /Library/Preferences/com.apple.PowerManagement.plist'''.format(rule_yaml['id'] + "_" + odv_label,x) pmset_key = str() if "powernap" in rule_yaml['check']: pmset_key = "DarkWakeBackgroundTasks" if "womp" in rule_yaml['check']: pmset_key = "Wake On LAN" oval_object = oval_object + ''' boolean(plist/dict[key="AC Power"]/dict[key="{}"]/integer/text() = "{}") '''.format(pmset_key,rule_yaml['fix'].split("----")[1].replace("\n","")[-1]) oval_state = oval_state + ''' true '''.format(rule_yaml['id'] + "_" + odv_label,x) x += 1 continue if "socketfilterfw" in rule_yaml['check']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) if rule_yaml['check'].split()[1] == "--getloggingmode": firewall_variable = "loggingenabled" elif rule_yaml['check'].split()[1] == "--getstealthmode": firewall_variable = "stealthenabled" elif rule_yaml['check'].split()[1] == "--getglobalstate": firewall_variable = "globalstate" oval_object = oval_object + ''' /Library/Preferences/com.apple.alf.plist //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(rule_yaml['id'] + "_" + odv_label,x,firewall_variable) oval_state = oval_state + ''' 1 '''.format(rule_yaml['id'] + "_" + odv_label,x) x += 1 continue if "systemsetup" in command[3]: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x) state_test = "" if "-getnetworktimeserver" in rule_yaml['check']: timeservers = rule_yaml['result']['string'] state_test = ''' {} '''.format(timeservers) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,state_test) abc = 0 if "defaults" in rule_yaml['check'] and "grep" in rule_yaml['check'] and "CURRENT_USER" in rule_yaml['check']: regex = r"(?<=\()(.*?)(?=\))" test_str = rule_yaml['check'].split("grep")[1] matches = re.finditer(regex, test_str, re.MULTILINE) matchy_match = "" for matchNum, match in enumerate(matches, start=1): matchy_match = match.group() oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) for multi_grep in matchy_match.split("|"): oval_definition = oval_definition + ''' '''.format(rule_yaml['id']+"_"+str(abc),x) oval_test = oval_test + ''' '''.format(rule_yaml['id']+"_"+str(abc),x,x,x) key = matchy_match.split("|")[abc].split(" = ")[0].replace("\"","") value = matchy_match.split("|")[abc].split(" = ")[1].replace(";","") if "$CURRENT_USER" in rule_yaml['check']: oval_object = oval_object + ''' .* oval:mscp:ste:{} '''.format(x+1999,x+1999) oval_state = oval_state + ''' ^[^_\s].* 0 0 /usr/bin/false '''.format(x+1999) plist = rule_yaml['check'].split("read")[1].split()[0].replace(".plist","") oval_variable = oval_variable + ''' /Library/Preferences/{}. plist '''.format(x,x+1999,plist) oval_object = oval_object + ''' '''.format(rule_yaml['id']+"_"+str(abc),x,x) oval_datatype = "" try: int(value) oval_datatype = "int" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) except: if value.lower() == "true" or value.lower == "false": oval_datatype = "boolean" oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) else: oval_datatype = "string" oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' {} '''.format(rule_yaml['id']+"_"+str(abc),x,oval_datatype,value) abc =+ 1 x = x+1 oval_definition = oval_definition + ''' ''' oval_definition = re.sub('(?=\n\[NOTE\])(?s)(.*)\=\n<', '<', oval_definition) x = x+1 break if "defaults" in rule_yaml['check']: if rule_yaml['id'] == "system_settings_hot_corners_secure" or rule_yaml['id'] == "sysprefs_hot_corners_secure": oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label,x+5000,rule_yaml['id'] + "_" + odv_label,x+5001,rule_yaml['id'] + "_" + odv_label,x+5002) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x+5000,x+5000,x+5000) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x+5001,x+5001,x+5001) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x+5002,x+5002,x+5002) plist = rule_yaml['check'].split("read")[1].split()[0].replace(".plist","") check_length = len(rule_yaml['check'].split()) key = rule_yaml['check'].split("\n")[0].replace(" 2>/dev/null","").split()[-1].replace('"','').replace(")",'') oval_object = oval_object + ''' .* oval:mscp:ste:{} '''.format(x+1999,x+1999,rule_yaml['id'] + "_" + odv_label,x,x) oval_object = oval_object + '''//*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) key = rule_yaml['check'].split("\n")[1].replace(" 2>/dev/null","").split()[-1].replace('"','').replace(")",'') oval_object = oval_object + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x+5000,x) oval_object = oval_object + '''//*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) key = rule_yaml['check'].split("\n")[2].replace(" 2>/dev/null","").split()[-1].replace('"','').replace(")",'') oval_object = oval_object + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x+5001,x) oval_object = oval_object + '''//*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) key = rule_yaml['check'].split("\n")[3].replace(" 2>/dev/null","").split()[-1].replace('"','').replace(")",'') oval_object = oval_object + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x+5002,x) oval_object = oval_object + '''//*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' ^[^_\s].* 0 0 /usr/bin/false '''.format(x+1999) after_user = plist.split('"')[2] oval_variable = oval_variable + ''' {} .plist '''.format(x,x+1999,after_user,x+999) try: check_if = rule_yaml['check'].split("\n")[5] modifier = 0 for n in check_if.split(): if n.replace('"',"").isdigit(): if modifier >= 4999: modifier = modifier + 1 oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x+modifier,n.replace('"',"")) if modifier == 0: modifier = 4999 x = x + 1 continue except: x = x + 1 continue oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) plist = rule_yaml['check'].split("read")[1].split()[0].replace(".plist","") if "ByHost" in rule_yaml['fix'] or "currentHost" in rule_yaml['fix']: oval_object = oval_object + ''' SPHardwareDataType //*[contains(text(), "platform_UUID")]/following-sibling::string[position()=1]/text() '''.format("hardware UUID",x+999) if "$CURRENT_USER" in rule_yaml['check']: check_length = len(rule_yaml['check'].split()) key = rule_yaml['check'].split()[check_length-1] oval_object = oval_object + ''' .* oval:mscp:ste:{} '''.format(x+1999,x+1999,rule_yaml['id'] + "_" + odv_label,x,x) try: rule_yaml['result']['boolean'] oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) except: oval_object = oval_object + '''//*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' ^[^_\s].* 0 0 /usr/bin/false '''.format(x+1999) oval_variable = oval_variable + ''' /Library/Preferences/ByHost/{}. .plist '''.format(x,x+1999,plist,x+999) else: check_length = len(rule_yaml['check'].split()) key = rule_yaml['check'].replace(" 2>/dev/null","").split()[check_length-1] oval_object = oval_object + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x) try: rule_yaml['result']['boolean'] oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) except: oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_variable = oval_variable + ''' {}. .plist '''.format(x,plist,x+999) elif "$CURRENT_USER" in rule_yaml['check']: check_length = len(rule_yaml['check'].split()) key = rule_yaml['check'].replace(" 2>/dev/null","").split()[-1] oval_object = oval_object + ''' .* oval:mscp:ste:{} '''.format(x+1999,x+1999,rule_yaml['id'] + "_" + odv_label,x,x) try: rule_yaml['result']['boolean'] oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) except: oval_object = oval_object + '''//*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' ^[^_\s].* 0 0 /usr/bin/false '''.format(x+1999) oval_variable = oval_variable + ''' /Library/Preferences/{}. plist '''.format(x,x+1999,plist,x+999) else: if plist[-6:] != ".plist": plist = plist + ".plist" plist_key = rule_yaml['check'].replace(" 2>/dev/null","").split(" ")[3].rstrip() oval_object = oval_object + ''' {}'''.format(rule_yaml['id'] + "_" + odv_label,x,plist) try: rule_yaml['result']['boolean'] oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(plist_key) except: oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(plist_key) datatype = "" plist_key = rule_yaml['check'].split(" ")[3].rstrip() for key in rule_yaml['result']: datatype = key if datatype == "integer": oval_datatype = "int" else: oval_datatype = datatype if oval_datatype == "boolean" and rule_yaml['result'][datatype] == 0: value = "false" elif oval_datatype == "boolean" and rule_yaml['result'][datatype] == 1: value = "true" else: value = rule_yaml['result'][datatype] oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,oval_datatype,value) oval_definition = re.sub('(?=\n\[NOTE\])(?s)(.*)\=\n<', '<', oval_definition) x = x+1 continue if "security" in command[3]: if rule_yaml['check'].split()[1] == "authorizationdb": check = rule_yaml['check'].split("|") authdb = rule_yaml['check'].split()[3] if len(check) > 2: matches = re.findall(r'(?<=\>)(.*)(?=\<)',check[1]) key = str(matches).replace("[","").replace("]","").replace("'","") length = len(check[2].split()) last_string = check[2].split()[length-1].replace('"',"").replace("<","").replace(">","").replace("/","") oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' {} boolean(//key[text()="{}"]/following-sibling::{}) '''.format(rule_yaml['id'] + "_" + odv_label,x,authdb,key,last_string) oval_state = oval_state + ''' true '''.format(rule_yaml['id'] + "_" + odv_label,x) else: key = (check[1].split()[2].replace("'","")) oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' {} //*[contains(text(), "{}")]/text() '''.format(rule_yaml['id'] + "_" + odv_label,x,authdb,key) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,key) else: if "authorizationdb" in rule_yaml['check']: regex = r"=\(.*.\)" matchy_match = [] matches = re.finditer(regex, rule_yaml['check'], re.MULTILINE) for matchNum, match in enumerate(matches, start=1): matchy_match = match.group().replace('=(',"").replace(")","").replace('"','').split() oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion']) for match in matchy_match: oval_definition = oval_definition + ''' '''.format(rule_yaml['id'] + "+" + match, x) oval_test = oval_test + ''' '''.format(match,x,x,x) key="shared" value="" if "false" in rule_yaml["check"]: value="false" else: value="true" oval_object = oval_object + ''' {} boolean(//key[text()="{}"]/following-sibling::{}) '''.format(match,x,match,key,value) oval_state = oval_state + ''' true '''.format(match,x) x += 1 oval_definition = oval_definition + "" x += 1 continue if "/bin/rm" in rule_yaml['fix'] and "/bin/ls" in rule_yaml['check']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(x,rule_yaml['id'] + "_" + odv_label,x) path = rule_yaml['fix'].split("----")[1].split(" ")[-1] oval_object = oval_object + ''' {} '''.format(x,rule_yaml['id'] + "_" + odv_label,path.rstrip()) x += 1 continue if "ls" in command[2] or "stat" in command[3].split()[0]: if '/Library/Security/PolicyBanner.rtf' in rule_yaml['check']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label,x+2999) oval_test = oval_test + ''' '''.format(x,rule_yaml['id'] + "_" + odv_label,x,x+2999,rule_yaml['id'] + "_" + odv_label,x+2999) oval_object = oval_object + ''' /Library/Security/PolicyBanner.rtf /Library/Security/PolicyBanner.rtfd '''.format(x,rule_yaml['id'] + "_" + odv_label,x+2999,rule_yaml['id']) x = x + 1 continue s = rule_yaml['check'] config_file = str() oval_variable_need = bool() if "grep" in s.split()[2]: oval_variable_need = True grep_search = re.search('\((.*?)\)', s).group(1) substring = grep_search.split("|")[0] regex = re.search('\'(.*?)\'', substring).group(1) try: regex = re.search('/(.*?)/', regex).group(1) except: regex = regex config_file = substring = grep_search.split("|")[0].split()[-1] oval_object = oval_object + ''' {} {}:\s*(.*)$ 1 '''.format(rule_yaml['id'] + "_" + odv_label, x+999, config_file, regex) oval_variable = oval_variable + ''' '''.format(x,rule_yaml['id'] + "_" + odv_label,x+999) else: oval_variable_need = False config_file = s.split()[2] s = rule_yaml['fix'] fix_command = re.search('-\n(.*?)\n-', s).group(1).split('$')[0] oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(x,rule_yaml['id'] + "_" + odv_label,x,x) if "-" in fix_command and "R" in fix_command or rule_yaml['fix'].split("\n")[2][-1] == "*": behavior = '' if "audit" in rule_yaml['id']: filename = 'current' else: behavior = "" filename = '' if oval_variable_need == True: oval_object = oval_object + ''' {} {} '''.format(rule_yaml['id'] + "_" + odv_label,x,behavior,x,filename) else: oval_object = oval_object + ''' {} {} '''.format(rule_yaml['id'] + "_" + odv_label,x,behavior,config_file) state_test = "" if "-" in fix_command and "N" in fix_command and "chmod" in fix_command: state_test = ''' false ''' elif "chgrp" in fix_command: state_test = ''' {} '''.format(rule_yaml['result']['integer']) elif "chown" in fix_command: state_test = ''' {} '''.format(rule_yaml['result']['integer']) elif "chmod" in fix_command: perms = fix_command.split()[1] if perms[0] == "0": state_test = ''' false false false''' if perms[0] == "1": state_test = ''' false false true''' elif perms[0] == "2": state_test = ''' false true false''' elif perms[0] == "3": state_test = ''' false true true''' elif perms[0] == "4": state_test = ''' true false false''' elif perms[0] == "5": state_test = ''' true false true''' elif perms[0] == "6": state_test = ''' true true false''' elif perms[0] == "7": state_test = ''' true true true''' if perms[1] == "0": state_test = state_test + ''' false false false''' elif perms[1] == "1": state_test = state_test + ''' false false true''' elif perms[1] == "2": state_test = state_test + ''' false true false''' elif perms[1] == "3": state_test = state_test + ''' false true true''' elif perms[1] == "4": state_test = state_test + ''' true false false''' elif perms[1] == "5": state_test = state_test + ''' true false true''' elif perms[1] == "6": state_test = state_test + ''' true true false''' elif perms[1] == "7": state_test = state_test + ''' true true true''' if perms[2] == "0": state_test = state_test + ''' false false false''' if perms[2] == "1": state_test = state_test + ''' false false true''' elif perms[2] == "1": state_test = state_test + ''' false false true''' elif perms[2] == "2": state_test = state_test + ''' false true false''' elif perms[2] == "3": state_test = state_test + ''' false true true''' elif perms[2] == "4": state_test = state_test + ''' true false false''' elif perms[2] == "5": state_test = state_test + ''' true false true''' elif perms[2] == "6": state_test = state_test + ''' true true false''' elif perms[2] == "7": state_test = state_test + ''' true true true''' oval_state = oval_state + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x) + state_test + ''' ''' x += 1 continue if "dscl" in command[3]: if "UserShell" in rule_yaml['check']: shell = rule_yaml['check'].split()[9].replace('"','') oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) oval_object = oval_object + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,command[5].split()[0]) oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,shell) x += 1 continue if "awk" in command[3]: awk_file = "" awk_search = "" field_sep = "" if "grep -qE" in rule_yaml['fix']: awk_file = rule_yaml['fix'].split(" ")[3].strip(" ") awk_search = rule_yaml['fix'].split(" ")[2].strip("\"") elif "grep" in rule_yaml['check']: awk_file = rule_yaml['check'].split("|")[0].split(" ")[-2] awk_search = rule_yaml['check'].split("|")[-1].split(" ")[-2].strip("\'") else: awk_file = rule_yaml['check'].split("'")[2].strip(" ") awk_search = rule_yaml['check'].split("'")[1].split("/")[1] try: field_sep = rule_yaml['check'].split("-F")[1].split(" ")[0].replace('\"',"") except: field_sep = " " try: awk_result = rule_yaml['result']['string'] except: awk_result = str(rule_yaml['result']['integer']) if awk_search[0] != "^": awk_search = "^" + awk_search + field_sep + awk_result else: awk_search = awk_search + field_sep + awk_result oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label, x) oval_object = oval_object + ''' {} {} 1 '''.format(x,rule_yaml['id'] + "_" + odv_label,awk_file.rstrip(), awk_search) x += 1 continue if "grep" in command[3] and not "pgrep" in command[3]: if "bannerText" in rule_yaml['check'] or "fips_" in rule_yaml['check']: text_to_find = rule_yaml['check'].split("=")[1].split('"')[1] matches = text_to_find.replace(".","\.").replace(")","\)").replace("(","\(").replace("*","\*") oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label, x) file_path = rule_yaml["check"].split(" ")[-1].rstrip() oval_object = oval_object + ''' {} {} 1 '''.format(x,rule_yaml['id'] + "_" + odv_label,file_path,matches) x += 1 continue else: s = rule_yaml['check'] try: grep_search = re.search('"(.*?)"', s).group(1) except: grep_search = re.search('\'(.*?)\'', s).group(1) grep_file = rule_yaml['check'].split(grep_search,1)[1].split(" ")[1] oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label, x) oval_object = oval_object + ''' {} {} 1 '''.format(x,rule_yaml['id'] + "_" + odv_label,grep_file.rstrip(),grep_search) x += 1 continue if "launchctl" in command[2] or "launchctl" in rule_yaml['fix']: if "disable" in command[2] and "=> true" in rule_yaml['check'] or "unload -w" in rule_yaml['fix'] or "disable" in command[2] and "=> disabled" in rule_yaml['check']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label,x+999) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x,x+999,rule_yaml['id'] + "_" + odv_label,x+999) domain = str() if "launchctl" not in rule_yaml['check']: domain = rule_yaml['fix'].split()[4].split('/')[4].replace(".plist","") else: s = command[5].split()[2] domain = re.search('"(.*?)"', s).group(1) oval_object = oval_object + ''' /var/db/com.apple.xpc.launchd/disabled.plist name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(rule_yaml['id'] + "_" + odv_label,x,domain,x+999,rule_yaml['id'] + "_" + odv_label,domain) status = "" if "enable" in rule_yaml["fix"]: status = "false" else: status = "true" oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,status) elif "launchctl unload" in rule_yaml['fix']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x,rule_yaml['id'] + "_" + odv_label,x+999) oval_test = oval_test + ''' '''.format(x,rule_yaml['id'] + "_" + odv_label,x) domain = str() if "launchctl" not in rule_yaml['check']: domain = rule_yaml['fix'].split()[4].split('/')[4].replace(".plist","") else: s = command[5].split()[2] domain = re.search('"(.*?)"', s).group(1) oval_object = oval_object + ''' '''.format(x, rule_yaml['id'] + "_" + odv_label,domain) elif "defaults write" in rule_yaml['fix']: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'],rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x,x) plist = rule_yaml['fix'].split(" ")[2].replace(".plist","") # plist = rule_yaml['check'].split("read")[1].split()[0].replace(".plist","") if "ByHost" in rule_yaml['fix'] or "currentHost" in rule_yaml['fix']: oval_object = oval_object + ''' SPHardwareDataType //*[contains(text(), "platform_UUID")]/following-sibling::string[position()=1]/text() '''.format("hardware UUID",x+999) if "$CURRENT_USER" in rule_yaml['check']: key = rule_yaml['fix'].split("defaults")[1].split(" ")[3] oval_object = oval_object + ''' .* oval:mscp:ste:{} '''.format(x+1999,x+1999,rule_yaml['id'] + "_" + odv_label,x,x) if rule_yaml['fix'].split("defaults")[1].split(" ")[4] == "-bool": rule_yaml['result']['boolean'] oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) else: oval_object = oval_object + '''//*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' ^[^_\s].* 0 0 /usr/bin/false '''.format(x+1999) oval_variable = oval_variable + ''' /Library/Preferences/ByHost/{}. .plist '''.format(x,x+1999,plist,x+999) else: key = rule_yaml['fix'].split("defaults")[1].split(" ")[3] oval_object = oval_object + ''' '''.format(rule_yaml['id'] + "_" + odv_label,x,x) if rule_yaml['fix'].split("defaults")[1].split(" ")[4] == "-bool": oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) else: oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_variable = oval_variable + ''' {}. .plist '''.format(x,plist,x+999) elif "$CURRENT_USER" in rule_yaml['check']: check_length = len(rule_yaml['check'].split()) key = rule_yaml['fix'].split("defaults")[1].split(" ")[3] oval_object = oval_object + ''' .* oval:mscp:ste:{} '''.format(x+1999,x+1999,rule_yaml['id'] + "_" + odv_label,x,x) if rule_yaml['fix'].split("defaults")[1].split(" ")[4] == "-bool": oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(key) else: oval_object = oval_object + '''//*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(key) oval_state = oval_state + ''' ^[^_\s].* 0 0 /usr/bin/false '''.format(x+1999) oval_variable = oval_variable + ''' /Library/Preferences/{}. plist '''.format(x,x+1999,plist,x+999) else: if plist[-6:] != ".plist": plist = plist + ".plist" plist_key = rule_yaml['fix'].split("defaults")[1].split(" ")[3] oval_object = oval_object + ''' {}'''.format(rule_yaml['id'] + "_" + odv_label,x,plist) try: rule_yaml['result']['boolean'] oval_object = oval_object + ''' name(//*[contains(text(), "{}")]/following-sibling::*[1]) '''.format(plist_key) except: oval_object = oval_object + ''' //*[contains(text(), "{}")]/following-sibling::*[1]/text() '''.format(plist_key) datatype = "" plist_key = rule_yaml['fix'].split("defaults")[1].split(" ")[3] oval_datatype = rule_yaml['fix'].split("defaults")[1].split(" ")[4].replace("-","") if oval_datatype == "integer": oval_datatype = "int" if oval_datatype == "bool": oval_datatype = "boolean" value = rule_yaml['fix'].split("defaults")[1].split(" ")[5].replace(";","") oval_state = oval_state + ''' {} '''.format(rule_yaml['id'] + "_" + odv_label,x,oval_datatype,value) oval_definition = re.sub('(?=\n\[NOTE\])(?s)(.*)\=\n<', '<', oval_definition) x = x+1 continue else: oval_definition = oval_definition + ''' {} {} '''.format(x,rule_yaml['title'],cce,rule_yaml['id'] + "_" + odv_label,rule_yaml['discussion'].rstrip(),rule_yaml['id'] + "_" + odv_label,x) oval_test = oval_test + ''' '''.format(x,rule_yaml['id'] + "_" + odv_label,x) domain = command[5].split()[2] domain = domain.replace('"','').replace("'",'') oval_object = oval_object + ''' '''.format(x,rule_yaml['id'] + "_" + odv_label,domain) x += 1 continue for k in generated_baselines.keys(): xccdf_profiles = xccdf_profiles + ''' {0} This profile selects all rules tagged as {0}.'''.format(k, k.replace(" ","_")) for v in generated_baselines[k]: xccdf_profiles = xccdf_profiles + '''