From 55f086e8affaf1a407f1e89f927db36ee26ff2a9 Mon Sep 17 00:00:00 2001 From: Ryan Prather Date: Thu, 17 Jan 2019 12:20:18 -0500 Subject: [PATCH] bug(software): Bug fix with software detection Ubuntu.png - Add new Ubuntu checklist icon Database_Baseline.zip - Update software detection tables checklist.inc - Fix software icon detection for IE and SLES, and added detection for Ubuntu software.inc - Fix bug adding extra spaces to software strings parse_stig.php - Formatting and add save for when icon is updated parse_stig_viewer.php - Add scan note when CKL file is missing or has empty tag Fix #87 --- Database_Baseline.zip | Bin 1192414 -> 1192500 bytes classes/checklist.inc | 9 +- classes/software.inc | 4 +- exec/parse_stig.php | 949 +++++++++++++++++---------------- exec/parse_stig_viewer.php | 3 +- img/checklist_icons/Ubuntu.png | Bin 0 -> 17166 bytes 6 files changed, 498 insertions(+), 467 deletions(-) create mode 100644 img/checklist_icons/Ubuntu.png diff --git a/Database_Baseline.zip b/Database_Baseline.zip index 575cd5f5631d8bd83d7148938f73099052a3e404..e7b4036b063fdc82c387cb81e2797e97172ccf97 100644 GIT binary patch delta 5283 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 G0002*D9n%m diff --git a/classes/checklist.inc b/classes/checklist.inc index 966da27..002157d 100644 --- a/classes/checklist.inc +++ b/classes/checklist.inc @@ -5,7 +5,7 @@ * Purpose: Represents a checklist that links a PDI and software package * Created: Sep 12, 2013 * - * Portions Copyright 2017: Cyber Perspectives, All rights reserved + * Portions Copyright 2017-2019: CyberPerspectives, LLC, All rights reserved * Released under the Apache v2.0 License * * Portions Copyright (c) 2012-2015, Salient Federal Solutions @@ -406,7 +406,7 @@ class checklist case (preg_match("/Dot Net|DotNet/i", $this->name) ? true : false): $this->icon = 'Microsoft .NET.png'; break; - case (preg_match("/Internet Explorer/i", $this->name) ? true : false): + case (preg_match("/Internet Explorer|Microsoft IE/i", $this->name) ? true : false): $this->icon = 'Internet Explorer.png'; break; case (preg_match("/Windows Phone/i", $this->name) ? true : false): @@ -452,7 +452,7 @@ class checklist case (preg_match("/Red ?Hat/i", $this->name) ? true : false): $this->icon = 'RedHat Linux.jpg'; break; - case (preg_match("/SUSE Linux/i", $this->name) ? true : false): + case (preg_match("/SUSE Linux|SLES/i", $this->name) ? true : false): $this->icon = 'SUSE Linux.png'; break; case (preg_match("/Solaris/i", $this->name) ? true : false): @@ -461,6 +461,9 @@ class checklist case (preg_match("/Storage Area/i", $this->name) ? true : false): $this->icon = 'Storage Area Network.gif'; break; + case (preg_match("/Ubuntu/i", $this->name) ? true : false): + $this->icon = 'Ubuntu.png'; + break; case (preg_match("/z\/OS/i", $this->name) ? true : false): $this->icon = 'ZOS.jpg'; break; diff --git a/classes/software.inc b/classes/software.inc index 6cc537d..c246092 100644 --- a/classes/software.inc +++ b/classes/software.inc @@ -595,7 +595,7 @@ class software { if ($regex2['name_match']) { foreach (explode(",", $regex2['name_match']) as $idx) { - if (isset($match[$idx])) { + if (isset($match[$idx]) && $match[$idx]) { $sw['name'] .= " " . $match[$idx]; } } @@ -603,7 +603,7 @@ class software { if ($regex2['ver_match']) { foreach (explode(",", $regex2['ver_match']) as $idx) { - if (isset($match[$idx])) { + if (isset($match[$idx]) && $match[$idx]) { $sw['ver'] .= $match[$idx] . " "; } } diff --git a/exec/parse_stig.php b/exec/parse_stig.php index ca5bb96..0e1c6e2 100644 --- a/exec/parse_stig.php +++ b/exec/parse_stig.php @@ -6,7 +6,7 @@ * Purpose: To parse a STIG file * Created: Jul 9, 2014 * - * Portions Copyright 2016-2017: Cyber Perspectives, LLC, All rights reserved + * Portions Copyright 2016-2019: CyberPerspectives, LLC, All rights reserved * Released under the Apache v2.0 License * * Portions Copyright (c) 2012-2015, Salient Federal Solutions @@ -31,10 +31,15 @@ * - Dec 27, 2017 - Added up date for load date * - May 10, 2018 - Starting to migrate logging and fixed install status bar issues (#403) */ -$cmd = getopt("f:", ['debug::', 'ia_reset::', 'draft::', 'help::']); +$cmd = getopt("f:", [ + 'debug::', + 'ia_reset::', + 'draft::', + 'help::' +]); -if (!isset($cmd['f']) || isset($cmd['help'])) { - die(usage()); +if (! isset($cmd['f']) || isset($cmd['help'])) { + die(usage()); } set_time_limit(0); @@ -50,21 +55,20 @@ use Monolog\Formatter\LineFormatter; $stream = new StreamHandler("php://output", Logger::INFO); $stream->setFormatter(new LineFormatter("%datetime% %level_name% %message%", "H:i:s.u")); /* -$log = new Logger("parse_stig"); -$log->pushHandler(new StreamHandler(LOG_PATH . "/" . basename($cmd['f']) . ".log", LOG_LEVEL)); -$log->pushHandler($stream); -*/ + * $log = new Logger("parse_stig"); + * $log->pushHandler(new StreamHandler(LOG_PATH . "/" . basename($cmd['f']) . ".log", LOG_LEVEL)); + * $log->pushHandler($stream); + */ chdir(DOC_ROOT . "/exec"); // Capture start time for performance metrics $start = new DateTime(); // Check to make sure file argument exists and is an XCCDF file -if (!file_exists($cmd['f'])) { - Sagacity_Error::err_handler("XML file not found {$cmd['f']}", E_ERROR); -} -elseif (strpos(strtolower($cmd['f']), "xccdf") === false) { - Sagacity_Error::err_handler("Only compatible with XCCDF file formats", E_ERROR); +if (! file_exists($cmd['f'])) { + Sagacity_Error::err_handler("XML file not found {$cmd['f']}", E_ERROR); +} elseif (strpos(strtolower($cmd['f']), "xccdf") === false) { + Sagacity_Error::err_handler("Only compatible with XCCDF file formats", E_ERROR); } // Verify our STIG reference directory exists @@ -73,7 +77,11 @@ check_path(DOC_ROOT . "/reference/stigs"); // open db connection $db = new db(); -$content = str_replace(["’", "–", "“", "â€"], ["'", "-", '"', '"'], file_get_contents($cmd['f'])); +$content = str_replace([ + "’", "–", "“", "â€" +], [ + "'", "-", '"', '"' +], file_get_contents($cmd['f'])); file_put_contents($cmd['f'], $content); // open xml file @@ -85,49 +93,65 @@ $log = new Sagacity_Error($base_name); // Create and update parse job details $db->help->select_count("sagacity.catalog_scripts", [ - [ - 'field' => 'file_name', - 'op' => '=', - 'value' => $base_name - ] + [ + 'field' => 'file_name', + 'op' => '=', + 'value' => $base_name + ] ]); $exists = $db->help->execute(); -if (!$exists) { - $db->add_Catalog_Script($base_name); +if (! $exists) { + $db->add_Catalog_Script($base_name); } -$db->update_Catalog_Script($base_name, ['name' => 'pid', 'value' => getmypid()]); -$db->help->update("sagacity.settings", ['meta_value' => new DateTime()], [ - [ - 'field' => 'meta_key', - 'op' => '=', - 'value' => 'stig-load-date' - ] +$db->update_Catalog_Script($base_name, [ + 'name' => 'pid', + 'value' => getmypid() +]); +$db->help->update("sagacity.settings", [ + 'meta_value' => new DateTime() +], [ + [ + 'field' => 'meta_key', + 'op' => '=', + 'value' => 'stig-load-date' + ] ]); $db->help->execute(); $tmp = $db->get_Stig(); $stigs = []; foreach ($tmp as $s) { - $stigs["{$s->get_ID()}"] = $s; + $stigs["{$s->get_ID()}"] = $s; } print "Currently " . count($stigs) . " in the DB" . PHP_EOL; // Load XML into DOMDocument $xml = new DOMDocument(); -if (!$xml->load($cmd['f'])) { - $log->script_log("Error opening file", E_ERROR); +if (! $xml->load($cmd['f'])) { + $log->script_log("Error opening file", E_ERROR); } // Get regexes used to assess the STIG for known applicable software products $regex_arr = $db->get_Regex_Array("checklist"); -if (is_array($regex_arr) && !count($regex_arr)) { - die("There are no regular expressions to detect checklist software"); +if (is_array($regex_arr) && ! count($regex_arr)) { + die("There are no regular expressions to detect checklist software"); } -$csv_file = substr($cmd['f'], 0, -3) . "csv"; +$csv_file = substr($cmd['f'], 0, - 3) . "csv"; $csv = fopen($csv_file, "w"); -fputcsv($csv, ["STIG_ID", "VMS_ID", "CAT", "IA_Controls", "Short_Title", "Status", "Notes", "Check_Contents", "SV_Rule_ID", "Oval_ID"]); +fputcsv($csv, [ + "STIG_ID", + "VMS_ID", + "CAT", + "IA_Controls", + "Short_Title", + "Status", + "Notes", + "Check_Contents", + "SV_Rule_ID", + "Oval_ID" +]); // get checklist data $checklist = []; @@ -135,16 +159,19 @@ $checklist['id'] = str_replace("-", '.', getValue($xml, '@id')); $checklist['status'] = getValue($xml, "/x:Benchmark/x:status"); // Skip draft STIGs if debug flag is not set. @Ryan: Shouldn't this be checking the draft flag instead of debug? -if (!isset($cmd['draft'])) { - if (strtolower($checklist['status']) == 'draft') { - $db->update_Catalog_Script($base_name, ["name" => "status", "value" => "SKIPPED"]); - fclose($csv); - unset($xml); - unlink($cmd['f']); - $log->script_log("Skipping since this is a draft STIG" . PHP_EOL, E_NOTICE); +if (! isset($cmd['draft'])) { + if (strtolower($checklist['status']) == 'draft') { + $db->update_Catalog_Script($base_name, [ + "name" => "status", + "value" => "SKIPPED" + ]); + fclose($csv); + unset($xml); + unlink($cmd['f']); + $log->script_log("Skipping since this is a draft STIG" . PHP_EOL, E_NOTICE); - die(); - } + die(); + } } $checklist['status_date'] = getValue($xml, "/x:Benchmark/x:status", null, true)->item(0)->getAttribute('date'); $checklist['status_date'] = new DateTime($checklist['status_date']); @@ -155,80 +182,72 @@ $checklist['plain_text'] = getValue($xml, "/x:Benchmark/x:plain-text"); $checklist['software'] = software::identify_Software($regex_arr, $checklist['id']); if (isset($cmd['debug'])) { - $log->script_log(print_r($checklist['software'], true), E_DEBUG); + $log->script_log(print_r($checklist['software'], true), E_DEBUG); } // If no matching software is found, default to "generic" -if (!count($checklist['software'])) { - $log->script_log("Could not identify software, setting as Generic/Generic", E_NOTICE); - $checklist['software'][] = [ - 'man' => 'Generic', - 'name' => 'Generic', - 'ver' => '-', - 'sp' => null, - 'type' => false - ]; +if (! count($checklist['software'])) { + $log->script_log("Could not identify software, setting as Generic/Generic", E_NOTICE); + $checklist['software'][] = [ + 'man' => 'Generic', + 'name' => 'Generic', + 'ver' => '-', + 'sp' => null, + 'type' => false + ]; } // Convert identified software to a software object. $sw_arr = software::toSoftwareFromArray($checklist['software']); if (isset($cmd['debug'])) { - $log->script_log(print_r($sw_arr, true), E_DEBUG); + $log->script_log(print_r($sw_arr, true), E_DEBUG); } foreach ($sw_arr as $key => $sw) { - do { - $cpe = "cpe:/" . ($sw->is_OS() ? "o" : "a") . ":{$sw->get_Man()}:{$sw->get_Name()}" . - ($sw->get_Version() != '-' ? ":{$sw->get_Version()}" : ""); - $cpe = str_replace( - [" ", "(", ")"], ["_", "%28", "%29"], strtolower($cpe) - ); + do { + $cpe = "cpe:/" . ($sw->is_OS() ? "o" : "a") . ":{$sw->get_Man()}:{$sw->get_Name()}" . ($sw->get_Version() != '-' ? ":{$sw->get_Version()}" : ""); + $cpe = str_replace([" ", "(", ")"], ["_", "%28","%29"], strtolower($cpe)); - $db_sw = $db->get_Software($cpe); + $db_sw = $db->get_Software($cpe); - if (!count($db_sw) && !count($checklist['software'])) { - $sw->reduce_CPE(); - } - elseif (is_array($db_sw) && count($db_sw) == 1 && $db_sw[0]->get_Version() == '-' && !preg_match("/generic/", $sw->get_CPE())) { - $checklist['software'] = array_merge($checklist['software'], $db_sw); - $sw->reduce_CPE(); - $db_sw = []; - } - else { - break; - } + if (! count($db_sw) && ! count($checklist['software'])) { + $sw->reduce_CPE(); + } elseif (is_array($db_sw) && count($db_sw) == 1 && $db_sw[0]->get_Version() == '-' && ! preg_match("/generic/", $sw->get_CPE())) { + $checklist['software'] = array_merge($checklist['software'], $db_sw); + $sw->reduce_CPE(); + $db_sw = []; + } else { + break; + } - if (isset($cmd['debug'])) { - $log->script_log("$cpe found " . count($db_sw), E_DEBUG); - } - } - while (!count($db_sw)); + if (isset($cmd['debug'])) { + $log->script_log("$cpe found " . count($db_sw), E_DEBUG); + } + } while (! count($db_sw)); - $checklist['software'] = array_merge($checklist['software'], $db_sw); + $checklist['software'] = array_merge($checklist['software'], $db_sw); } foreach ($checklist['software'] as $key => $sw) { - if (!is_a($sw, 'software')) { - unset($checklist['software'][$key]); - } + if (! is_a($sw, 'software')) { + unset($checklist['software'][$key]); + } } $match = []; if (preg_match('/Release: (\d+\.\d+|\d+)/', $checklist['plain_text'], $match)) { - $checklist['rel'] = $match[1]; -} -else { - $checklist['rel'] = ''; + $checklist['rel'] = $match[1]; +} else { + $checklist['rel'] = ''; } // Get the date of the benchmark in the 'plain-text' element or set to 'status-date' if match fails if (preg_match('/Benchmark Date: (.*)$/', $checklist['plain_text'], $match)) { - $checklist['benchmark_date'] = new DateTime($match[1]); -} -else { - $checklist['benchmark_date'] = $checklist['status_date']; + $checklist['benchmark_date'] = new DateTime($match[1]); +} else { + $checklist['benchmark_date'] = $checklist['status_date']; } // Get the STIG title and convert common acronyms (STIG, IAVM, and SRG) @@ -243,28 +262,24 @@ $checklist['desc'] = getValue($xml, "/x:Benchmark/x:description"); $checklist['type'] = 'benchmark'; if (preg_match('/IAVM/i', $base_name)) { - $checklist['type'] = 'iavm'; -} -elseif (preg_match('/policy|srg/i', $base_name)) { - $checklist['type'] = 'policy'; -} -elseif (preg_match('/manual/i', $base_name)) { - $checklist['type'] = 'manual'; + $checklist['type'] = 'iavm'; +} elseif (preg_match('/policy|srg/i', $base_name)) { + $checklist['type'] = 'policy'; +} elseif (preg_match('/manual/i', $base_name)) { + $checklist['type'] = 'manual'; } // Capture version release in filename as sometimes it doesn't match the plain_text element if (preg_match('/V(\d+)R/', $base_name, $match)) { - $checklist['file_ver'] = $match[1]; -} -else { - $checklist['file_ver'] = 0; + $checklist['file_ver'] = $match[1]; +} else { + $checklist['file_ver'] = 0; } if (preg_match('/V\d+R(\d+|\d+\.\d+)/', $base_name, $match)) { - $checklist['file_rel'] = $match[1]; -} -else { - $checklist['file_rel'] = 0; + $checklist['file_rel'] = $match[1]; +} else { + $checklist['file_rel'] = 0; } // Assign ver and rel to whichever value is greater (filename or xml) @@ -272,403 +287,407 @@ $checklist['ver'] = $checklist['file_ver'] > $checklist['ver'] ? $checklist['fil $checklist['rel'] = $checklist['file_rel'] > $checklist['rel'] ? $checklist['file_rel'] : $checklist['rel']; if (isset($cmd['debug'])) { - $log->script_log("Checklist:" . PHP_EOL . print_r($checklist, true), E_DEBUG); + $log->script_log("Checklist:" . PHP_EOL . print_r($checklist, true), E_DEBUG); } // Query the db to see if the checklist is already in there $db->help->select("sagacity.checklist", ['id'], [ - [ - 'field' => 'checklist_id', - 'op' => '=', - 'value' => $checklist['id'] - ], - [ - 'field' => 'release', - 'op' => '=', - 'value' => $checklist['rel'], - 'sql_op' => 'AND' - ], - [ - 'field' => 'ver', - 'op' => '=', - 'value' => $checklist['ver'], - 'sql_op' => 'AND' - ], - [ - 'field' => 'type', - 'op' => '=', - 'value' => $checklist['type'], - 'sql_op' => 'AND' - ] + [ + 'field' => 'checklist_id', + 'op' => '=', + 'value' => $checklist['id'] + ], + [ + 'field' => 'release', + 'op' => '=', + 'value' => $checklist['rel'], + 'sql_op' => 'AND' + ], + [ + 'field' => 'ver', + 'op' => '=', + 'value' => $checklist['ver'], + 'sql_op' => 'AND' + ], + [ + 'field' => 'type', + 'op' => '=', + 'value' => $checklist['type'], + 'sql_op' => 'AND' + ] ]); $chk = $db->help->execute(); // If checklist is found, retrieve it if ($chk) { - $chk = $db->get_Checklist($chk['id']); + $chk = $db->get_Checklist($chk['id']); - if (count($chk) && is_a($chk[0], 'checklist')) { - $chk = $chk[0]; - } - // Update software products associated with this checklist - $sw_arr = []; - foreach ($checklist['software'] as $sw) { - $sw_arr[] = [$chk->get_ID(), $sw->get_ID()]; - } - - if (is_array($sw_arr) && count($sw_arr)) { - $db->help->extended_insert("sagacity.checklist_software_lookup", ['chk_id', 'sw_id'], $sw_arr, true); - if (!$db->help->execute()) { - $db->debug(E_WARNING); + if (count($chk) && is_a($chk[0], 'checklist')) { + $chk = $chk[0]; } - } - if (isset($cmd['debug'])) { - $log->script_log(print_r($chk, true), E_DEBUG); - } -} -else { - // If checklist is not found, add checklist to DB - $chk = new checklist( - null, $checklist['id'], $checklist['title'], $checklist['desc'], $checklist['status_date'], $base_name, $checklist['ver'], $checklist['rel'], ($checklist['type'] == 'iavm' ? 'IAVM' : ucfirst($checklist['type'])), null - ); - $chk->add_SW($checklist['software']); + /** @var checklist $chk */ + $chk->find_Icon(); - if (!($chk->id = $db->save_Checklist($chk))) { - $log->script_log("Failed to save new checklist ({$chk->get_Name()})", E_ERROR); - } + // Update software products associated with this checklist + foreach ($checklist['software'] as $sw) { + $chk->add_SW($sw); + } + + $db->save_Checklist($chk); + + if (isset($cmd['debug'])) { + $log->script_log(print_r($chk, true), E_DEBUG); + } +} else { + // If checklist is not found, add checklist to DB + $chk = new checklist(null, $checklist['id'], $checklist['title'], $checklist['desc'], $checklist['status_date'], $base_name, $checklist['ver'], $checklist['rel'], ($checklist['type'] == 'iavm' ? 'IAVM' : ucfirst($checklist['type'])), null); + $chk->add_SW($checklist['software']); + + if (! ($chk->id = $db->save_Checklist($chk))) { + $log->script_log("Failed to save new checklist ({$chk->get_Name()})", E_ERROR); + } } -if (!$chk->id) { - $log->script_log("Could not find or create checklist", E_ERROR); +if (! $chk->id) { + $log->script_log("Could not find or create checklist", E_ERROR); } if (isset($cmd['debug'])) { - $log->script_log("Found checklist:" . PHP_EOL . print_r($chk, true), E_DEBUG); + $log->script_log("Found checklist:" . PHP_EOL . print_r($chk, true), E_DEBUG); } // Get the collection of STIG rules i.e., elements $groups = getValue($xml, '/x:Benchmark/x:Group', null, true); $log->script_log("$groups->length STIGs to run", E_DEBUG); -$db->update_Catalog_Script($base_name, ['name' => 'stig_count', 'value' => $groups->length]); +$db->update_Catalog_Script($base_name, [ + 'name' => 'stig_count', + 'value' => $groups->length +]); print "File: $base_name" . PHP_EOL; print "Total: $groups->length" . PHP_EOL; // Iterate over each group element processing the attributes/children foreach ($groups as $group) { - // Initialize local variables to hold parsed data - $new = false; - $references = []; - $ias = []; - $ia_controls = ''; - $perc_comp++; - $vms_id = $group->getAttribute('id'); + // Initialize local variables to hold parsed data + $new = false; + $references = []; + $ias = []; + $ia_controls = ''; + $perc_comp ++; + $vms_id = $group->getAttribute('id'); - // the ".//" indicates that we are starting at the current node ($group) and looking in all child nodes for the "title" and "description" nodes - $group_title = getValue($xml, './/x:title', $group, true)->item(0)->nodeValue; - $group_desc = getValue($xml, './/x:description', $group); + // the ".//" indicates that we are starting at the current node ($group) and looking in all child nodes for the "title" and "description" nodes + $group_title = getValue($xml, './/x:title', $group, true)->item(0)->nodeValue; + $group_desc = getValue($xml, './/x:description', $group); - // Get the Rule DOMElement - $group_rule = getValue($xml, 'x:Rule', $group, true)->item(0); + // Get the Rule DOMElement + $group_rule = getValue($xml, 'x:Rule', $group, true)->item(0); - $sv_rule = $group_rule->getAttribute('id'); + $sv_rule = $group_rule->getAttribute('id'); - // Get the severity category and convert to an integer from one to three - $cat = 0; - if ($group_rule->getAttribute('severity') == 'high') { - $cat = 1; - } - elseif ($group_rule->getAttribute('severity') == 'medium') { - $cat = 2; - } - elseif ($group_rule->getAttribute('severity') == 'low') { - $cat = 3; - } - - $rule_check_content = ''; - $rule_ident = getValue($xml, ".//x:ident", $group_rule, true); - $rule_stig_id = getValue($xml, './/x:version', $group_rule); - $rule_title = textCleanup(getValue($xml, './/x:title', $group_rule)); - $rule_desc = textCleanup(getValue($xml, './/x:description', $group_rule)); - $check_content_nodes = getValue($xml, './/x:check-content', $group_rule, true); - $rule_check_ref = getValue($xml, './/x:check-content-ref', $group_rule, true); - $fix_text = getValue($xml, './/x:fixtext', $group_rule); - if ($rule_check_ref->length) { - $oval_id = $rule_check_ref->item(0)->getAttribute('name'); - } - else { - $oval_id = ''; - } - $match = []; - $discussion = ""; - if (preg_match("/(.*)<\/VulnDiscussion>/", html_entity_decode($rule_desc), $match)) { - $discussion = $match[1]; - } - - // Remove unnecessary whitespace from and concatenate check content - if ($check_content_nodes->length > 0) { - for ($x = 0; $x < $check_content_nodes->length; $x++) { - $rule_check_content .= ($x + 1) . ") " . textCleanup($check_content_nodes->item($x)->textContent) . PHP_EOL; + // Get the severity category and convert to an integer from one to three + $cat = 0; + if ($group_rule->getAttribute('severity') == 'high') { + $cat = 1; + } elseif ($group_rule->getAttribute('severity') == 'medium') { + $cat = 2; + } elseif ($group_rule->getAttribute('severity') == 'low') { + $cat = 3; } - $rule_check_content = trim($rule_check_content, PHP_EOL); - } - - //$log->script_log("STIG ID: $rule_stig_id", E_DEBUG); - // Assign default category if not provided and add comment indicating such to rule description - if (!$cat) { - $cat = 2; - $discussion .= " :CAT SET BY SCRIPT"; - } - - // Extract and append potential impacts tag content from/to rule description - if (preg_match('/(.*)<\/PotentialImpacts>/', $rule_desc, $match)) { - $discussion .= "\n{$match[1]}"; - } - - if (!$rule_stig_id) { - if ($vms_id == 'V0001073' || $vms_id == 'V-1073') { - $rule_stig_id = '2.005'; + $rule_check_content = ''; + $rule_ident = getValue($xml, ".//x:ident", $group_rule, true); + $rule_stig_id = getValue($xml, './/x:version', $group_rule); + $rule_title = textCleanup(getValue($xml, './/x:title', $group_rule)); + $rule_desc = textCleanup(getValue($xml, './/x:description', $group_rule)); + $check_content_nodes = getValue($xml, './/x:check-content', $group_rule, true); + $rule_check_ref = getValue($xml, './/x:check-content-ref', $group_rule, true); + $fix_text = getValue($xml, './/x:fixtext', $group_rule); + if ($rule_check_ref->length) { + $oval_id = $rule_check_ref->item(0)->getAttribute('name'); + } else { + $oval_id = ''; } - elseif ($vms_id == 'V0001103' || $vms_id == 'V-1103') { - $rule_stig_id = '4.010'; + $match = []; + $discussion = ""; + if (preg_match("/(.*)<\/VulnDiscussion>/", html_entity_decode($rule_desc), $match)) { + $discussion = $match[1]; } - } - // Check if rule is an IAVM - $is_iavm = false; - if (preg_match('/([\d]+\-[ABT]\-[\d]+)/', $rule_title, $match)) { - $references[] = $match[1]; - if (!$rule_stig_id) { - $rule_stig_id = $match[1]; - $is_iavm = true; - } - } - // Check if rule is an MS bulletin - if (preg_match('/(MS[\d]\-[\d]+)/', $rule_title, $match)) { - $references[] = $match[1]; - if (!$rule_stig_id) { - $rule_stig_id = $match[1]; - } - } - - // If no STIG ID found, set to "No Reference" - if (!$rule_stig_id) { - error_log("Could not find stig id for group id $vms_id"); - $rule_stig_id = 'No Reference'; - } - - $searchstring = [ - 'MS[\d]+\-[\d]+', - 'CVE\-[\d\-]+', - '[^E]CAN\-[\d\-]+' - ]; - - foreach ($searchstring as $string) { - if (preg_match_all("/($string)/", $rule_desc, $match)) { - for ($x = 0; $x < count($match[0]); $x++) { - if (!in_array($match[0][$x], $references)) { - $references[] = $match[0][$x]; + // Remove unnecessary whitespace from and concatenate check content + if ($check_content_nodes->length > 0) { + for ($x = 0; $x < $check_content_nodes->length; $x ++) { + $rule_check_content .= ($x + 1) . ") " . textCleanup($check_content_nodes->item($x)->textContent) . PHP_EOL; } - } + + $rule_check_content = trim($rule_check_content, PHP_EOL); } - if (preg_match_all("/($string)/", $rule_check_content, $match)) { - for ($x = 0; $x < count($match[0]); $x++) { - if (!in_array($match[0][$x], $references)) { - $references[] = $match[0][$x]; + // $log->script_log("STIG ID: $rule_stig_id", E_DEBUG); + // Assign default category if not provided and add comment indicating such to rule description + if (! $cat) { + $cat = 2; + $discussion .= " :CAT SET BY SCRIPT"; + } + + // Extract and append potential impacts tag content from/to rule description + if (preg_match('/(.*)<\/PotentialImpacts>/', $rule_desc, $match)) { + $discussion .= "\n{$match[1]}"; + } + + if (! $rule_stig_id) { + if ($vms_id == 'V0001073' || $vms_id == 'V-1073') { + $rule_stig_id = '2.005'; + } elseif ($vms_id == 'V0001103' || $vms_id == 'V-1103') { + $rule_stig_id = '4.010'; } - } - } - } - - $safe_rule_title = preg_replace('/[\(\)\[\]\.\+\*]/', '', $rule_title); - - $ia_ctrl = []; - - if (isset($stigs["$rule_stig_id"])) { - print "."; - $updated_count++; - $db_stig = $stigs["$rule_stig_id"]; - $db_pdi = $db->get_PDI($db_stig->get_PDI_ID(), $chk->get_ID()); - $db_pdi->set_Group_Title($group_title); - $db_pdi->set_Short_Title($rule_title); - $db_pdi->set_Check_Contents($rule_check_content); - $db_pdi->set_Fix_Text($fix_text); - $pdi_id = $db_pdi->get_ID(); - - if ($db_pdi->get_Category_Level() != $cat) { - $db_pdi->set_Catetgory_Level($cat); - $db_pdi->set_Update($checklist['benchmark_date']->format("Y-m-d")); } - $db->save_PDI($db_pdi, $chk); - } - else { - print "*"; - // add pdi - $new_count++; - $db_pdi = new pdi(null, $cat, $checklist['benchmark_date']->format('Y-m-d')); - $db_pdi->set_Group_Title($group_title); - $db_pdi->set_Short_Title($rule_title); - $db_pdi->set_Check_Contents($rule_check_content); - $db_pdi->set_Fix_Text($fix_text); - $pdi_id = $db->save_PDI($db_pdi, $chk); - $db_pdi->set_ID($pdi_id); - - // add stig - $db_stig = new stig($pdi_id, $rule_stig_id, $discussion); - $db->add_Stig($db_stig); - - $new = true; - } - - if (!empty($vms_id)) { - $vms_id = preg_replace("/^V0+/", "V-", $vms_id); - $gd = $db->get_GoldDisk($vms_id); - if (empty($gd)) { - $gd = new golddisk($pdi_id, $vms_id, $rule_title); - $db->save_GoldDisk($gd); - } - } - - /* - if (!$db->save_Check_Contents($db_pdi, $chk, $rule_check_content, $fix_text)) { - $log->script_log("Couldn't save check contents for STIG ID: {$db_stig->get_ID()} in checklist {$chk->get_Checklist_ID()} ({$chk->get_File_Name()})\n", E_ERROR); - } - */ - - $new_controls = []; - $control_fields = ['pdi_id', 'type', 'type_id']; - - if (preg_match("/(.*)<\/IAControls>/i", $rule_desc, $match)) { - $ia_controls = (isset($match[1]) && !empty($match[1]) ? $match[1] : null); - - if (preg_match("/DCSQ|ECMT/i", $ia_controls)) { - $new_controls[] = [ - $pdi_id, - 'VIVM', - '1' - ]; - $ias[] = "VIVM-1"; - } - elseif ($ia_controls) { - $split_ias = preg_split('/\, ?/', $ia_controls); - - foreach ($split_ias as $ia) { - $split_ia = explode("-", $ia); - - if (isset($split_ia[0]) && $split_ia[1]) { - $ias[] = "{$split_ia[0]}-{$split_ia[1]}"; - $new_controls[] = [ - $pdi_id, - $split_ia[0], - $split_ia[1] - ]; + // Check if rule is an IAVM + $is_iavm = false; + if (preg_match('/([\d]+\-[ABT]\-[\d]+)/', $rule_title, $match)) { + $references[] = $match[1]; + if (! $rule_stig_id) { + $rule_stig_id = $match[1]; + $is_iavm = true; } - } } - } - elseif ($rule_ident->length) { - for ($x = 0; $x < $rule_ident->length; $x++) { - if (substr($rule_ident->item($x)->textContent, 0, 3) == 'CCI') { - $split_ia = explode("-", $rule_ident->item($x)->textContent); - - if (isset($split_ia[0]) && isset($split_ia[1])) { - $ias[] = "{$split_ia[0]}-{$split_ia[1]}"; - $new_controls[] = [ - $pdi_id, - $split_ia[0], - $split_ia[1] - ]; + // Check if rule is an MS bulletin + if (preg_match('/(MS[\d]\-[\d]+)/', $rule_title, $match)) { + $references[] = $match[1]; + if (! $rule_stig_id) { + $rule_stig_id = $match[1]; } - } } - } - else { - if ($is_iavm) { - $ias[] = "CCI-002613"; - $new_controls[] = [ - $pdi_id, - "CCI", - "002613" - ]; - } - else { - $ias[] = "CCI-000366"; - $new_controls[] = [ - $pdi_id, - "CCI", - "000366" - ]; - } - } - //$db_ia = $db->get_IA_Controls_By_PDI($db_pdi->get_ID()); - if (isset($cmd['ia_reset']) && !$new) { - // delete ia controls - $db->help->delete("sagacity.ia_controls", [ - [ - 'field' => 'pdi_id', - 'op' => '=', - 'value' => $pdi_id - ] + // If no STIG ID found, set to "No Reference" + if (! $rule_stig_id) { + error_log("Could not find stig id for group id $vms_id"); + $rule_stig_id = 'No Reference'; + } + + $searchstring = [ + 'MS[\d]+\-[\d]+', + 'CVE\-[\d\-]+', + '[^E]CAN\-[\d\-]+' + ]; + + foreach ($searchstring as $string) { + if (preg_match_all("/($string)/", $rule_desc, $match)) { + for ($x = 0; $x < count($match[0]); $x ++) { + if (! in_array($match[0][$x], $references)) { + $references[] = $match[0][$x]; + } + } + } + + if (preg_match_all("/($string)/", $rule_check_content, $match)) { + for ($x = 0; $x < count($match[0]); $x ++) { + if (! in_array($match[0][$x], $references)) { + $references[] = $match[0][$x]; + } + } + } + } + + $safe_rule_title = preg_replace('/[\(\)\[\]\.\+\*]/', '', $rule_title); + + $ia_ctrl = []; + + if (isset($stigs["$rule_stig_id"])) { + print "."; + $updated_count ++; + $db_stig = $stigs["$rule_stig_id"]; + $db_pdi = $db->get_PDI($db_stig->get_PDI_ID(), $chk->get_ID()); + $db_pdi->set_Group_Title($group_title); + $db_pdi->set_Short_Title($rule_title); + $db_pdi->set_Check_Contents($rule_check_content); + $db_pdi->set_Fix_Text($fix_text); + $pdi_id = $db_pdi->get_ID(); + + if ($db_pdi->get_Category_Level() != $cat) { + $db_pdi->set_Catetgory_Level($cat); + $db_pdi->set_Update($checklist['benchmark_date']->format("Y-m-d")); + } + + $db->save_PDI($db_pdi, $chk); + } else { + print "*"; + // add pdi + $new_count ++; + $db_pdi = new pdi(null, $cat, $checklist['benchmark_date']->format('Y-m-d')); + $db_pdi->set_Group_Title($group_title); + $db_pdi->set_Short_Title($rule_title); + $db_pdi->set_Check_Contents($rule_check_content); + $db_pdi->set_Fix_Text($fix_text); + $pdi_id = $db->save_PDI($db_pdi, $chk); + $db_pdi->set_ID($pdi_id); + + // add stig + $db_stig = new stig($pdi_id, $rule_stig_id, $discussion); + $db->add_Stig($db_stig); + + $new = true; + } + + if (! empty($vms_id)) { + $vms_id = preg_replace("/^V0+/", "V-", $vms_id); + $gd = $db->get_GoldDisk($vms_id); + if (empty($gd)) { + $gd = new golddisk($pdi_id, $vms_id, $rule_title); + $db->save_GoldDisk($gd); + } + } + + /* + * if (!$db->save_Check_Contents($db_pdi, $chk, $rule_check_content, $fix_text)) { + * $log->script_log("Couldn't save check contents for STIG ID: {$db_stig->get_ID()} in checklist {$chk->get_Checklist_ID()} ({$chk->get_File_Name()})\n", E_ERROR); + * } + */ + + $new_controls = []; + $control_fields = [ + 'pdi_id', + 'type', + 'type_id' + ]; + + if (preg_match("/(.*)<\/IAControls>/i", $rule_desc, $match)) { + $ia_controls = (isset($match[1]) && ! empty($match[1]) ? $match[1] : null); + + if (preg_match("/DCSQ|ECMT/i", $ia_controls)) { + $new_controls[] = [ + $pdi_id, + 'VIVM', + '1' + ]; + $ias[] = "VIVM-1"; + } elseif ($ia_controls) { + $split_ias = preg_split('/\, ?/', $ia_controls); + + foreach ($split_ias as $ia) { + $split_ia = explode("-", $ia); + + if (isset($split_ia[0]) && $split_ia[1]) { + $ias[] = "{$split_ia[0]}-{$split_ia[1]}"; + $new_controls[] = [ + $pdi_id, + $split_ia[0], + $split_ia[1] + ]; + } + } + } + } elseif ($rule_ident->length) { + for ($x = 0; $x < $rule_ident->length; $x ++) { + if (substr($rule_ident->item($x)->textContent, 0, 3) == 'CCI') { + $split_ia = explode("-", $rule_ident->item($x)->textContent); + + if (isset($split_ia[0]) && isset($split_ia[1])) { + $ias[] = "{$split_ia[0]}-{$split_ia[1]}"; + $new_controls[] = [ + $pdi_id, + $split_ia[0], + $split_ia[1] + ]; + } + } + } + } else { + if ($is_iavm) { + $ias[] = "CCI-002613"; + $new_controls[] = [ + $pdi_id, + "CCI", + "002613" + ]; + } else { + $ias[] = "CCI-000366"; + $new_controls[] = [ + $pdi_id, + "CCI", + "000366" + ]; + } + } + + // $db_ia = $db->get_IA_Controls_By_PDI($db_pdi->get_ID()); + if (isset($cmd['ia_reset']) && ! $new) { + // delete ia controls + $db->help->delete("sagacity.ia_controls", [ + [ + 'field' => 'pdi_id', + 'op' => '=', + 'value' => $pdi_id + ] + ]); + $db->help->execute(); + } + + if (count($new_controls)) { + $db->help->extended_replace("sagacity.ia_controls", $control_fields, $new_controls); + if (! $db->help->execute()) { + $db->help->debug(E_ERROR); + } + } + + $sv = new sv_rule($pdi_id, $sv_rule); + $db->save_SV_Rule(array( + 0 => $sv + )); + + if ($rule_ident->length) { + foreach ($rule_ident as $ident_node) { + if (! in_array($ident_node->textContent, $references) && $ident_node->textContent != 'CCI') { + $references[] = $ident_node->textContent; + } + } + } + + if (count($references)) { + foreach ($references as $key => $ref) { + $tmp = null; + if (substr($ref, 0, 3) == 'CVE' || substr($ref, 0, 3) == 'CAN') { + $tmp[] = new cve($pdi_id, $ref); + $db->save_CVE($tmp); + } elseif (substr($ref, 0, 3) == 'CCE') { + $tmp[] = new cce($pdi_id, $ref); + $db->save_CCE($tmp); + } elseif (substr($ref, 0, 2) == 'KB') {} elseif (substr($ref, 0, 2) == 'MS') { + $tmp[] = new advisory($pdi_id, $ref, '', 'MS', ''); + $db->save_Advisory($tmp); + } + // print_r($tmp[0]); + unset($tmp); + } + } + + if ($perc_comp % 100 == 0) { + print "\t$perc_comp completed" . PHP_EOL; + } + + // Output the CSV contents + fputcsv($csv, [ + $rule_stig_id, + $vms_id, + implode("", array_fill(0, $cat, "I")), + implode(" ", $ias), + $rule_title, + "Not Reviewed", + "", + $rule_check_content, + $sv_rule, + $oval_id ]); - $db->help->execute(); - } - if (count($new_controls)) { - $db->help->extended_replace("sagacity.ia_controls", $control_fields, $new_controls); - if (!$db->help->execute()) { - $db->help->debug(E_ERROR); - } - } - - $sv = new sv_rule($pdi_id, $sv_rule); - $db->save_SV_Rule(array(0 => $sv)); - - if ($rule_ident->length) { - foreach ($rule_ident as $ident_node) { - if (!in_array($ident_node->textContent, $references) && $ident_node->textContent != 'CCI') { - $references[] = $ident_node->textContent; - } - } - } - - if (count($references)) { - foreach ($references as $key => $ref) { - $tmp = null; - if (substr($ref, 0, 3) == 'CVE' || substr($ref, 0, 3) == 'CAN') { - $tmp[] = new cve($pdi_id, $ref); - $db->save_CVE($tmp); - } - elseif (substr($ref, 0, 3) == 'CCE') { - $tmp[] = new cce($pdi_id, $ref); - $db->save_CCE($tmp); - } - elseif (substr($ref, 0, 2) == 'KB') { - - } - elseif (substr($ref, 0, 2) == 'MS') { - $tmp[] = new advisory($pdi_id, $ref, '', 'MS', ''); - $db->save_Advisory($tmp); - } - //print_r($tmp[0]); - unset($tmp); - } - } - - if ($perc_comp % 100 == 0) { - print "\t$perc_comp completed" . PHP_EOL; - } - - // Output the CSV contents - fputcsv($csv, [$rule_stig_id, $vms_id, implode("", array_fill(0, $cat, "I")), implode(" ", $ias), $rule_title, "Not Reviewed", "", $rule_check_content, $sv_rule, $oval_id]); - - unset($references); - $db->update_Catalog_Script($base_name, ['name' => 'perc_comp', 'value' => ($perc_comp / $groups->length) * 100]); + unset($references); + $db->update_Catalog_Script($base_name, [ + 'name' => 'perc_comp', + 'value' => ($perc_comp / $groups->length) * 100 + ]); } $db->help->select_count("sagacity.stigs"); @@ -678,27 +697,35 @@ $db->set_Setting('stig-count', $stig_count); $end = new DateTime(); $diff = $end->diff($start); -print PHP_EOL . "Start Time: {$start->format("H:i:s")}" . PHP_EOL; -print "End Time: {$end->format("H:i:s")}" . PHP_EOL; -print "Execution time: {$diff->format("%H:%I:%S")}" . PHP_EOL . PHP_EOL; -print "New STIGs: $new_count" . PHP_EOL; -print "Updated STIGs: $updated_count" . PHP_EOL; -print "Total STIGs: " . ($new_count + $updated_count) . PHP_EOL . PHP_EOL . PHP_EOL; +print <<format("H:i:s")} +End Time: {$end->format("H:i:s")} +Execution time: {$diff->format("%H:%I:%S")} + +New STIGs: $new_count +Updated STIGs: $updated_count +Total STIGs: ($new_count + $updated_count) $log->script_log("$groups->length complete"); fclose($csv); -if (!isset($cmd['debug'])) { - rename($cmd['f'], DOC_ROOT . "/reference/stigs/$base_name"); +if (! isset($cmd['debug'])) { + rename($cmd['f'], DOC_ROOT . "/reference/stigs/$base_name"); } rename($csv_file, DOC_ROOT . "/reference/stigs/" . basename($csv_file)); -$db->update_Catalog_Script($base_name, ['name' => 'perc_comp', 'value' => 100, 'complete' => 1]); +$db->update_Catalog_Script($base_name, [ + 'name' => 'perc_comp', + 'value' => 100, + 'complete' => 1 +]); /** * Usage output */ -function usage() { - print <<update_Running_Scan($base_name, ['name' => 'status', 'value' => 'TERMINATED']); + $db->update_Running_Scan($base_name, ['name' => 'notes', 'value' => 'File parsing was terminated because was empty or absent']); unset($xml); rename($cmd['f'], TMP . "/terminated/{$base_name}"); diff --git a/img/checklist_icons/Ubuntu.png b/img/checklist_icons/Ubuntu.png new file mode 100644 index 0000000000000000000000000000000000000000..4758e9b9f90255ed47ea880d4eb2e4d1cec3f065 GIT binary patch literal 17166 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 literal 0 HcmV?d00001