sagacity/exec/export-ckl.php
Ryan Prather 21082c7513 checklist.inc - deleted duplicate BIND 9 checklist icon entry
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
2018-11-06 15:36:48 -05:00

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