338 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			338 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * File: parse_iavm.php
 | |
|  * Author: Ryan Prather
 | |
|  * Purpose: To parse IAVM files retrieved from https://iavm.csd.disa.mil
 | |
|  * Created: Jul 9, 2014
 | |
|  *
 | |
|  * Portions Copyright 2016: Cyber Perspectives, All rights reserved
 | |
|  * Released under the Apache v2.0 License
 | |
|  *
 | |
|  * Portions Copyright (c) 2012-2015, Salient Federal Solutions
 | |
|  * Portions Copyright (c) 2008-2011, Science Applications International Corporation (SAIC)
 | |
|  * Released under Modified BSD License
 | |
|  *
 | |
|  * See license.txt for details
 | |
|  *
 | |
|  * Change Log:
 | |
|  *  - Jul 9, 2014 - File created
 | |
|  *  - Sep 1, 2016 - Copyright Updated and converted to constants
 | |
|  */
 | |
| $cmd = getopt("d:f::", array('debug::', 'help::'));
 | |
| 
 | |
| if (!isset($cmd['f']) || !isset($cmd['s']) || isset($cmd['help'])) {
 | |
|   usage();
 | |
|   exit;
 | |
| }
 | |
| 
 | |
| include_once 'config.inc';
 | |
| include_once "database.inc";
 | |
| include_once 'helper.inc';
 | |
| 
 | |
| chdir(DOC_ROOT . "/tmp");
 | |
| set_time_limit(0);
 | |
| 
 | |
| $sys = new db();
 | |
| 
 | |
| $db = new mysqli(DB_SERVER, 'web', db::decrypt_pwd(), 'sagacity');
 | |
| if ($db->connect_errno) {
 | |
|   die($db->connect_error);
 | |
| }
 | |
| 
 | |
| if (!isset($cmd['d'])) {
 | |
|   die("Did not include the directory the files are in");
 | |
| }
 | |
| 
 | |
| chdir($cmd['d']);
 | |
| 
 | |
| if (isset($cmd['f'])) {
 | |
|   $files = array(0 => $cmd['f']);
 | |
| }
 | |
| else {
 | |
|   $files = glob("*.xml");
 | |
| }
 | |
| 
 | |
| foreach ($files as $file) {
 | |
|   print $file . PHP_EOL;
 | |
|   $doc = new DOMDocument();
 | |
|   $doc->load($file);
 | |
| 
 | |
|   $pi = $doc->createProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="iavm.xsl"');
 | |
|   $doc->insertBefore($pi, $doc->getElementsByTagName("iavmNotice")->item(0));
 | |
|   $doc->xmlStandalone = true;
 | |
| 
 | |
|   $tmp = $doc->saveXML();
 | |
|   $tmp = str_replace(" xmlns=\"http://iavm.csd.disa.mil/schemas/IavmNoticeSchema/1.2\"", "", $tmp);
 | |
|   $doc->loadXML($tmp);
 | |
| 
 | |
|   // root node values (iavm_notice table)
 | |
|   $id = getValue($doc, '/iavmNotice/@noticeId');
 | |
|   $xmlurl = getValue($doc, '/iavmNotice/xmlUrl');
 | |
|   $htmlurl = getValue($doc, '/iavmNotice/htmlUrl');
 | |
|   $noticeNumber = getValue($doc, '/iavmNotice/iavmNoticeNumber');
 | |
|   $title = getValue($doc, '/iavmNotice/title');
 | |
|   $type = getValue($doc, '/iavmNotice/type');
 | |
|   $state = getValue($doc, '/iavmNotice/state');
 | |
|   $lastUpdated = getValue($doc, '/iavmNotice/lastUpdated');
 | |
|   $releaseDate = getValue($doc, '/iavmNotice/releaseDate');
 | |
|   $supersedes = getValue($doc, '/iavmNotice/supersedes');
 | |
|   $execSummary = getValue($doc, '/iavmNotice/executiveSummary');
 | |
|   $fixAction = getValue($doc, '/iavmNotice/fixAction');
 | |
|   $note = getValue($doc, '/iavmNotice/note');
 | |
|   $vulnAppsSysAndCntrmsrs = getValue($doc, '/iavmNotice/vulnAppsSysAndCntrmsrs');
 | |
|   $knownExploits = getValue($doc, '/iavmNotice/knownExploits');
 | |
|   $stigFindingSeverity = getValue($doc, '/iavmNotice/vms/stigFindingSeverity');
 | |
| 
 | |
|   // iavm_tech_overview
 | |
|   $techOverview = getValue($doc, '/iavmNotice/techOverview', null, true);
 | |
| 
 | |
|   // iavm_references
 | |
|   $references = getValue($doc, '/iavmNotice/references/reference', null, true);
 | |
| 
 | |
|   // iavm_bids
 | |
|   $bids = getValue($doc, '/iavmNotice/deepSightBids/bid', null, true);
 | |
| 
 | |
|   // iavm_patches
 | |
|   $patches = getValue($doc, '/iavmNotice/patches/patch', null, true);
 | |
| 
 | |
|   // iavm_mitigations
 | |
|   $mitHeader = getValue($doc, '/iavmNotice/tempMitStrat/header');
 | |
|   $mitBody = getValue($doc, '/iavmNotice/tempMitStrat/body');
 | |
| 
 | |
|   $doc->formatOutput = true;
 | |
|   $doc->preserveWhiteSpace = true;
 | |
|   //print $doc->saveXML();
 | |
| 
 | |
|   if (is_array($supersedes)) {
 | |
|     $supersedes = implode(',', $supersedes);
 | |
|   }
 | |
| 
 | |
|   $stig = $sys->get_Stig($noticeNumber);
 | |
|   if (is_array($stig) && count($stig) && isset($stig[0]) && is_a($stig[0], 'stig')) {
 | |
|     $stig = $stig[0];
 | |
|     $pdi_id = $stig->get_PDI_ID();
 | |
|   }
 | |
|   else {
 | |
|     $pdi = new pdi(null, $stigFindingSeverity, $lastUpdated);
 | |
|     $pdi->set_Short_Title($title);
 | |
|     $pdi->set_Group_Title($title);
 | |
|     $pdi->set_Description($execSummary);
 | |
|     // print_r($pdi);
 | |
|     $pdi_id = $sys->save_PDI($pdi);
 | |
| 
 | |
|     $stig = new stig($pdi_id, $noticeNumber, $execSummary);
 | |
|     // print_r($stig);
 | |
|     $sys->add_Stig($stig);
 | |
|   }
 | |
| 
 | |
|   $last_updated_dt = new DateTime($lastUpdated);
 | |
|   $release_date_dt = new DateTime($releaseDate);
 | |
| 
 | |
|   $iavm = $sys->get_IAVM($noticeNumber);
 | |
|   if (is_null($iavm)) {
 | |
|     $sys->help->insert("sagacity.iavm_notices", [
 | |
|       'pdi_id'                 => $pdi_id,
 | |
|       'noticeId'               => $id,
 | |
|       'xmlUrl'                 => $xmlurl,
 | |
|       'htmlUrl'                => $htmlurl,
 | |
|       'file_name'              => basename($file),
 | |
|       'iavmNoticeNumber'       => $noticeNumber,
 | |
|       'title'                  => $title,
 | |
|       'type'                   => $type,
 | |
|       'state'                  => $state,
 | |
|       'lastUpdated'            => $last_updated_dt->format(MYSQL_D_FORMAT),
 | |
|       'releaseDate'            => $release_date_dt->format(MYSQL_D_FORMAT),
 | |
|       'supersedes'             => $supersedes,
 | |
|       'executiveSummary'       => $execSummary,
 | |
|       'fixAction'              => $fixAction,
 | |
|       'note'                   => $note,
 | |
|       'vulnAppsSysAndCntrmsrs' => $vulnAppsSysAndCntrmsrs,
 | |
|       'stigFindingSeverity'    => $stigFindingSeverity,
 | |
|       'knownExploits'          => $knownExploits
 | |
|         ], true);
 | |
| 
 | |
|     if (!$sys->help->execute()) {
 | |
|       error_log("file: $file" . PHP_EOL . $db->error . PHP_EOL . $ins_sql);
 | |
|       continue;
 | |
|       //die;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ($bids->length) {
 | |
|     foreach ($bids as $bid) {
 | |
|       if ($res = $db->query(
 | |
|           "SELECT COUNT(1) as 'cnt' FROM sagacity.iavm_bids WHERE iavm_notice_id = $id AND bid = '" . $bid->textContent .
 | |
|           "'")) {
 | |
|         if ($res->num_rows) {
 | |
|           $row = $res->fetch_array(MYSQLI_ASSOC);
 | |
|           print "existing bid: $bid->textContent" . PHP_EOL;
 | |
|         }
 | |
|         else {
 | |
|           $sql = "INSERT INTO sagacity.iavm_bids (iavm_notice_id, bid) VALUES ($id, $bid->textContent)";
 | |
|           $db->real_query($sql);
 | |
|           print "new bid: $bid->textContent" . PHP_EOL;
 | |
|         }
 | |
|       }
 | |
|       else {
 | |
|         error_log($db->error);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ($references->length) {
 | |
|     foreach ($references as $ref) {
 | |
|       $url = getValue($doc, "url", $ref);
 | |
|       $title = getValue($doc, "title", $ref);
 | |
|       $type = getValue($doc, "type", $ref);
 | |
| 
 | |
|       $res = $db->query(
 | |
|           "SELECT id FROM sagacity.iavm_references WHERE iavm_notice_id = $id AND url='" .
 | |
|           $db->real_escape_string($url) . "'");
 | |
| 
 | |
|       if ($res->num_rows) {
 | |
|         $row = $res->fetch_array(MYSQLI_ASSOC);
 | |
|         $sql = "UPDATE sagacity.iavm_references SET title = '" . $db->real_escape_string($title) .
 | |
|             "' WHERE id = " . $row['id'];
 | |
|         $db->real_query($sql);
 | |
|         print "existing reference: " . $title . " (" . $row['id'] . ")" . PHP_EOL;
 | |
|       }
 | |
|       else {
 | |
|         $sql = "INSERT INTO sagacity.iavm_references (iavm_notice_id, title, url) VALUES ($id, '" .
 | |
|             $db->real_escape_string($title) . "','" . $db->real_escape_string($url) . "')";
 | |
|         $db->real_query($sql);
 | |
|         // print "db error: ".$db->error.PHP_EOL;
 | |
|         print "new reference: " . $title . PHP_EOL;
 | |
|       }
 | |
| 
 | |
|       $matches = array();
 | |
|       if (preg_match("/microsoft\.com.*\/([\d]+)/i", $url, $matches) ||
 | |
|           preg_match("/(MS[\d]+\-[\d]+)/", $title, $matches)) {
 | |
|         if (is_numeric($matches[1])) {
 | |
|           $matches[1] = "KB" . $matches[1];
 | |
|         }
 | |
|         $adv = new advisory($pdi_id, $matches[1], "", "", $url);
 | |
|         $sys->save_Advisory(array(
 | |
|           0 => $adv
 | |
|         ));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ($techOverview->length) {
 | |
|     foreach ($techOverview as $to) {
 | |
|       $details = getValue($doc, "details", $to);
 | |
|       if ($details) {
 | |
|         $res = $db->query(
 | |
|             "SELECT id FROM sagacity.iavm_tech_overview WHERE iavm_notice_id = $id AND details='" .
 | |
|             $db->real_escape_string($details) . "'");
 | |
|         $row = $res->fetch_array(MYSQLI_ASSOC);
 | |
| 
 | |
|         if ($row['id']) {
 | |
|           print "existing overview for $id" . PHP_EOL;
 | |
|         }
 | |
|         else {
 | |
|           $sql = "INSERT INTO sagacity.iavm_tech_overview (iavm_notice_id, details) VALUES ($id, '" .
 | |
|               $db->real_escape_string($details) . "')";
 | |
|           $db->real_query($sql);
 | |
|           print "new overview" . PHP_EOL;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       $entries = getValue($doc, "entry", $to, true);
 | |
|       if ($entries->length) {
 | |
|         foreach ($entries as $entry) {
 | |
|           $entry_title = getValue($doc, "title", $entry);
 | |
|           $entry_desc = getValue($doc, "description", $entry);
 | |
| 
 | |
|           if (substr($entry_title, 0, 3) == 'CVE') {
 | |
|             print "CVE: $entry_title" . PHP_EOL;
 | |
|             $sql = "REPLACE INTO sagacity.iavm_to_cve (noticeId, cve_id) VALUES (" . $id . "," . "'" .
 | |
|                 $db->real_escape_string($entry_title) . "')";
 | |
| 
 | |
|             $db->real_query($sql);
 | |
|           }
 | |
|           else {
 | |
|             Sagacity_Error::err_handler("Entry title: $entry_title in file $file");
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ($patches->length) {
 | |
|     foreach ($patches as $patch) {
 | |
|       $title = getValue($doc, "title", $patch);
 | |
|       $type = getValue($doc, "type", $patch);
 | |
|       $url = getValue($doc, "url", $patch);
 | |
| 
 | |
|       $res = $db->query(
 | |
|           "SELECT id FROM sagacity.iavm_patches WHERE iavm_notice_id = $id AND url = '" .
 | |
|           $db->real_escape_string($url) . "'");
 | |
|       $row = $res->fetch_array(MYSQLI_ASSOC);
 | |
| 
 | |
|       if ($row['id']) {
 | |
|         $sql = "UPDATE sagacity.iavm_patches SET `type` = '" . $db->real_escape_string($type) .
 | |
|             "', `title` = '" . $db->real_escape_string($title) . "' WHERE id = " . $row['id'];
 | |
|         $db->real_query($sql);
 | |
|         print "existing patch: $title (" . $row['id'] . ")" . PHP_EOL;
 | |
|       }
 | |
|       else {
 | |
|         $sql = "INSERT INTO sagacity.iavm_patches (iavm_notice_id, `type`, title, url) VALUES ($id, '" .
 | |
|             $db->real_escape_string($type) . "','" . $db->real_escape_string($title) . "','" .
 | |
|             $db->real_escape_string($url) . "')";
 | |
|         $db->real_query($sql);
 | |
|         print "new patch: $title" . PHP_EOL;
 | |
|       }
 | |
| 
 | |
|       $matches = array();
 | |
|       if (preg_match("/(KB[\d]+)|(MS[\d]+\-[\d]+)/i", $title, $matches)) {
 | |
|         $adv = new advisory($pdi_id, $matches[1], "", "", $url);
 | |
|         $sys->save_Advisory(array(
 | |
|           0 => $adv
 | |
|         ));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ($mitHeader) {
 | |
|     $res = $db->query(
 | |
|         "SELECT id FROM sagacity.iavm_mitigations WHERE iavm_notice_id = $id AND header = '" .
 | |
|         $db->real_escape_string($mitHeader) . "'");
 | |
|     $row = $res->fetch_array(MYSQLI_ASSOC);
 | |
| 
 | |
|     if ($row['id']) {
 | |
|       $sql = "UPDATE sagacity.iavm_mitigations SET body = '" . $db->real_escape_string($mitBody) .
 | |
|           "' WHERE id = " . $row['id'];
 | |
|       $db->real_query($sql);
 | |
|       print "existing mitigation: " . $row['id'] . PHP_EOL;
 | |
|     }
 | |
|     else {
 | |
|       $sql = "INSERT INTO sagacity.iavm_mitigations (iavm_notice_id, header, body) VALUES ($id, '" .
 | |
|           $db->real_escape_string($mitHeader) . "','" . $db->real_escape_string($mitBody) . "')";
 | |
|       $db->real_query($sql);
 | |
|       print "new mitigation: $mitHeader" . PHP_EOL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!$doc->save(DOC_ROOT . "/reference/iavms/$file")) {
 | |
|     print "error saving" . PHP_EOL;
 | |
|     die;
 | |
|   }
 | |
| }
 | |
| 
 | |
| function usage() {
 | |
|   print <<<EOO
 | |
| Purpose: To import an IAVM file and populate/update the database
 | |
| 
 | |
| Usage: php parse_iavm.php -d={IAVM Directory} [-f={XCCDF result file}] [--debug] [--help]
 | |
| 
 | |
|  -d={IAVM directory}    The directory to import the files from.  This will crawl the directory and import all the IAVMs
 | |
|  -f={XCCDF file}        The IAVM file specifically
 | |
| 
 | |
|  --debug                Debugging output
 | |
|  --help                 This screen
 | |
| 
 | |
| EOO;
 | |
| }
 |