sagacity/exec/parse_iavm.php
2018-05-07 10:51:08 -04:00

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;
}