Ryan Prather
21082c7513
finding.inc - removed ID property to prevent duplicate findings from being added to the table host_list.inc - deleted unused constructor import.inc - formatting db_schema.json - removed sagacity.findings.id field (making tgt_id and pdi_id new primary keys), and updated references Database_Baseline.zip - updated routines for above change background_results.php - fixed bug #19 export-ckl.php - performance adjustments parse_excel_echecklist.php - performance improvements, ensure duplicate findings are not created, make eChecklist true status, update for removing findings.id field parse_nvd_json_cve.php - convert reading json to array instead of object for reading CPEs (which were updated to CPE 2.3 instead of 2.2) parse_* - remove findings.id field database.inc - formatting, and update for removing findings.id field index.php - ensure user can't import a host list without uploading a host list file Fixed: #65, #51, #28, #27, #10
439 lines
12 KiB
PHP
439 lines
12 KiB
PHP
<?php
|
|
|
|
/**
|
|
* File: export-ckl.php
|
|
* Author: Ryan Prather <ryan.prather@cyberperspectives.com>
|
|
* Purpose:
|
|
* Created: Feb 20, 2017
|
|
*
|
|
* Copyright 2017: Cyber Perspective, LLC, All rights reserved
|
|
* Released under the Apache v2.0 License
|
|
*
|
|
* See license.txt for details
|
|
*
|
|
* Change Log:
|
|
* - Feb 20, 2017 - File created
|
|
* - Mar 8, 2017 - Completed preliminary functionality
|
|
* - May 13, 2017 - Set default export path to TMP/ckl
|
|
* Only exporting manual checklists and not export orphan findings
|
|
* - Oct 23, 2017 - Added a few more fields and added data to some fields that didn't have a value
|
|
* - Nov 25, 2017 - Fixed notice bug #346
|
|
* - Jan 6, 2018 - Bug fix #337 and formatting
|
|
*/
|
|
include_once 'config.inc';
|
|
include_once 'database.inc';
|
|
include_once 'helper.inc';
|
|
include_once 'array2xml.inc';
|
|
|
|
$db = new db();
|
|
$dt = new DateTime();
|
|
|
|
$cmd = getopt('s:t::c::h::d::', ['help::', 'debug::']);
|
|
|
|
if (!isset($cmd['s']) || !is_numeric($cmd['s'])) {
|
|
die(usage());
|
|
}
|
|
|
|
if (isset($cmd['t'])) {
|
|
$tgts = $db->get_Target_Details($cmd['s'], $cmd['t']);
|
|
}
|
|
elseif (isset($cmd['c'])) {
|
|
$tgts = $db->get_Target_By_Category($cmd['c']);
|
|
}
|
|
else {
|
|
$tgts = $db->get_Target_Details($cmd['s']);
|
|
}
|
|
|
|
if (isset($cmd['d'])) {
|
|
if (file_exists($cmd['d'])) {
|
|
$dest = realpath($cmd['d']) . "/";
|
|
}
|
|
else {
|
|
die("Could not find destination path {$cmd['d']}");
|
|
}
|
|
}
|
|
else {
|
|
check_path(TMP . "/ckl", true);
|
|
$dest = realpath(TMP . "/ckl") . "/";
|
|
}
|
|
|
|
print "Destination: $dest" . PHP_EOL;
|
|
|
|
$status_map = [
|
|
'Not Reviewed' => 'Not_Reviewed',
|
|
'Not a Finding' => 'NotAFinding',
|
|
'Open' => 'Open',
|
|
'Not Applicable' => 'Not_Applicable',
|
|
'No Data' => 'Not_Reviewed',
|
|
'Exception' => 'Open',
|
|
'False Positive' => 'NotAFinding'
|
|
];
|
|
|
|
$xml = new Array2XML();
|
|
$xml->standalone = true;
|
|
$xml->formatOutput = true;
|
|
|
|
$total_chk_count = 0;
|
|
$total_stigs = 0;
|
|
|
|
if ($tgt_count = count($tgts)) {
|
|
print "Total Targets: $tgt_count" . PHP_EOL;
|
|
|
|
foreach ($tgts as $tgt) {
|
|
$host_ip = (is_array($tgt->interfaces) && count($tgt->interfaces) ? current($tgt->interfaces)->get_IPv4() : null);
|
|
$host_fqdn = (is_array($tgt->interfaces) && count($tgt->interfaces) ? current($tgt->interfaces)->get_FQDN() : null);
|
|
$host_mac = (is_array($tgt->interfaces) && count($tgt->interfaces) ? current($tgt->interfaces)->get_MAC() : null);
|
|
|
|
print "Target: {$tgt->get_Name()}" . PHP_EOL;
|
|
|
|
foreach ($tgt->checklists as $key => $chk) {
|
|
if ($chk->name == 'Orphan' || $chk->type != 'manual') {
|
|
unset($tgt->checklists[$key]);
|
|
}
|
|
}
|
|
|
|
$total_chk_count += $chk_count = (is_array($tgt->checklists) ? count($tgt->checklists) : 0);
|
|
|
|
print "Total Checklists: $chk_count" . PHP_EOL;
|
|
|
|
foreach ($tgt->checklists as $chk) {
|
|
print "Type: {$chk->type}\tChecklist: {$chk->name}" . PHP_EOL;
|
|
$class = '';
|
|
$stig_class = '';
|
|
|
|
switch ($chk->get_Classification()) {
|
|
case 'U':
|
|
$class = 'UNCLASSIFIED';
|
|
$stig_class = "Unclass";
|
|
break;
|
|
case 'FOUO':
|
|
$class = 'UNCLASSIFIED//FOUO';
|
|
$stig_class = "FOUO";
|
|
break;
|
|
case 'S':
|
|
$class = 'SECRET';
|
|
$stig_class = "Secret";
|
|
break;
|
|
}
|
|
|
|
$arr = [
|
|
'@comment' => "CyberPerspectives Sagacity v" . VER,
|
|
'ASSET' => [
|
|
'ROLE' => 'None',
|
|
'ASSET_TYPE' => 'Computing',
|
|
'HOST_NAME' => $tgt->get_Name(),
|
|
'HOST_IP' => $host_ip,
|
|
'HOST_MAC' => $host_mac,
|
|
'HOST_FQDN' => $host_fqdn,
|
|
'TECH_AREA' => '',
|
|
'TARGET_KEY' => '',
|
|
'WEB_OR_DATABASE' => false,
|
|
'WEB_DB_SITE' => '',
|
|
'WEB_DB_INSTANCE' => ''
|
|
],
|
|
'STIGS' => [
|
|
'iSTIG' => [
|
|
'STIG_INFO' => [
|
|
'SI_DATA' => [
|
|
[
|
|
'SID_NAME' => 'version',
|
|
'SID_DATA' => $chk->get_Version()
|
|
],
|
|
[
|
|
'SID_NAME' => 'classification',
|
|
'SID_DATA' => $class
|
|
],
|
|
[
|
|
'SID_NAME' => 'customname'
|
|
],
|
|
[
|
|
'SID_NAME' => 'stigid',
|
|
'SID_DATA' => $chk->get_Checklist_ID()
|
|
],
|
|
[
|
|
'SID_NAME' => 'description',
|
|
'SID_DATA' => $chk->get_Description()
|
|
],
|
|
[
|
|
'SID_NAME' => 'filename',
|
|
'SID_DATA' => $chk->get_File_Name()
|
|
],
|
|
[
|
|
'SID_NAME' => 'releaseinfo',
|
|
'SID_DATA' => "Release: {$chk->get_Release()} Benchmark Date: {$chk->get_Date()->format("j M Y")}"
|
|
],
|
|
[
|
|
'SID_NAME' => 'title',
|
|
'SID_DATA' => $chk->get_Name()
|
|
],
|
|
[
|
|
'SID_NAME' => 'uuid',
|
|
'SID_DATA' => UUID::v4()
|
|
],
|
|
[
|
|
'SID_NAME' => 'notice',
|
|
'SID_DATA' => 'terms-of-use'
|
|
],
|
|
[
|
|
'SID_NAME' => 'source',
|
|
'SID_DATA' => 'STIG.DOD.MIL'
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
$pdis = get_checklist_data($tgt, $chk);
|
|
$stig_data = [];
|
|
|
|
$total_stigs += $pdi_count = (is_array($pdis) ? count($pdis) : 0);
|
|
$count = 0;
|
|
|
|
$findings = $db->get_Finding($tgt);
|
|
|
|
foreach ($pdis as $pdi) {
|
|
if (isset($findings[$pdi['pdi_id']])) {
|
|
$find = $findings[$pdi['pdi_id']];
|
|
}
|
|
|
|
$sev = 'low';
|
|
if ($pdi['CAT'] == 'I') {
|
|
$sev = 'high';
|
|
}
|
|
elseif ($pdi['CAT'] == 'II') {
|
|
$sev = 'medium';
|
|
}
|
|
|
|
$ccis = preg_grep("/CCI\-/", explode(" ", $pdi['IA_Controls']));
|
|
$cci_list = [];
|
|
|
|
if (is_array($ccis) && count($ccis)) {
|
|
foreach ($ccis as $cci) {
|
|
$cci_list[] = [
|
|
'VULN_ATTRIBUTE' => 'CCI_REF',
|
|
'ATTRIBUTE_DATA' => $cci
|
|
];
|
|
}
|
|
}
|
|
|
|
// decoding because check contents are already encoded
|
|
//$cc = str_replace("\\n", "\n", htmlentities(html_entity_decode($pdi['check_contents'])));
|
|
|
|
$stig_data = array_merge([
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Vuln_Num',
|
|
'ATTRIBUTE_DATA' => $pdi['VMS_ID']
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Severity',
|
|
'ATTRIBUTE_DATA' => $sev
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Group_Title',
|
|
'ATTRIBUTE_DATA' => $pdi['group_title']
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Rule_ID',
|
|
'ATTRIBUTE_DATA' => $pdi['SCAP_Rule']
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Rule_Ver',
|
|
'ATTRIBUTE_DATA' => $pdi['STIG_ID']
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Rule_Title',
|
|
'ATTRIBUTE_DATA' => $pdi['short_title']
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Vuln_Discuss',
|
|
'ATTRIBUTE_DATA' => $pdi['Description']
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'IA_Controls',
|
|
'ATTRIBUTE_DATA' => $pdi['IA_Controls']
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Check_Content',
|
|
'ATTRIBUTE_DATA' => htmlentities(str_replace("\\n", "\n", html_entity_decode(html_entity_decode($pdi['check_contents']))))
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Fix_Text',
|
|
'ATTRIBUTE_DATA' => htmlentities(str_replace("\\n", "\n", html_entity_decode(html_entity_decode($pdi['fix_text']))))
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'False_Positives',
|
|
'ATTRIBUTE_DATA' => ''
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'False_Negatives',
|
|
'ATTRIBUTE_DATA' => ''
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Documentable',
|
|
'ATTRIBUTE_DATA' => 'false'
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Mitigations',
|
|
'ATTRIBUTE_DATA' => ''
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Potential_Impact',
|
|
'ATTRIBUTE_DATA' => ''
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Third_Party_Tools',
|
|
'ATTRIBUTE_DATA' => ''
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Mitigation_Control',
|
|
'ATTRIBUTE_DATA' => ''
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Responsibility',
|
|
'ATTRIBUTE_DATA' => ''
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Security_Override_Guidance',
|
|
'ATTRIBUTE_DATA' => ''
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Check_Content_Ref',
|
|
'ATTRIBUTE_DATA' => 'M'
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Weight',
|
|
'ATTRIBUTE_DATA' => '10.0'
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'Class',
|
|
'ATTRIBUTE_DATA' => $stig_class
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'STIGRef',
|
|
'ATTRIBUTE_DATA' => "{$chk->get_Name()} :: Release: {$chk->get_Release()} Benchmark Date: {$chk->get_Date()->format("j M Y")}"
|
|
],
|
|
[
|
|
'VULN_ATTRIBUTE' => 'TargetKey',
|
|
'ATTRIBUTE_DATA' => ''
|
|
]
|
|
], $cci_list);
|
|
|
|
$status = 'Not_Reviewed';
|
|
$notes = '';
|
|
|
|
if (is_a($find, 'finding')) {
|
|
/** @var finding $find */
|
|
$status = $status_map[$find->get_Finding_Status_String()];
|
|
$notes = $find->get_Notes();
|
|
}
|
|
|
|
$arr['STIGS']['iSTIG']['VULN'][] = [
|
|
'STIG_DATA' => $stig_data,
|
|
'STATUS' => $status,
|
|
'FINDING_DETAILS' => $notes,
|
|
'COMMENTS' => '',
|
|
'SEVERITY_OVERRIDE' => '',
|
|
'SEVERITY_JUSTIFICATION' => ''
|
|
];
|
|
|
|
$count++;
|
|
|
|
printf("\r%.2f%%", ($count / $pdi_count) * 100);
|
|
}
|
|
|
|
print PHP_EOL;
|
|
|
|
$file = $xml->createXML('CHECKLIST', $arr);
|
|
|
|
$file->save("{$dest}{$tgt->get_Name()}_{$chk->get_Checklist_ID()}_{$chk->get_type()}_{$dt->format("Ymd")}.ckl");
|
|
}
|
|
}
|
|
}
|
|
|
|
print <<<EOO
|
|
|
|
Total Targets: $tgt_count
|
|
Total Checklists: $total_chk_count
|
|
Total STIGs: $total_stigs
|
|
|
|
EOO;
|
|
|
|
/**
|
|
*
|
|
* @global db $db
|
|
*
|
|
* @param target $tgt
|
|
* @param checklist $chk
|
|
*
|
|
* @return mixed
|
|
*/
|
|
function get_checklist_data($tgt, $chk) {
|
|
if (!is_a($tgt, 'target') || !is_a($chk, 'checklist')) {
|
|
return;
|
|
}
|
|
|
|
global $db;
|
|
|
|
$db->help->select("sagacity.pdi", ["pdi.*", "pcl.*", "s.description AS 'Description'"], [
|
|
[
|
|
'field' => 'tc.tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_ID()
|
|
],
|
|
[
|
|
'field' => 'tc.chk_id',
|
|
'op' => '=',
|
|
'value' => $chk->id,
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"JOIN sagacity.pdi_checklist_lookup pcl ON pcl.pdi_id = pdi.pdi_id",
|
|
"JOIN sagacity.target_checklist tc ON tc.chk_id = pcl.checklist_id",
|
|
"JOIN sagacity.stigs s ON s.pdi_id = pdi.pdi_id"
|
|
]
|
|
]);
|
|
$pdis = $db->help->execute();
|
|
|
|
return $pdis;
|
|
}
|
|
|
|
/**
|
|
* Function retrieve
|
|
*
|
|
* @global db $db
|
|
*
|
|
* @param target $tgt
|
|
* @param checklist $chk
|
|
*
|
|
* @return mixed
|
|
*/
|
|
function get_finding_data($tgt, $chk) {
|
|
global $db;
|
|
$ret = [];
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Usage output
|
|
*/
|
|
function usage() {
|
|
print <<<EOO
|
|
Purpose: This script was written to be able to export CKL files from the data contained in the database.
|
|
|
|
Usage: php export-ckl.php [-d={destination}] -s={ste id} [-c={category id}] [-t={target id}] [-h|--help]
|
|
|
|
-s={STE ID} Export a CKL for each assigned checklist for ALL targets in this ST&E
|
|
-c={Category ID} Export CKL files for all targets contained in this Category
|
|
-t={Target ID} Export CKL file for each assigned checklist for this target
|
|
|
|
-d={destination} Location of where you want the files saved
|
|
|
|
-h|--help This screen
|
|
--debug Debugging output
|
|
|
|
EOO;
|
|
}
|