Automating Security Control Compliance Assessment with Sagacity
MATTHEW SHUTER, University of Colorado, Colorado Springs
Conducting vulnerability assessments on Department of Defense systems is subject to numerous
levels of requirements to assess for compliance. We help to develop, test, and stabilize the open
source tool Sagacity, which aims to automate much of the effort associated with correlating data from
multiple vulnerability assessment tools, vulnerability databases, and compliance frameworks. We
extend Sagacity to include the capability to map findings to NIST 800-53 security controls and
identified 55 bugs in Sagacity, remediating 13 of them.
1 IntroductionThe US Department of Defense (DoD) considers the security of information systems to be of
paramount importance to national security. As such, the DoD mandates compliance with DoD
Instruction (DoDI) 8510.01, which, among other requirements, directs the use of the Risk Management
Framework (RMF) and the Committee for National Security Systems Instruction (CNSSI) 1253 to select,
implement, evaluate, and monitor compliance with the NIST 800-53 security controls (hereafter, “NIST
Controls”) [1, 2, 3]. Furthermore, it directs implementation of the DoD Information Systems Agency’s
(DISA) Security Requirements Guides (SRGs) and Security Technical Implementation Guides (STIGs),
hereafter collectively referred to as Security Guides (SGs) for brevity unless more specificity is needed
[4].
The implementation of RMF has proved to provide an overwhelming quantity of data to manage for
DoD programs, with the 800-53 controls being decomposed into a minimum of 1,376 Control
Correlation Identifiers (CCIs) – a number which only goes up depending on security and privacy control
requirements selected for information systems [5]. CCIs represent a standard identifier and description
for each atomic, actionable statement that comprises a cybersecurity control [6]. Each of the SG
requirements maps to a CCI, which in turn maps to an 800-53 control. Furthermore, the SGs
themselves can be quite lengthy. For example, the Windows 7 STIG alone has 303 checklist items, all
of which must be validated to show compliance with their parent CCIs and controls [7]. Considering
that there are SGs for each of dozens of different operating systems, applications and technologies,
and that they need to be applied to complex, enterprise networks sometimes with hundreds if not
thousands of hosts, the problem is clearly unmanageable without the assistance of automated
compliance assessment and analysis tools.
Exacerbating the problem is the fact that even with automated tools, at present, many of the SG
checklist items and controls must be manually checked by an auditor in an interactive fashion due to a
number of factors. In some cases, the check could be automated but simply has not been. In others,
the check is too complex to automate. Another possibility is that the check requires some on-site
inspection of the system before the correct course of action for evaluating the check may be
determined. Finally, some of the checks require interviews with personnel or inspection of the
environment in order to assess compliance and are therefore not candidates for automation.
In order to attempt to help manage the sizeable task of planning, executing, analyzing, and
reporting on such a compliance assessment, the developers at CyberPerspectives, LLC have designed
and implemented the open source project Sagacity [8]. Sagacity is intended to be a multi-input, multi-
output security data correlation engine that attempts to enable all phases of compliance assessment
by:
Centralizing and indexing configuration and vulnerability reference data from multiple sources
Processing automated scan results and script output from multiple sources
Producing electronic checklists for manual compliance checks in a user-friendly Microsoft Excel
format which auditors can use to conduct assessments
Providing an extensible framework for reducing manual checks
Correlating the data for analysis and reporting compliance against either legacy DIACAP or
RMF controls.
Eventually, enabling compliance reporting in a multitude of other compliance frameworks
including the Health Insurance Portability and Accountability Act (HIPAA), Payment Card
Industry Data Security Standard (PCI DSS), and more [9, 10].
1.1ObjectivesThe purpose of this project is to help stabilize and extend the Sagacity tool. The following are four
specific objectives in scope for this project:
1. Test and debug the Sagacity tool to make it stable enough for initial public release
2. Add the capability to export eChecklists with NIST 800-53 RMF control mappings for STIG
checklist items
3. Contribute to code comments and documentation to facilitate recruiting of additional
contributors to the project and encourage adoption
4. Learn web-based database application development in general and specifically the Sagacity
project well enough to use, debug, and extend the tool in real-world compliance assessment
1.2Sagacity BackgroundThe original concept for Sagacity arises from the developers’ experiences conducting vulnerability
assessments on isolated DoD systems with limited connectivity, few-to-no integrated enterprise
capabilities, and extensive security compliance requirements. The limitations of existing tools and
laborious process of compliance auditing and analyzing data in these non-enterprise environments
inspired the ideas and early scripting efforts that would eventually grow into Sagacity.
The predominant use case for Sagacity is to aid an assessment team in evaluating such a system
while using DoD-prescribed vulnerability scanning and configuration auditing tools and checklists.
Figure 1-1 illustrates the role of Sagacity in orchestrating a vulnerability assessment and managing
and correlating the different data types as described below.
Figure 1-1 - Sagacity Concept of Operations
In this scenario, a large portion of compliance auditing is conducted with a combination of
Commercial Off-The-Shelf (COTS), Government Off-The-Shelf (GOTS), and Free and Open Source
Software (FOSS) assessment tools. Typically an assessment begins with using network-based
vulnerability scanners (e.g, Tenable Nessus, and Nmap) to maximize automated assessment of as
many hosts on the network as possible and as many compliance settings as supported by these tools
[11,12]. There is also a government-provided tool called the SPAWAR SCAP Compliance Checker (SCC)
which can be executed on a target host to evaluate compliance with DISA-provided SCAP benchmarks
in the case that a host is not scannable from the network for any number of reasons (network
architecture, firewalls, physical isolation, host configuration prevents remote access, etc.) [13,14].
Running multiple tools is considered a best practice due to the fact that it provides greater coverage of
potential vulnerabilities as well as helping to root out potential false positives and false negatives.
Automated tools are not sufficient, however, as there are SG requirements for compliance that
extend substantially past what these tools are capable of automating, which are hereafter referenced
as “manual checks”. The SGs provide “check contents” for these manual checks written in such a way
as to assume that the auditor is sitting at the terminal on the target system interactively executing
commands, which is untenable based on the sheer volume and effort involved in such an approach for
any network of significant size and complexity. To address this, Sagacity includes a number of host-
based scripts which collect system baseline configuration files and command output which contains
much of the data required for assessment of the manual checks, reducing required on-system data
collection time. In addition to supporting the evaluation of manual checks, the script output can be
used offline following the assessment to facilitate risk analysis. Furthermore, Sagacity is extensible in
that it supports creation of “Tweak Data” scripts which can process the output from these scripts in a
user-defined manner to evaluate checklist items according to the Tweak Data script logic.
While the goal is obviously to minimize manual effort, there will always be some checks which do
not lend themselves to automation. This includes physical, environmental, or documentation
requirements, targets that have only a GUI interface, or those that have only general SGs available
(i.e, do not have specific check content commands which can be incorporated into a script). The
challenges here are that 1.) the SGs do not distinguish automatable from non-automatable checks, 2.)
The automated tools have already evaluated many of the SG checks, so a way is needed to determine
which have been evaluated and which have not, and 3.) each tool or script used provides its output in
disparate formats, and 4.) different tools may have identified conflicting results for the same check.
Sagacity facilitates reduction of SGs to the remaining manual checks by providing parsers for the most
commonly used tools and then correlating the SG checks to the scan data. It then deconflicts results
by taking the “high-water mark” of all open findings (i.e., if any tool identifies a finding as open, its
status is set to “Open”). Additionally it saves notes that indicate which tool found which result,
highlighting the conflict for analysts to further investigate.
Finally, Sagacity provides the capability to export the checklists in one of two useful formats – the
eChecklist Excel spreadsheet format or the .ckl format used by DISA’s STIG Viewer tool. Both formats
pre-populate the output with the findings which were automatically evaluated, enabling the auditor to
address only those findings which were not reviewed. The .ckl format provides the advantage of being
a standard format used by the prescribed DISA tool commonly used by organizations, while the
eChecklist format provides the advantages of displaying each checklist/platform in a tabular array of
hosts by findings and leverages Excel’s capabilities to facilitate working with and analyzing the data.
The tabular layout enables sorting and filtering (e.g., by category or finding status) and also enables
auditors to assess manual checks on multiple systems in parallel while providing a color-coded visual
indicator of the compliance level of the platform and completion level of the checklists. Excel formulas
also provide real-time metrics that indicate the numbers of findings by severity, the consistency of a
set of hosts, a “high-water mark” of open findings (i.e., which findings are open on at least one host),
and the total number of remaining manual checks to be assessed.
Once manual checks are complete, the completed checklists can then be re-imported into Sagacity
as the central repository for all assessment-related data. Here, Sagacity also provides the feature of
tracking the status of assessment tasks, enabling the users to specify the types of data anticipated for
each collection of hosts and tracking progress toward collection of all data. Finally, the developers
intend to expand Sagacity’s capabilities to include generation of reports in a number of desired
compliance framework formats.
1. Tool must be open source and widely available. As discussed in Section 1.2, many tools used
throughout the DoD have limitations which necessitate organizations creating custom tools to
address the gaps. This results in redundant time and expense as agencies develop their own
solutions which are either considered proprietary and contained in stove-piped organizations
or allowed to wither as the cost of support becomes too great. Making a tool widely available
that addresses common needs will alleviate this waste of resources.
2. Tool must be extensible. To address new and updated security related data standards as well
as expanding support for additional compliance frameworks, the tool must be extensible.
Making the tool open source (Requirement 1) goes a long way to addressing this as
contributors can add their own parsers. The relational database backend and object/data
models also facilitate the integration and correlation of new data sources.
3. Tool must support the most commonly used compliance scanning tools in DoD risk
assessments. These tools are discussed further in Section 1.2.
4. Scanner data sources should be correlated to security controls in the DIACAP compliance
framework and any remaining checklist items that must be manually checked should be easily
identified. Conflicts between findings status from independent scanner sources should also be
highlighted for manual assessment.
5. Tool must export remaining manual checks into a portable format for auditors to execute and
record manual checks
6. Tool must leverage popular open data standards including but not limited to CVEs, CPEs, SCAP,
STIGs
7. Tool must provide an interface for tracking progress toward assessment completion, grouping
related hosts, and tracking progress of data import jobs.
1.3Related Tools and ResearchThe DoD and commercial vendors provide multiple tools for cybersecurity practitioners to employ in
automation of security control assessments (SCAs), each with its own strengths and limitations.
Tools that are currently used to automate DoD vulnerability assessment and risk assessment
include most prominently Tenable SecurityCenter, Nessus, and Passive Vulnerability Scanner [15], the
SCAP Compliance Checker (SCC) [16], DISA STIG Viewer [17], Vulnerator [18], and DISA Enterprise
Mission Assurance Support Service (eMASS) [19]. Tenable SecurityCenter, while providing a rich
automated environment is not capable of importing and correlating data from multiple sources. Being
a closed-source, for-profit product, Tenable develops their technologies to work only with Tenable-
specified, tightly-coupled data formats and stores the data in their unspecified database schema. The
SecurityCenter product cannot, for example, import nmap scan results or SCC reports or perform
correlations to NIST controls. Additionally, Tenable products do not map CVEs to the corresponding
IAVMs which the DoD uses to track compliance.
Government-provided products include the and SCC, STIG Viewer, Vulnerator, and eMASS. SCC also
is a closed-source product with no ability to import data sources other than SCAP/OVAL or correlate
findings to NIST controls. Furthermore, it is primarily a host-based scanning tool, making it impractical
for being the single option for assessment. STIG Viewer imports SCC results and eliminates automated
checks, however it is single-threaded, meaning that it only supports a single checklist being run
against a single host at a time, making it impractical for large systems. It also does not do correlation
of CCIs to NIST controls. Vulnerator provides only the ability to import, correlate, and export data into a
spreadsheet. There is no persistence and no data model to be leveraged to support analysis and
reporting, nor the ability to integrate new data sources. Finally, eMASS is a centralized, cloud
deployed, enterprise capability which is not typically accessible from the field when conducting
vulnerability assessments. Furthermore, it is intended for senior level compliance reporting and does
not include many of the detailed technical level features provided by Sagacity.
1.4Summary of contributionsThis project contributes the following capabilities to the Sagacity effort and its developer
community:
Tested and identified 55 bugs in Sagacity
Resolved and patched 13 bugs in Sagacity
Added Risk Management Framework / NIST SP 800-53A Security Controls mapping and
exporting to the Sagacity application
Provided code comments for developers and documentation for users of Sagacity.
2 Analysis and DesignThe architecture of Sagacity is depicted in Figure 2-1. This shows how administrative command line
scripts are used to import open source vulnerability data in a variety of formats to build the database.
Once the database is built, users may begin using the web interface to import the various data types
generated by vulnerability assessments. All data types are normalized and correlated before persisting
into the database. Finally, checklist files can be exported for analysis and in the future, compliance
reports will be exported as well.
Additionally, Figure 2-1 shows the portions of Sagacity that will be modified to implement the RMF
control mapping. New capabilities are depicted in blue, while modified capabilities are depicted in
green. Details of how these capabilities will be modified are described futher in the remainder of this
section.
Figure 2-2 - Sagacity Architecture
2.1New RequirementsShortly after the initial pre-beta release of Sagacity (version 1.2) the DoD migrated from the DIACAP
framework to the Risk Management Framework (RMF). In light of this change, Sagacity must be
adapted such that export and reporting functions are capable of correlating scanner and checklist
findings to NIST SP 800-53 controls (hereafter “NIST controls”) instead of legacy DIACAP controls. A
principle objective of this project is to lay the foundation for RMF compliance assessment by
implementing the following two new requirements:
1. Import eMASS Control Correlation Identifier (CCI) to NIST control mapping spreadsheet. eMASS
is used by agencies to report compliance to the Authorizing Official for approval. It has a
unique control numbering scheme which is slightly different than that implemented by the CCI
XML or the NIST SP 800-53 publications themselves. The control mapping spreadsheet maps
the NIST controls to the CCIs that correlate to STIG findings.
2. Export eChecklists with eMASS/NIST SP800-53 security control identifiers to facilitate analysis
and reporting of control compliance.
Figure 2-2 is an example of an eChecklists before modification of the export algorithm to map the CCIs
in the STIGs to the NIST SP800-53 controls. Our objective is to replace the CCIs in column D (“IA
Controls”) with the NIST control identifier so that non-compliant STIG settings can be used to identify
their associated non-compliant control(s).
Figure 2-3 - CCIs in eChecklist Exports
2.2Database Schema Modifications
To store the mapping of NIST controls in the database, we need to identify a reasonable place to
store the mapping. In analyzing the database schema, we see that there is an existing table named
rmf.cci which holds the CCIs. This table is intended to be populated from the DISA-provided, XML-
formatted CCI list which maps NIST controls to CCIs. Since CCIs are intended to be atomic and the
eMASS CCI list is meant to provide a one-to-one mapping of subcontrols to CCIs, this initially seemed
like a perfect place to store the eMASS control identifier.
However, upon attempting to update the rmf.cci table from the DISA CCI list, we discovered that
there is an issue with using this table. Specifically, the parser for the CCI list, parse_cci.php was written
in 2014 and DISA has since changed the schema of the CCI list XML, therefore it is not currently
functional. Although the table in the database baseline is currently populated in the baseline from an
older, compatible version of the CCI file, with no feasible way of making regular updates it seemed
unwise to use the table to store the eMASS control identifiers until CCI import is working again. Upon
first importing, it was confirmed that this was a wise decision, as the rmf.cci table contained 2,734
records, while the emass_cci table contained 2,921 records, confirming that there would have been
unpopulated CCI records created as a result of importing the eMASS control map, with no effective way
to update them.
Therefore, we chose to read in the eMASS CCI table to a new table named rmf.emass_cci. The table
contains two fields, id and control. The id field is used to correlate the controls to the CCI specified in
STIG checklists. The control field is used to export NIST controls that are associated with STIG checks
for compliance reporting as required by eMASS.
2.3Required New CodeTo implement the new requirements, there are three primary components which must be created:
1. Create a parser to read the eMASS control to CCI mapping spreadsheet
2. Create a function in the database class to save the records in the table
3. Create a function in the database class to retrieve the records from the table
In Sagacity, parsers of the various data formats required to build the initial database are
implemented in command-line scripts contained in the <wwwroot>/exec directory. By convention,
they are named parse_<file_type>.php. In keeping with this convention, we will implement the parser
in a script titled parse_emass_control_map.php. Sagacity is using the PHPOffice library for interfacing
with Microsoft Excel, so this script will use the same library to read in the eMASS-to-CCI map file,
iterating over rows in the spreadsheet and saving them to the database table. Table 2-1 shows an
excerpt of the eMASS-to-CCI map file to indicate its structure.
Table 2-1 - Exceprt of eMASS-to-CCI Mapping Spreadsheet
AC-1.1 CCI-
002107
AC-1.2 CCI-
002108
AC-1.3 CCI-
000001
AC-1.4 CCI-
000002
AC-1.5 CCI-
000004
AC-1.6 CCI-
000005
AC-1.7 CCI-
000003
AC-1.8 CCI-
001545
AC-1.9 CCI-
000006
AC-1.10 CCI-
001546
AC-2.1 CCI-
002110
AC-2.2 CCI-
002111
AC-2.3 CCI-
002112
AC-2.4 CCI-
000008
AC-2.5 CCI-
002113
AC-2.6 CCI-
002115
AC-2.7 CCI-
002116
AC-2.8 CCI-
002117
AC-2.9 CCI-
002118
AC-2.10 CCI-
002119
AC-2.11 CCI-
000010
AC-2.12 CCI-
002120
… …
All of Sagacity’s interaction with the database is implemented in the ‘db’ class in database.inc.
Functions in this class follow the convention get_<Table_Name> and save_<Table_Name> for the
functions that save complete records. Again, adhering to convention, we name our functions
save_EMASS_CCIs() and get_EMASS_CCIs() functions. It should be noted that although there are
already functions for save_CCIs() and get_CCIs(), these functions are intended for use in the
unsupported parse_CCI.php script previously mentioned. Because of the decision create a new table,
there is no conflict with function names.
2.4Required Code ModificationsIn addition to creating the parsing script and database interface functions, existing functionality
must be modified to enable Sagacity to export the NIST controls made accessible through the new
database table in lieu of the CCIs it was previously exporting as references for the STIG settings.
Sagacity currently exports the CCIs to a column in eChecklists at two different points. The first is
when STIG checklists are imported, and the second is when eChecklists are exported. Upon importing
STIG checklists, the parse_stig.php script creates CSV-formatted eChecklist templates in the
<wwwroot>/reference/stigs directory. These CSVs can then be used during the assessment to quickly
create eChecklists for evaluation of hosts and platforms that are not automatically populated based on
scan data (in lieu of using the interface to create targets, assign checklists, and export them). Listing
2-1 is an example of the XML being parsed by the parse_stig.php script, and following that is Listing 2-
2 which shows the relevant sections of code that extracts the CCIs and writes them to the CSV.
Listing 2-1 - CCI Reference in STIG XML
Note the tag <ident system="http://iase.disa.mil/cci">CCI-000366</ident>. This is the CCI value
that we are looking for to enable correlation to the NIST controls.
<Group id="V-1115"><title>Rename Built-in Administrator Account</title><description><GroupDescription></GroupDescription></description><Rule id="SV-25023r2_rule" weight="10.0" severity="medium"> <version>4.022</version> <title>The built-in administrator account must be renamed.</title> <description> <VulnDiscussion>The built-in administrator account is a well-known account subject to attack. Renaming this account to an unidentified name improves the protection of this account and the system.</VulnDiscussion>… </description> <ident system="http://cce.mitre.org">CCE-8484-8</ident> <ident system="http://iase.disa.mil/cci">CCI-000366</ident>…</Rule></Group>
Listing 2-2 - CCI Processing Code
In the above code, the $groups variable is the collection of <Group> DOMElement nodes of the XML
STIG checklist. The loop simply iterates over each <Group> element, capturing the data that is desired
for storage in the database. In addition to saving the data in the database, select data is assembled
into a CSV-formatted eChecklists as well, which is written in the call to fputcsv() in the final line of code
above. To make this function write controls as opposed to CCIs, we must modify the $ias variable so
that it is populated with the correlated controls from the rmf.emass_cci table.
The second place that Sagacity currently exports the CCIs is when exporting eChecklists via the
export.php script. This script behaves in much the same way, however instead of creating a CSV file
from the STIG XML, it retrieves the findings from the database and writes them to an Excel eChecklist.
Listing 2-3 shows this in action. In this code, like before, we must replace the $ia_controls_string
variable with a list of NIST controls rather than a list of CCIs.
// Get the collection of STIG rules i.e., <Group> elements$groups = getValue($xml, '/x:Benchmark/x:Group', null, true);…foreach ($groups as $group) {… // Get the Rule DOMElement $group_rule = getValue($xml, 'x:Rule', $group, true)->item(0);… // Get the ident DOMElement $rule_ident = getValue($xml, ".//x:ident", $group_rule, true); // Loop over ident elements, looking for CCIs for ($x = 0; $x < $rule_ident->length; $x++){ // If text looks like a CCI, save it 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])) { // Add cci string to the array that will be inserted into the csv $ias[] = "{$split_ia[0]}-{$split_ia[1]}"; // Add cci to the array that will be inserted into the ia_controls table $new_controls[] = array( $pdi_id, $split_ia[0], $split_ia[1] ); } }… // Insert the all the STIG check attributes into the STIG csv. fputcsv($csv, array($rule_stig_id, $vms_id, implode("", array_fill(0, $cat, "I")), implode(" ", $ias), $rule_title, "Not Reviewed", "", $rule_check_content, $sv_rule, $oval_id));}
Listing 2-3 - CCI Exporting Code
Finally, to enable testing of the new RMF export functionality without breaking current functionality,
we will want to wrap all modified code in a block which executes conditionally depending on the
setting of a Boolean global variable which we will call “do_rmf”.
3 Implementation3.1Database Schema Implementation
Upon installation, Sagacity uses the install.php script to read in the db_schema.xml file, which it
uses to create the baseline database schema. Therefore, to add our table to the schema, we modified
the file to include an XML description of the table, its fields, constraints, and attributes.
We chose the ‘id’ field representing the CCI identifier as the primary key. Since CCI identifiers are
fixed length and all begin with the string “CCI-“ followed by a six-digit unique integer, we chose the
mediumint data type to efficiently store the ID. The “CCI-“ string and leading zeroes will be prepended
in code where CCIs are used. For example, the first CCI in the imported file is “CCI-002107”, which will
be stored as a mediumint value 2107.
The second field named ‘control’ is used to represent the NIST control identifier used by the eMASS
database. These identifiers are alphanumeric and consist of a two-character control family, followed by
a dash and control number, optional parenthetical control enhancement number, and finally a decimal
CCI identifier to uniquely identify each atomic CCI element of the control. An example control ID with
no enhancement would be “AC-1.1.” This tells us this is the first control in the Access Control (AC) family, and the first CCI
// Iterate over checklist items ($stig_id) and populate spreadsheet with status foreach ($data['stigs'] as $stig_id => $tgt_status) { $notes = ''; $ia_controls_string = $tgt_status['echecklist']->get_IA_Controls_String(); $sheet->setCellValue("A{$row}", $stig_id) ->setCellValue("B{$row}", $tgt_status['echecklist'] ->get_VMS_ID()) ->setCellValue("C{$row}", $tgt_status['echecklist'] ->get_Cat_Level_String()) ->setCellValue("D{$row}", $ia_controls_string) ->setCellValue("E{$row}", html_entity_decode($tgt_status['echecklist'] ->get_Short_Title())); …}
of that control. An example of a control ID with enhancement would be AC-2(1).1, which would be first enhancement to control
AC-2, and the first CCI of that control enhancement. Since control numbers, enhancements, and CCI numbers are currently at
most two digits, the field size for the control string must be 12 characters with punctuation.
Finally, both fields are assigned the attribute of “Not Null”, since this is a junction table and there is
no reason to have a record if both fields are not populated. The following is the modification to the
db_schema.xml file required to implement the control-to-CCI mapping in the database:
Listing 3-4 - Extending the Database Schema
3.2New CodeThe primary new code is in the parse_emass_control_map.php script. This script does the work of
importing the mapping of the CCIs to the eMASS-formatted NIST control IDs. Listing 3-2 shows the
essential code used in importing the spreadsheet.
<!-- rmf.emass_cci --> <table id='rmf.emass_cci'> <field id='id' type='mediumint' attr='NN' default='' /> <field id='control' type='varchar(12)' attr='NN' default='' /> <primary_key>id</primary_key> </table> <!-- rmf.emass_cci -->
Listing 3-5 - Parsing the eMASS Control Map Spreadsheet
The main code is the loop which reads in a line and cell at a time and captures the mappings in an
array. It then pushes each mapping onto the $ccis array, which is then written to the database using
the call to save_EMASS_CCIs.
The save_EMASS_CCIs function is defined in databases.inc, and is reproduced in Listing 3-3. The db
class acts as the interface between the objects Sagacity uses and the database. To import the new
mapping to a junction table, we defined the function so that it takes the array of mappings created in
the above code and inserts them into the database with an extended insert. It does this using the
extended_insert function of the db objects helper class, which abstracts the SQL INSERT statement to
allow for insertion of an arbitrary number of records into the table passed in the first argument with
the columns being inserted passed as a second argument and the array of records to insert passed in
as the third argument.
// Create reader for file$Reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile($cmd['f']);$Reader->setReadDataOnly(true);$objSS = $Reader->load($cmd['f']);
// Get the first and only worksheet$wksht = $objSS->getSheet(0);
$col1 = true; // Bool to determine which column we're in within the loop$ccis = array(); // Array to hold cci-control mappings
// Main loop to read in the Excel spreadsheetforeach ($wksht->getRowIterator() as $row) { foreach ($row->getCellIterator() as $cell) { if ($col1){ // First column is the control $ctrl = $cell->getValue(); } else { // Second column is the cci $cci = $cell->getValue(); } // Change the col1 to iterate between the two columns $col1 = !$col1; } // Truncate the CCI to just the integer portion $cci_id = substr($cci, strpos($cci, "-") + 1); // Push the pair on the $ccis array array_push($ccis, array($cci_id, $ctrl));} // Save the completed array to the database$db->save_EMASS_CCIs($ccis);
Listing 3-6 - Function save_EMASS_CCIs
Finally, we need a way to retrieve the mappings from the database. Fortunately, the table is small
enough that we can load the entire array into memory for very fast lookups. Therefore, we need define
only a function to retrieve the entire table and return it into an array. Listing 3-4 shows the
get_EMASS_CCIs function, which is called in the sections of code we modify to populate with controls in
lieu of CCIs.
Listing 3-7 - Function get_EMASS_CCIs
3.3Modified CodeThe modifications we made to replace CCIs with RMF controls in parse_stig.php are shown in Listing
3-5. Immediately before the script begins looping over the <group> nodes in the XML, we retrieve the
mapping of controls to CCIs from the database using the database class get_EMASS_CCIs function
defined and described in Section 3.2. Within the loop, after the CCIs relevant to the currently
processing <group> node have been extracted to the $ias variable, we simply loop over the CCIs, and
/** * Function to save an array of eMASS-CCI mappings * * @param array:cci $cci_in * * @return boolean */ public function save_EMASS_CCIs($ccis_in) { $ret = false; $columns = array('id', 'control'); $this->help->extended_insert('rmf.emass_cci', $columns, $ccis_in, true); if ($this->help->execute()) { $ret = true; } else { $this->help->debug(E_ERROR); } return $ret;
/** * Get eMASS CCI Map * * @return array * Array of CCI-eMASS control mappings */ public function get_EMASS_CCIs() { $ret = array(); $this->help->select("rmf.emass_cci"); $ret = $this->help->execute(); return $ret; }
build an array of the correlated controls in the $rmf_controls array variable. Then in the fputcsv call
that writes the row to the CSV file, we replace the $ias array used previously with our newly created
$rmf_controls array.
Listing 3-8 - Substituting Control IDs for CCIs on STIG Checklist Creation
The behavior of export.php is similarly modified as shown in Listing 3-6. We begin be retrieving the
mapping of CCIs to controls, and this time, instead of looping over STIG XML, we are looping over
actual results that have been retrieved from the database. For each result, we retrieve the list of CCIs
using the get_IA_Controls method of the echecklist object. Then we declare an array to hold the
$rmf_controls, and loop over the CCIs (the $ia_controls variable) and replace them with RMF controls
looked up from the $emass_ccis array and expanded into a string in the $ia_controls_string variable.
And finally, the $ia_controls_string is inserted into the appropriate spreadsheet cell with the
setCellValue function.
// Get mapping of eMASS controls to CCIs from DB$emass_ccis = $db->get_EMASS_CCIs();// Iterate over each group element processing the attributes/childrenforeach ($groups as $group) {… // MAS replace CCIs w/ eMASS RMF Control
$rmf_controls = array(); foreach($ias as $ia){ // Remove 'CCI-' and leading zeros $id = ltrim( substr( $ia, strpos($ia, "-") + 1) , '0'); // lookup cci in $emass_ccis $key = array_search($id, array_column($emass_ccis, 'id')); // Push the control onto $rmf_controls array_push($rmf_controls, $emass_ccis[$key]['control']); }
fputcsv($csv, array($rule_stig_id, $vms_id, implode("", array_fill(0, $cat, "I")), implode(" ", $rmf_controls), $rule_title, "Not Reviewed", "", $rule_check_content, $sv_rule, $oval_id));
Listing 3-9 - Substituting Control IDs for CCIs on eChecklist Export
This concludes the description of the new features we added to Sagacity to support basic RMF
control compliance assessment. The following section shifts the focus to our involvement in testing
numerous successive Sagacity releases, debugging and fixing issues that were found, and
documenting Sagacity operation via code commenting. Figure 3-1 shows the updated exported
eChecklist with the NIST controls identified in Column D.
// Get mapping of eMASS controls to CCIs from DB$emass_ccis = $db->get_EMASS_CCIs();
foreach ($data['stigs'] as $stig_id => $tgt_status) {… // MAS replace CCIs w/ eMASS RMF Control and build string for checklist $ia_controls = $tgt_status['echecklist']->get_IA_Controls(); $rmf_controls = array();
foreach($ia_controls as $control){ // Remove 'CCI-' and leading zeros $id = ltrim( substr( $control, strpos($control, "-") + 1) , '0'); // lookup cci in $emass_ccis $key = array_search($id, array_column($emass_ccis, 'id')); // Push the control onto $rmf_controls array_push($rmf_controls, $emass_ccis[$key]['control']); }
$ia_controls_string = implode(" ", $rmf_controls); $sheet->setCellValue("A{$row}", $stig_id) ->setCellValue("B{$row}", $tgt_status['echecklist']->get_VMS_ID()) ->setCellValue("C{$row}", $tgt_status['echecklist']->get_Cat_Level_String()) ->setCellValue("D{$row}", $ia_controls_string) ->setCellValue("E{$row}", html_entity_decode($tgt_status['echecklist']->get_Short_Title()));
Figure 3-4 - NIST Control Identifiers in Exported eChecklist
4 Testing, Debugging, and Code CommentingAt the time of undertaking this project, the Sagacity tool was undergoing multiple transformations
resulting in a high degree of churn in the code base. The most significant of these changes include the
following:
Beginning and then abandoning an attempt to port the product to WordPress
Porting the product from Windows to support cross platform Windows and Linux web servers
Porting the database from MySQL to MariaDB
Regularly implementing bug fixes
Adding several needed features
These changes necessitated frequent releases and testing. For this reason, a major goal of this
project was to help stabilize the code base and identify and remediate bugs. In doing so, we found it
convenient to add code comments as we were tracing execution to isolate bugs. The following sections
highlight details of select bugs with which we had significant involvement in fixing and/or debugging
throughout the duration of this project. A complete table of the bugs we identified and their resolutions
is included in Appendix A.
4.1Details of Select Bugs FixedThis section details significant issues we identified and debugged to the point of isolating the
problems and submitting fixes to the lead developer for incorporation into the Sagacity project.
4.1.1 Overwriting Apache, MariaDB, and PHP Configuration Files (Bug #14)
Sagacity ships with its own configuration files for Apache, MariaDB, and PHP. These configuration
files are copied over the default files upon Sagacity installation by the 'install.bat' script. The my.ini file
(used to configure MariaDB) that was included with Sagacity included a 'skip-federated' directive which
had been supported in MySQL but is not supported in MariaDB. Therefore, when the XAMPP project
migrated from MySQL to MariaDB, MariaDB would fail to start after Sagacity installation due to the
invalid directive. The solution was to remove the 'skip-federated' directive from the my.ini file supplied
with Sagacity.
Additionally, this bug included discussion with the team regarding whether it was a bad practice to
overwrite users' configuration files on the chance that it might be a multi-application server. This was
mitigated by editing the install script to back up the existing config files (renamed to '*.old') before
copying the Sagacity configuration files.
4.1.2 Fixing Nessus File Parse Errors (Bug #15)With Developer release #14, upon attempting to import Nessus scan files, the following failure was
observed:
Listing 4-10 - Nessus Parsing Errors
An examination of the code revealed the failing line 269 as follows:
Listing 4-11 - Undefined Variable (1 of 2)
This and one subsequent line both referred to a non-existent $db variable. The second was line
279:
Listing 4-12 - Undefined Variable (2 of 2)
c:\xampp\www\exec>php parse_nessus.php -s 1 -f ..\tmp\nessus_report_Linux_Vulnerability_Scan.nessus -d \xampp\www
Notice: Undefined variable: db in C:\xampp\www\exec\parse_nessus.php on line 269
Call Stack: 0.0042 690312 1. {main}() C:\xampp\www\exec\parse_nessus.php:0 1.0967 3753024 2. scan_xml_parser->parse() C:\xampp\www\exec\parse_nessus.php:1633 1.4158 3767176 3. xml_parse() C:\xampp\www\inc\xml_parser.inc:355 1.4300 3772368 4. scan_xml_parser->stopElement() C:\xampp\www\inc\xml_parser.inc:355 1.4306 3772824 5. call_user_func:{C:\xampp\www\inc\xml_parser.inc:309}() C:\xampp\www\inc\xml_parser.inc:309 1.4306 3775352 6. nessus_parser->NessusClientData_v2_Report_ReportHost_HostProperties_end() C:\xampp\www\inc\xml_parser.inc:309
Fatal error: Call to a member function get_Regex_Array() on null in C:\xampp\www\exec\parse_nessus.php on line 269
Call Stack: 0.0042 690312 1. {main}() C:\xampp\www\exec\parse_nessus.php:0 1.0967 3753024 2. scan_xml_parser->parse() C:\xampp\www\exec\parse_nessus.php:1633 1.4158 3767176 3. xml_parse() C:\xampp\www\inc\xml_parser.inc:355 1.4300 3772368 4. scan_xml_parser->stopElement() C:\xampp\www\inc\xml_parser.inc:355 1.4306 3772824 5. call_user_func:{C:\xampp\www\inc\xml_parser.inc:309}() C:\xampp\www\inc\xml_parser.inc:309 1.4306 3775352 6. nessus_parser->NessusClientData_v2_Report_ReportHost_HostProperties_end() C:\xampp\www\inc\xml_parser.inc:309
$os_regex = $db->get_Regex_Array("os");
$os = $db->get_Software($os_arr->get_CPE());
These functions get_Regex_Array() and get_Software() are member functions of the database
object. Each parser object, including the nessus_parser object implemented by parse_nessus.php, has
a ‘db’ variable which holds a database object to abstract the parser’s connection to the database.
Since the ‘db’ variable is inherited from the scan_xml_parser object, the fix was to use $this->db-
>get_Regex_Array() or $this->db->get_Software().
4.1.3 Targets Not Populating in Multiple Screens (Bug #19)Once targets were confirmed to be loading into the database successfully, an issue remained where
the targets would not be displayed on the AJAX-enabled screens. In Figure 4-1, note the Operations
screen, where the “Unassigned” category has 23 hosts in the group (indicated by the “(23)” at the
right, and the category is expanded (indicated by the “-“ icon), however no hosts are listed. Similar
issues are exhibited in other pages wherever hosts are listed with AJAX calls, which indicates a
common root cause.
Figure 4-5 - AJAX Control Bug
Reloading the Operations screen with the Chrome developer tools console open, we get the
following error:
Listing 4-13 - Internal Server Error in ajax.php
The apache error log shows the following error repeated multiple times:
jquery-1.11.3.min.js:5 POST http://localhost/cgi-bin/ajax.php 500 (Internal Server Error)send @ jquery-1.11.3.min.js:5ajax @ jquery-1.11.3.min.js:5get_hosts @ ste_script.js:296collapse_expand @ ste_script.js:239onclick @ (index):327
Listing 4-14 - "Not Executable" Error in Apache Error Log
Adding a “#!C:\xampp\php\php.exe” fixes the server error, but now we get the following in our php
error log:
Listing 4-15 - - PHP Error Log Errors Executing ajax.php
Realizing that this seemed to be an error in the Apache configuration file with the repository, we
consulted the Apache CGI documentation to identify several issues with the provided configuration
[20]. To get ajax.php to work from /xampp/cgi-bin, the +ExecCGI option must be set on the
C:/xampp/cgi-bin directory. To fix, we corrected the configuration from that shown in Listing 4.7 to that
shown in Listing 4.8.
[Tue Nov 15 18:34:30.754455 2016] [win32:error] [pid 5416:tid 1772] [client 127.0.0.1:6471] AH02102: C:/xampp/cgi-bin/ajax.php is not executable; ensure interpreted scripts have "#!" or "'!" first line, referer: http://localhost/ste/[Tue Nov 15 18:34:30.754455 2016] [cgi:error] [pid 5416:tid 1772] (9)Bad file descriptor: [client 127.0.0.1:6471] AH01222: don't know how to spawn child process: C:/xampp/cgi-bin/ajax.php, referer: http://localhost/ste/
[15-Nov-2016 19:03:44 America/Denver] PHP Notice: Use of undefined constant DB_SERVER - assumed 'DB_SERVER' in C:\xampp\www\inc\database.inc on line 276[15-Nov-2016 19:03:44 America/Denver] PHP Stack trace:[15-Nov-2016 19:03:44 America/Denver] PHP 1. {main}() C:\xampp\cgi-bin\ajax.php:0[15-Nov-2016 19:03:44 America/Denver] PHP 2. db->__construct() C:\xampp\cgi-bin\ajax.php:36[15-Nov-2016 19:03:47 America/Denver] PHP Warning: mysqli::mysqli(): php_network_getaddresses: getaddrinfo failed: No such host is known. in C:\xampp\www\inc\database.inc on line 276[15-Nov-2016 19:03:47 America/Denver] PHP Stack trace:[15-Nov-2016 19:03:47 America/Denver] PHP 1. {main}() C:\xampp\cgi-bin\ajax.php:0[15-Nov-2016 19:03:47 America/Denver] PHP 2. db->__construct() C:\xampp\cgi-bin\ajax.php:36[15-Nov-2016 19:03:47 America/Denver] PHP 3. mysqli->mysqli() C:\xampp\www\inc\database.inc:276[15-Nov-2016 19:03:47 America/Denver] PHP Warning: mysqli::mysqli(): (HY000/2002): php_network_getaddresses: getaddrinfo failed: No such host is known. in C:\xampp\www\inc\database.inc on line 276[15-Nov-2016 19:03:47 America/Denver] PHP Stack trace:[15-Nov-2016 19:03:47 America/Denver] PHP 1. {main}() C:\xampp\cgi-bin\ajax.php:0[15-Nov-2016 19:03:47 America/Denver] PHP 2. db->__construct() C:\xampp\cgi-bin\ajax.php:36[15-Nov-2016 19:03:47 America/Denver] PHP 3. mysqli->mysqli() C:\xampp\www\inc\database.inc:276[15-Nov-2016 19:03:47 America/Denver] php_network_getaddresses: getaddrinfo failed: No such host is known.
Listing 4-16 - Original httpd.conf cgi-bin Directory Configuration
Listing 4-17 - Corrected httpd.c onf cgi-bin Directory Configuration
4.1.4 Errors Displayed When Adding and Editing Categories (Bug #23)When adding or editing a category on index.php, the interface provides a multiselect box to choose
the scan source data types that are expected for that category of targets (e.g., Nessus, SCC,
eChecklists, etc.). This selection is then used for tracking completion of those scan sources. When the
page is first loaded, however, none of these scan sources are selected, so a 'foreach' loop that loops
over them to associate them to the category was producing errors since the _REQUEST object
'scan_sources' key was initially unset.
Listing 4-18 - Undefined Index Errors in index.php
This was fixed by simply wrapping the 'foreach' loop in a test to ensure the key is set:
<Directory "C:/xampp/cgi-bin"> AllowOverride All Options None Require all granted</Directory>
<Directory "C:/xampp/cgi-bin"> AllowOverride All Options +ExecCGI Require all granted</Directory>
[20-Nov-2016 16:04:00 America/Denver] PHP Notice: Undefined index: scan_sources in C:\xampp\www\ste\index.php on line 48[20-Nov-2016 16:04:00 America/Denver] PHP Stack trace:[20-Nov-2016 16:04:00 America/Denver] PHP 1. {main}() C:\xampp\www\ste\index.php:0[20-Nov-2016 16:04:00 America/Denver] PHP Warning: Invalid argument supplied for foreach() in C:\xampp\www\ste\index.php on line 48[20-Nov-2016 16:04:00 America/Denver] PHP Stack trace:[20-Nov-2016 16:04:00 America/Denver] PHP 1. {main}() C:\xampp\www\ste\index.php:0
Listing 4-19 - Testing for the scan_sources Request Parameter
4.1.5 Undefined Offset Notices When Importing CPEs (Bug #54)Using the parse_cpe.php script to import the CPE dictionary resulted in undefined offset errors. This
was because the parse_cpe.php script was reading CPE string fields into an array and attempting to
operate on the array parts without first verifying that the array parts were not empty. As such, blank
fields in the CPE resulted in attempts to operate on null array elements, causing a large number of
errors on import. The array with empty elements (printed via var_dump) and the error can both be
seen in Listing 4-11.
if(isset($_REQUEST['scan_sources'])){ foreach($_REQUEST['scan_sources'] as $idx => $id) { $ste_cat->add_Source($db->get_Sources($id)); }}
Listing 4-20 - Undefined Offset Warnings in parse_cpe.php
To fix this, we added a check to verify if the array element is set prior to operating on the element
using:
Listing 4-21 - Testing for Presence of CPE Array Elements
4.1.6 Issues Importing Nessus Plugins (Bugs #262 and #270)
c:\xampp\www\exec>php parse_cpe.php -f ..\tmp\official-cpe-dictionary_v2.3.xml[ C:\xampp\www\exec\parse_cpe.php:119:$attrs ]array(1) {'name' =>string(72) "cpe:/a:%240.99_kindle_books_project:%240.99_kindle_books:6::~~~android~~"}[ C:\xampp\www\exec\parse_cpe.php:151:$this->short_string ]string(28) "%240.99_kindle_books_project"[ C:\xampp\www\exec\parse_cpe.php:199:$this->cpe_arr ]array(7) {[0] =>string(3) "cpe"[1] =>string(2) "/a"[2] =>string(28) "%240.99_kindle_books_project"[3] =>string(20) "%240.99_kindle_books"[4] =>string(1) "6"[5] =>string(0) ""[6] =>string(12) "~~~android~~"}[ C:\xampp\www\exec\parse_cpe.php:203:$this->short_string ]string(51) "%240.99_kindle_books_project %240.99 kindle books 6"Notice: Undefined offset: 1 in C:\xampp\www\exec\parse_cpe.php on line 216Call Stack:0.0005 163896 1. {main}() C:\xampp\www\exec\parse_cpe.php:02.0731 3378752 2. basic_xml_parser->parse() C:\xampp\www\exec\parse_cpe.php:3232.5205 3391520 3. xml_parse() C:\xampp\www\inc\xml_parser.inc:5222.5207 3392560 4. basic_xml_parser->startElement() C:\xampp\www\inc\xml_parser.inc:5222.5208 3393032 5. call_user_func:{C:\xampp\www\inc\xml_parser.inc:476}() C:\xampp\www\inc\xml_parser.inc:4762.5208 3393464 6. cpe_parser->cpe_list_cpe_item() C:\xampp\www\inc\xml_parser.inc:476
if (isset($this->cpe_arr[n]){…}
When attempting to import Nessus plugins with the --nasl argument to update_db.php, the following
errors were reported for each disabled plugin:
Listing 4-22 - Errors Deleting Disabled Plugins
Running update_db.php yields countless errors of the following sort:
To debug, we used the PHP getcwd function to verify that the working directory was the document
root, whereas the files to be deleted were in tmp/nessus_plugins/. This was fixed by passing absolute
paths to the unlink command.
While debugging #262, we additionally observed that plugins that were being skipped were not
actually disabled and opened Bug #270. As shown in the following output:
XX.XX% Plugin file C:/xampp/www/tmp/nessus_plugins/xtux_server.nasl is DISABLEDXX.XX%Warning: unlink(xtux_server.nasl): No such file or directory in C:\xampp\www\exec\update_db.php on line 251Call Stack:0.0000 194456 1. {main}() C:\xampp\www\exec\update_db.php:02472.9520 13934816 2. unlink() C:\xampp\www\exec\update_db.php:251
Listing 4-23 - Plugins Incorrectly Identified as Disabled
The first plugin processed (CSCdx17916.nasl) is properly disabled in the NASL; however, the second
plugin processed (CSCeb56909.nasl) is not.
Listing 4-24 - Searching NASL Files for the "@DEPRECATED@" Keyword
The first plugin processed (CSCdx17916.nasl) is properly disabled in the NASL; however, the second
plugin processed (CSCeb56909.nasl) is not.
The keyword used to indicate deprecated plugins is “@DEPRECATED@”. The regular expression
used to match the deprecated plugins was case insensitive and did not include the “@” character
before and after the capitalized “DEPRECATED” keyword, therefore it was incorrectly matching
instances of the string “Deprecated” in vulnerability comments as well as the NASL function
deprecated_version. The corrected regular expression is:
Started at 15:21:18Found 86679 NASL filesStarted at 2017-06-26 15:21:18 Plugin file C:/xampp/www/tmp/nessus_plugins/CSCdx17916.nasl is DISABLED
0.00%Warning: unlink(CSCdx17916.nasl): No such file or directory in C:\xampp\www\exec\update_db.php on line 263
Call Stack: 0.0182 195152 1. {main}() C:\xampp\www\exec\update_db.php:0 349.6504 14348464 2. unlink(???) C:\xampp\www\exec\update_db.php:263
Plugin file C:/xampp/www/tmp/nessus_plugins/CSCeb56909.nasl is DISABLED
0.00%Warning: unlink(CSCeb56909.nasl): No such file or directory in C:\xampp\www\exec\update_db.php on line 263
Call Stack: 0.0182 195152 1. {main}() C:\xampp\www\exec\update_db.php:0
2199. 2198.0755 14390936 2. unlink(???) C:\xampp\www\exec\update_db.php:263
c:\xampp\www\tmp\nessus_plugins>find /N "DEPRECATED" CSC*.nasl---------- CSCDX17916.NASL[4]# @DEPRECATED@
---------- CSCEB56909.NASL
---------- CSCED40933.NASL…
Listing 4-25 - Corrected Regular Expression to Identify Disabled Plugins
4.1.7 Repeating Port Banners in the Database from Nessus Imports (Bug #280)When parsing Nessus scan results, the parser captures interface IP addresses, host names, and
open ports, as well as the banner associated with each port (the banner field of the targets.pps_list
table). The script appended the banner text to the existing text in the field if the port already exists in
the database. The problem observed was that a.) multiple plugins may report the same port and
banner and b.) multiple scan files sometimes scan the same interface. After several plugins or scan
files identifying the same port were imported, the field became quite large, and was causing database
timeouts when the script attempted to save the port to the database.
The fix was to add a check to ensure that the banner text from the plugin was not already in the
database field before appending it. A similar check was also added to the notes field. The following is
the revised update_TCP_Port function with comments. Similar updates were also made to the
update_UDP_Port function.
Listing 4-26 - Corrected update_TCP_Port Function
4.1.8 Exported .ckl Files Won’t Import into STIG Viewer (Bug #319)
“/Disabled on ([\d\/]+)|@DEPRECATED@/i"
public function update_TCP_Port($tcp_port) { // Get pointer to current port by reference so updates persist upon return $cur_port = &$this->tcp_ports[$tcp_port->get_Port()]; // Get current and new port banner and notes to determine if we need to update. $cur_banner = $cur_port->get_Banner(); $cur_notes = $cur_port->get_Notes();
$new_banner = $tcp_port->get_Banner(); $new_notes = $tcp_port->get_Notes();
// Only update banner if new banner is not already in current banner if (strpos($cur_banner, $new_banner) === false){ $cur_port->set_Banner($tcp_port->get_Banner()); } // Only update notes if new notes is not already in current notes if (strpos($cur_notes, $new_notes) === false){ $cur_port->append_Notes($tcp_port->get_Notes()); } }
After an update to the DISA STIG Viewer tool, the .ckl file format exported from Sagacity no longer
imported into STIG Viewer. The latest version was found to validate a UUID before importing. The uuid
parameter was being set to an empty string by export-ckl.php, which had worked in the past but now
did not. After testing, it was found that a pseudo-random UUID is sufficient to pass the validator.
To fix, we created a file uuid.inc in <wwwroot>/classes/ and added a UUID class found in the PHP
documentation forums. UUID.inc was then included in export-ckl.php. Then, on line 140 in export-
ckl.php we changed the array that creates the the uuid parameter to use a value generated by the
UUID class as shown in Listing 4-18.
Listing 4-27 - Populating the UUID Value
4.2Details of Significant Debugging WorkThis section details significant issues we identified and debugged to the point of isolating the
problems but stopping short of fixing the issue. Typically, this was due to the need to discuss the
proper approach with the development team or due to the need for additional insight into the design
and intended software operation, or otherwise because the fix needs additional testing or development
deferred to future releases.
4.2.1 Trigger Permissions Issues (Bug #17)Upon completion of Bug #14 (Section 4.1.2), importing Nessus data still did not work properly. The
script appeared to complete and did not report any runtime errors; however, the information was not
present in the database as shown in Figure 4-2 by the absence of hosts on the Operations screen.
20: include 'uuid.inc';...140: array(141: 'SID_NAME' => 'uuid',142: 'SID_DATA' => UUID::v4()143: ),…
Figure 4-6 – Failure to Load Sample Data
This issue was accompanied by an error visible in the php_error_log repeated multiple times:
Listing 4-28 - SQL Syntax Errors in PHP Error Log
Searching the code for the SQL string ‘AND `pdi_id`’ yields a SQL string being built dynamically in
the db object’s get_Finding method in the database.inc file.
We also observed that the application sql_log, which logs all SQL statements, shows the following:
Listing 4-29 - Invalid Statement in SQL Log
Note that the `tgt_id` parameter is not assigned to anything in the WHERE clause. This indicates
that the target id is null for some reason. Also we see the “AND `pdi_id`” string referenced in the PHP
error log.
The call to get_Finding in parse_nessus.php is in the callback function that gets called when
processing the NessusClientData_v2\Report\ReportHost\ReportItem closing tag in the Nessus xml. The
call is as follows:
Listing 4-30 - get_Finding Function Call in parse_nessus.php
So the method is passed the parser’s ‘tgt’ variable, which is a target object. To determine why it is
null, we must determine where the parser assigns the ‘tgt’ variable. Using var_dump on $this->tgt, I
noticed that the id attribute is ‘false,’ which is indicative of an error setting the ID value. So I searched
for calls to the $this->tgt->set_ID method, and found it is assigned in this line of code, belonging to
[13-Nov-2016 17:08:34 America/Denver] You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'AND `pdi_id` = 0' at line 1
2016-11-13T17:34:29-0700 - NOTICE - SELECT `id`,`tgt_id`,`pdi_id`,`scan_id`,`findings_status_id` as 'findings_status',`notes`,`change_id`,`orig_src`,`finding_itr`,`cat` FROM `scans`.`findings` WHERE `tgt_id`= AND `pdi_id` = 0
$finding = $this->db->get_Finding($this->tgt, $this->plugin->result->stig);
the callback function that gets called when processing the NessusClientData_v2\Report\ReportHost\
HostProperties closing tag:
Listing 4-31 - set_ID Function Call
Using var_dump to print the SQL string that gets executed by the save_Target method, I captured it
and attempted to run the SQL interactively, which yielded this SQL error:
Listing 4-32 - MySQL Permission Denied Error
Examining the target table’s triggers, the following BEFORE INSERT trigger was defined:
Listing 4-33 - Trigger Definer Error
The problem was that the DEFINER was set to `web`@`%`, and the TRIGGER privilege for the
`web`@`%` user were not granted. Changing the DEFINER to `web`@`localhost` solved the bug, and
importing the Nessus file now appears to work as intended, as shown by the newly populated list of
targets in the target table:
$ret = $this->tgt->set_ID($this->db->save_Target("insert", $this->tgt));
TRIGGER command denied to user 'web'@'%' for table 'target'
CREATE DEFINER=`web`@`%` TRIGGER `targets`.`target_BEFORE_INSERT` BEFORE INSERT ON `target` FOR EACH ROWBEGIN
SELECT MAX(`id`) INTO @newid FROM `targets`.`target`; SET NEW.`id` = COALESCE(@newid + 1, 1);END
Listing 4-34 - Target Data Correctly Populated
4.2.2 Undefined Offset Error When Exporting (Bug #20)Sagacity provides a feature to organize hosts in the target network into arbitrary categories (e.g., a
user might have a “Windows Workstations” category and a “Windows Servers” category to group
similar systems for analysis). Until they are categorized, it places hosts into the “Unassigned”
category. When clicking the Export button for the Unassigned category, the error in Figure 4-3 was
shown.
MariaDB [(none)]> select id,os_id,ste_id,os_string from targets.target;+------+-------+--------+----------------------------+| id | os_id | ste_id | os_string |+------+-------+--------+----------------------------+| 1 | 76373 | 1 | Red Hat Enterprise Linux 5 || 2 | 76373 | 1 | Red Hat Enterprise Linux 5 || 3 | 76373 | 1 | Red Hat Enterprise Linux 5 || 4 | 76373 | 1 | Red Hat Enterprise Linux 5 || 5 | 76373 | 1 | Red Hat Enterprise Linux 5 || 6 | 76373 | 1 | Red Hat Enterprise Linux 5 || 7 | 76373 | 1 | Red Hat Enterprise Linux 5 || 8 | 76373 | 1 | Red Hat Enterprise Linux 5 || 9 | 76373 | 1 | Red Hat Enterprise Linux 5 || 10 | 76373 | 1 | Red Hat Enterprise Linux 5 || 11 | 76373 | 1 | Red Hat Enterprise Linux 5 || 12 | 76373 | 1 | Red Hat Enterprise Linux 5 || 13 | 76373 | 1 | Red Hat Enterprise Linux 5 || 14 | 76373 | 1 | Red Hat Enterprise Linux 5 || 15 | 76373 | 1 | Red Hat Enterprise Linux 5 || 16 | 76373 | 1 | Red Hat Enterprise Linux 5 || 17 | 76373 | 1 | Red Hat Enterprise Linux 5 || 18 | 76373 | 1 | Red Hat Enterprise Linux 5 || 19 | 76373 | 1 | Red Hat Enterprise Linux 5 || 20 | 76373 | 1 | Red Hat Enterprise Linux 5 || 21 | 76373 | 1 | Red Hat Enterprise Linux 5 || 22 | 76373 | 1 | Red Hat Enterprise Linux 5 || 23 | 76373 | 1 | Red Hat Enterprise Linux 5 |+------+-------+--------+----------------------------+23 rows in set (0.00 sec)
Figure 4-7 - Undefined Offsest Error When Exporting
Line 43 of export.php at this time was:
Listing 4-35 - The Source of the Undefined Offset Error in export.php
Debugging the $_REQUEST object with print_r, we get the following:
Listing 4-36 - The _REQUEST Object Variable at Runtime
We observed that the ‘cat’ value passed to get_Category is 0. The SQL generated by
get_Category(0) is:
Listing 4-37 - SQL Statement Generated by get_Category(0)
This query, however, returns no results because there are not ste_cat records with id of 0. The
returned array is then null, which explains the Undefined offset error since there are no offsets to a null
array.
By default, newly imported targets are not assigned to a category, i.e., the target table cat_id field is
null. The link on the Operations page to the “Unassigned” category was passing the value of “0” to
the request object, as shown by the argument “0” to the open_echecklist function below:
$cat = $db->get_Category($_REQUEST['cat'])[0];
[26-Nov-2016 00:10:38 America/Denver] [_REQUEST]:Array( [ste] => 1 [cat] => 0)
SELECT `id`,`ste_id`,`name`,`analysts` FROM `targets`.`ste_cat` WHERE `id`=0;
Listing 4-38 - JavaScript to Initiate the Export
This initiates the cascade of calls all the way to the query where the script fails. We confirmed the
bug is isolated to the unassigned targets by assigning some of the hosts to a new category. As seen
below, the data on the category summary page now populates with host data and the export function
completes.
On speaking with the project team, the decision was made to disable the hyperlink to this category
since targets would not have an associated category number until they were sorted.
4.2.3 Large Text Strings in Inserts Cause Timeouts (Bug #281)Some Nessus plugins generate large quantities of text data which the parse_nessus.php script
attempts to insert into the database. These inserts were observed to cause the database connection to
timeout before the insert could complete. The problem was isolated by truncating insert, update, and
replace statements at 1024 bytes and observing that the same inserts now succeed. This was
accomplished by modifying the _escape function of the database class, which is used to escape data
being passed to the database. Listing 4-31 shows the updated function.
<a href="javascript:void(0);" onclick="open_echecklist(0);">Unassigned</a>
Listing 4-39 - Truncating Large Text Inserts, Updates, and Replaces
A fix was proposed to create a configurable variable (MAX_VALUE_SIZE) which would allow users to
specify a maximum size for unbounded Nessus plugin data. The lead developer also proposed reducing
the number of records inserted at a time. Adjudication is still pending and further testing is needed to
determine the impact of these solutions.
4.2.4 Multiple Discrepancies Between Sagacity and STIG Viewer .ckl Files (Bug #320)Once Bug #319 was fixed, it was quickly observed that the formats of the XML .ckl files generated
by the STIG Viewer and Sagacity were significantly different. Figure 4-4 shows the export from
Sagacity, and Figure 4-5 shows the output from STIG Viewer for the same STIG checklist and SCC data.
Significant differences can be easily observed.
public function _escape($val) { if (is_null($val)) { return 'NULL'; } elseif (is_numeric($val) || is_string($val)) { if (strtolower($val) == 'now()') { return $val; } elseif (preg_match("/\.`\w+`/", $val)) { return $val; } // If it's inserting/updating/replacing values based on query type, // truncate the field length to prevent DB timeouts if (in_array($this->query_type, array( 'insert', 'extended_insert', 'update', 'extended_update', 'replace', 'extended_replace', )) && strlen($val)>=1024) { $val = substr($val,0,1004) . "**OUTPUT TRUNCATED*"; } return "'{$this->c->real_escape_string($val)}'"; } elseif (is_a($val, 'DateTime')) { return "'{$val->format(MYSQL_DT_FORMAT)}'"; } elseif (is_bool($val)) { return $val ? "'1'" : "'0'"; } else { print_r($val); }
throw(new Exception("Unknown datatype to escape in SQL string {$this->sql} " . gettype($val), E_ERROR)); }
Figure 4-8 - The STIG Viewer .ckl File After Import
Figure 4-9 - The Sagacity .ckl File After Import
There are four unique types of inconsistencies identified through manually comparing each finding
in the two files and adjudicating the reasons for differences. The first is that the STIG viewer rejects
SCAP data that has a rule number revision mismatch (i.e., it will not import results for SV-25018r2_rule
if the checklist uses SV-25018r3_rule. The second was due to a bug in the SCC parser which did not
reset the finding status variable if a check was determined not to exist in the version of the STIG being
processed (i.e. the rule had been removed from the STIG in the current version of the checklist).
Third, the procedure to create the XML that is used to populate the Check Content and Fix Text tabs
was simply omitted from the export_ckl.php script. Finally, the database field that was being used to
populate the Rule Name was actually the stig.stig_id field, which is a numeric identifier rather than the
STIG's GroupTitle tag content as used by the STIG Viewer.
The first issue was determined to be working as intended. Since a goal of Sagacity is to reduce
manual checks, the decision was to allow matching regardless of rule revision number because
revisions are often merely cosmetic. The second was fixed since it could lead to corrupted data by
changing finding status. The third was fixed to ensure all required tags were present in the XML. The
fourth was changed to use the pdi_catalog.short_title field, which is a textual short description of the
STIG. This is still inconsistent with the GroupTitle tag used by the STIG Viewer, however the GroupTitle
tag is not currently being imported by Sagacity, so the fix for this was deferred to future releases.
4.3Commented FilesIn making the updates we attempted to comment all sections of code that we debugged or modified
as we came to them to increase the maintainability of the project. In addition, significant portions of
the following files were commented.
parse_cpe.php: Comments added throughout the entire file
update_db.php: Commented the NASL parsing routine
parse_stig.php: Comments added throughout the entire file.
Additionally, the portions of code provided for the implementation of RMF controls as described in
Section 3 were all commented in their entirety.
5 Future Work5.1Bug Fixes and Design Changes
As a project under active development, there are a significant number of outstanding bugs that
have been deferred to future releases. We opened several of these in the course of this project effort
and they are summarized in Appendix A. We highlight several of the more significant ones here.
Refactoring is recommended for more intuitive and consistent object names. For example, ‘STIG’ is
used in various places either to refer to individual STIG settings or the STIG checklists themselves.
Also, variations of ‘category’ are used in different contexts to mean either categories of systems,
category (severity) of STIG findings. Overloading these terms can be confusing when reading the code
as it can be unclear as to which context variable names and database fields refer.
Refactoring of the db object is also highly recommended. The class currently extends over 10,000
lines of code and is used by essentially every parser and object for all interactions with the database.
This has been causing issues since bug fixes for methods of the db class often manifest unanticipated
bugs in other areas of code, which is significant since the class must be frequently updated – having
been modified in 59 of 208 commits since the projects’ inception or 28%.
We observed that many functions accept arrays or primitives as datatypes rather than
encapsulating them in objects. This makes type checking challenging and inhibits IDE Content
Assistance. Additionally, it leads to a propensity to attempt to pass unexpected data types to the
functions.
Finally, there is a significant issue with the implementation of CPE checking. Sagacity attempts to
identify software using direct lookups of CPE strings, which is not how the CPE specification was
intended to be used [21]. As such, sections of code that attempt to identify software often behave
unpredictably, leading to false positives and false negatives. Additionally, these sections of code
become convoluted in an attempt to account for different conditions encountered. Sagacity would
benefit from a full implementation of the CPE specification.
5.2Feature AdditionsFull RMF compliance reporting is obviously a major objective for the project. To implement this,
there are several things that must be done. First, a parser will need to be written to ingest the DISA
CCI list, which provides the most comprehensive NIST 800-53 control data available. Second, the
CNSSI 1253 control baselines must be imported. Of course, the underlying database schema must be
updated to hold the data and user interface elements must be updated to include the reporting
controls and configuration options. Finally, there will need to be some business logic to implement
control baseline generation and risk determination.
Several features could be added to enhance the quality of reports as well. Compliance metrics
would be useful for an executive summary. Another often-requested capability is comparison of
results between assessments to show regressions, improvements, and trending in compliance.
Furthermore, the ability to parse the NIST CVE database (in lieu of the MITRE CVE database currently
used) would provide a great deal more data about identified CVEs. This includes CVSS scores,
vulnerable software CPEs, and vulnerable configuration CPEs [22]. This information could prove useful
in reporting as well.
Currently, Sagacity does not provide any capability to export data other than to eChecklist or .ckl
flat files. A useful feature would be to export and import an entire ST&E. This is especially useful
because they are not delivering releases as patches, so new releases frequently require dropping and
rebuilding the database, which means data must be re-imported one file at a time if the version is
upgraded.
Finally, since a current objective is to recruit new developers, it would be useful to publish a
developers’ guide to explain the software architecture, database architecture, code conventions, and
other such useful information to familiarize contributors with the application.
6 Lessons Learned and Conclusion6.1Lessons Learned
Our primary reason for undertaking the project was to learn the architecture and code base of
Sagacity sufficiently to be able to apply the tool to real-world data and isolate and fix problems as they
arise. This goal has been achieved and put into practice with two different real-world data sets in the
scope of this project.
The project has been an exercise in the synthesis of many years of education, training, and work
experience across numerous domains. This includes software design, project management,
programming, IDEs, database design and query language, cybersecurity governance, and the
vulnerability assessment process. Specific tools, technologies, and techniques learned include:
Installing and configuring development XAMPP and LAMP environments
PHP development, SQL, and, to a lesser extent, JavaScript
The PHPOffice PHPSpreadsheet Library
The PHP XML Parser Library
Installing and configuring Eclipse PHP Development Tools and configuring the XDebug
debugger for use with PHP CLI and Web Applications
Eclipse Debugger, including limitations on variable size, breakpoints, conditional breakpoints,
and watchlist expressions
Using SourceForge and the SVN protocol to checkout and commit to community open source
projects, including powerful SourceForge features such as bug tracking, commit browsing, and
diffs, and file history
Using WinMerge to merge code changes
MySQL Workbench design tools, code editor, and reverse engineering
The CPE Specification
Chrome Developer Tools
Numerous components of the Sagacity application as well as its architecture and database
structure/relationships
Multiple security data file formats including MITRE and NIST CVEs, CPEs, Nessus report files,
SCC XCCDF files, and DISA STIGs
6.2ConclusionThe public release of Sagacity 1.3 was November 1, 2017 due in large part to the contributions of
this project [24]. The critical RMF capability and increased stability provided as a result of this project
will increase the software’s chances for adoption and hopefully serve to encourage others to contribute
as well. Additionally, the proficiency we’ve gained in supporting and developing for Sagacity by virtue
of executing this project enables us to support and extend Sagacity as future bugs are identified and
to help to add features to the software in future releases.
7 References[1] Defense Information Systems Agency. 2014. DoDI 8510.01, Risk Management Framework for
DoD Information Technology. DISA. http://www.dtic.mil/whs/directives/corres/pdf/851001_2014.pdf.
[2] National Institute of Standards and Technology. 2013. NIST SP 800-53 Revision 4, Security and
Privacy Controls for Federal Information Systems and Organizations. NIST.
http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-53r4.pdf.
[3] Committee on National Security Systems. 2014. CNSSI No. 1253, Security Categorization and
Control Selection for National Security Systems. CNSS.
http://www.dss.mil/documents/CNSSI_No1253.pdf.
[4] Defense Information Systems Agency. Information Assurance Support Environment. DISA.
http://iase.disa.mil/, Accessed November 14, 2017.
[5] Committee on National Security Systems. 2014. CNSSI No. 1253, Security Categorization and
Control Selection for National Security Systems, D-1-D-35. CNSS.
http://www.dss.mil/documents/CNSSI_No1253.pdf.
[6] Defense Information Systems Agency. 2011. Control Correlation Identifier Specification (Draft)
Version 1, Release 2. DISA.
[7] Defense Information Systems Agency. 2017. Windows 7 Security Technical Implementation
Guide Version 1, Release 27. DISA.
[8] CyberPerspectives, LLC. http://www.cyberperspectives.com/. Accessed November 14, 2017.
[9] US Department of Health & Human Services. Health Information Privacy. Accessed November 14,
2017.
[10] Payment Card Industry Security Standards Council. PCI Compliance Guide.
https://www.pcisecuritystandards.org/, Accessed November 14, 2017.
[11] Tenable Network Security. Tenable Network Security Products Overview.
https://www.tenable.com/products. Accessed November 14, 2017.
[12] Lyon, Gordon. 2016. Nmap Reference Guide. Insecure.Com LLC. https://nmap.org/book/man.
[13] SPAWAR Systems Center Atlantic. Security Content Automation Protocol Compliance Checker.
http://www.public.navy.mil/spawar/Atlantic/Technology/Pages/SCAP.aspx. Accessed November 14,
2017
[14] Tenable Network Security, Inc. 2017. Nessus 6.11 User Guide. 282-297.
https://docs.tenable.com/nessus/6_11/Content/Resources/PDF/Nessus_6_11.pdf
[15] Tenable Network Security. Tenable Network Security Products Overview.
https://www.tenable.com/products. Accessed November 14, 2017.
[16] SPAWAR Systems Center Atlantic. Security Content Automation Protocol Compliance Checker.
http://www.public.navy.mil/spawar/Atlantic/Technology/Pages/SCAP.aspx. Accessed November 14,
2017.
[17] Defense Information Systems Agency. 2017. STIG Viewer 2.x User Guide Version 1, Release 3.
DISA.
[18] Vulnerator Project Home Page. SoftwareForge.mil. https://software.forge.mil/sf/go/proj1208,
Accessed March 8, 2016.
[19] Defense Information Systems Agency. DISA - Enterprise Mission Assurance Support Service
(eMASS). https://www.disa.mil/Cybersecurity/Assessments-and-Inspections/EMASS. Accessed
November 14, 2017.
[20] Apache HTTP Server Project. Apache Tutorial: Dynamic Content with CGI.
http://httpd.apache.org/docs/current/howto/cgi.html, Accessed November 14, 2017.
[21] Mary Parmelee, Harold Booth, David Waltermire, Karen Scarfone. 2011. NISTIR 7696, Common
Platform Enumeration: Name Matching Specification Version 2.3, 8-19. NIST. DOI:
http://doi.org/10.6028/NIST.IR.7696.
[22] National Institute of Standards and Technologies. National Vulnerability Database - Data Feeds.
https://nvd.nist.gov/vuln/data-feeds. Accessed November 14, 2017.
8 Appendix A – Table of Bugs ReportedBug No.
Title Status Date Created
LOE Rev Fixed
9 parse_nessus.php bombs when importing closed 10/23/2016 Opened 12Summary:Parse_nessus.php failed with "Fatal error: Cannot access protected property tcp_ports::$port in C:\xampp\www\classes\interfaces.inc on line 274". Problem was due to the interface class making direct calls to private variables of the port class.
14 Overwriting config files closed 11/10/2016 Fixed 27Summary:Sagacity ships with its own configuration files for Apache, MariaDB, and PHP. These configuration files are copied over the default files upon Sagacity installation by the 'install.bat' script. The my.ini file (used to configure MariaDB) that was included with Sagacity included a 'skip-federated' directive which had been supported in MySQL but is not supported in MariaDB. Therefore, when the XAMPP project migrated from MySQL to MariaDB, MariaDB would fail to start after Sagacity installation due to the invalid directive. The solution was to remove the 'skip-federated' directive from the my.ini file supplied with Sagacity.
Additionally, this bug included discussion with the team regarding whether it was a bad practice to overwrite users' configuration files on the chance that it might be a multi-application server. This was mitigated by editing the install script to back up the existing config files (renamed to '*.old') before copying the Sagacity configuration files.
15 Fix erroneous references to $db variable in parse_nessus.php closed 11/11/2016 Fixed 16Summary:Parsing Nessus results using parse_nessus.php failed with the a fatal error: c:\xampp\www\exec>php parse_nessus.php -s 1 -f ..\tmp\nessus_report_Linux_Vulnerability_Scan.nessus -d \xampp\wwwNotice: Undefined variable: db in C:\xampp\www\exec\parse_nessus.php on line 269Call Stack:0.0042 690312 1. {main}() C:\xampp\www\exec\parse_nessus.php:01.0967 3753024 2. scan_xml_parser->parse() C:\xampp\www\exec\parse_nessus.php:16331.4158 3767176 3. xml_parse() C:\xampp\www\inc\xml_parser.inc:3551.4300 3772368 4. scan_xml_parser->stopElement() C:\xampp\www\inc\xml_parser.inc:3551.4306 3772824 5. call_user_func:{C:\xampp\www\inc\xml_parser.inc:309}() C:\xampp\www\inc\xml_parser.inc:3091.4306 3775352 6. nessus_parser->NessusClientData_v2_Report_ReportHost_HostProperties_end() C:\xampp\www\inc\xml_parser.inc:309Fatal error: Call to a member function get_Regex_Array() on null in C:\xampp\www\exec\parse_nessus.php on line 269An examination of the code revealed the failing line 269 as follows: $os_regex = $db->get_Regex_Array("os");This and one subsequent line both referred to a non-existent $db variable. The second was line 279: $os = $db->get_Software($os_arr->get_CPE());The proper way to reference it would be to use $this->db->get_Regex_Array() and $this->db->get_Software().
16 Comments for parse_cpe.php closed 11/11/2016 Commented 17
Bug No.
Title Status Date Created
LOE Rev Fixed
Summary:Provided comments for parse_cpe.php
17 Fix DEFINER on target_BEFORE_INSERT Trigger closed 11/14/2016 Debugged 21Summary:"Permission is denied when doing operations that insert into 'targets' table due to the '%' wildcard in the target_BEFORE_INSERT trigger. Need to change:CREATE DEFINER=web@% TRIGGER targets.target_BEFORE_INSERT BEFORE INSERT ON target to:CREATE DEFINER=web@localhost TRIGGER targets.target_BEFORE_INSERT BEFORE INSERT ON target in db_schema.xml."
19 Targets not populating on ST&E Operations screen closed 11/14/2016 Fixed 32Summary:The httpd.conf file included unquoted ScriptAlias directory and was missing +ExecCGI from the directory options.
20 Export.php dies when attempting to export the "Unassigned" category closed 11/14/2016 Debugged 29Summary:Attempting to export spreadsheets from the "Unassigned" category hyperlink generated a PHP error because the hyperlink passess the category value "0" to the database query, and no hosts are ever assigned to category "0". Decision was made to disable the hyperlink to this category since targets would not have an associated category number until they were sorted.
21 E_DEBUG Undefined closed 11/20/2016 Fixed 24Summary:"Helper.inc errors with ""Notice: Use of undefined constant E_DEBUG - assumed 'E_DEBUG' in C:\xampp\www\inc\helper.inc on line 1124""E_DEBUG is not a predefined constant per http://php.net/manual/en/errorfunc.constants.php.I fixed this by adding: ""include_once 'error.inc';"" to helper.inc. Not sure if there is a better fix."
22 Typo in install.php closed 11/20/2016 Fixed 30Summary:Install.php errors with "Notice: Undefined variable: key in C:\xampp\www\install.php on line 345" due to comparison operator (==) where assignment operator (=) should be.Line reads:if(($key == array_search("sample_data.sql", $sql_files)) !== false) {should be:if(($key = array_search("sample_data.sql", $sql_files)) !== false) {
Bug No.
Title Status Date Created
LOE Rev Fixed
23 Error displayed in index.php if scan_sources is not set closed 11/20/2016 Fixed 28Summary:When adding or editing a category on index.php, the interface provides the ability for the user to use a multiselect box to identify the scan source data that is expected for that category of targets, which can then be used for tracking completion of those scan sources. When the page is first loaded, however, none of these scan sources are selected, so a 'foreach' loop that loops over them to associate them to the category was providing errors since the _REQUEST object 'scan_sources' key was initially unset. This was fixed by wrapping the 'foreach' loop in a test to ensure the key is set:
if(isset($_REQUEST['scan_sources'])){ foreach($_REQUEST['scan_sources'] as $idx => $id) { $ste_cat->add_Source($db->get_Sources($id)); }}
24 Non-intuitive and inconsistent path strings closed 11/27/2016 Opened 32Summary:Upon installation, the install.php form accepted configuration paths to files that were in non-standard Windows path formats (e.g., omitting the leading drive letter) and were inconsistent regarding the use of full paths or relative paths, and therefore the code that processed these configuration settings.
25 Remove "ENGINE=MyISAM" in install.php and update.php closed 12/8/2016 Opened 43Summary:Install and update scripts were setting the database engine to MyISAM in an attempt to enable full text indexing on the PDI Catalog. However, MyISAM does not support key constraints, which is dangerous, and furthermore does not support reverese engineering with MySQL Workbench, which is antithetical to the objective of recruiting new developers.
27 Need to LoadFile pthreadVC2.dll in httpd.conf wont-fix 12/9/2016 Rejected N/ASummary:Sagacity had been using the pthread library to track the PID of exec jobs. When the lead developer ported pthread calls to the native php getmypid() function, he removed the httpd.conf line to load the .dll file, but neglected to remove the line that loads the module. Rather than add the LoadFile line, the proper fix was to remove the LoadModule line.
28 Change Document Properties for Excel exports closed 12/10/2016 Opened 32Summary:The document properties that were generated for exported files were hard-coded strings and were not appropriate for general public use.
Bug No.
Title Status Date Created
LOE Rev Fixed
Recommended that the strings be added to the configuration variables upon install.
29 Multiple Copyright and SMC Remnants closed 12/10/2016 Opened 34Summary:Multiple files were still using an old and incorrect copyright notice and referenced the Space and Missile Systems agency which, being a government organization, cannot hold copyright.
52 Install.php redirect to home page after completion closed 2/4/2017 Opened UTDSummary:After completing database installation, the install.php script re-posts to itself. It should instead load the http://localhost/ste/index.php. Unable to determine which release fixed this issue.
54 Undefined offset Notices in parse_cpe.php closed 2/5/2017 Fixed 38Summary:The parse_cpe.php script was reading CPE string fields into an array and attempting to operate on the array parts without first verifying that the array parts were not empty. As such, blank fields in the CPE resulted in attempts to operate on null array elements, causing a large number of errors on import. Fix was to check if the array element is set prior to taking action.
94 Clean up if (false) instances accepted
3/14/2017 Opened N/A
Summary:The developers had been using the dead code if (false) { $arg = new objType() } as a hack to get Content Assist in Eclipse. The proper way of doing this is either to use type hints in the method declaration or to use PHPDoc for local variables. This is also indicative of a need for refactoring for increased abstraction in the many instances where arrays are passed as function arguments.
132 Import .nasl files from Nessus data directory open 4/9/2017 Opened N/ASummary:If Nessus installed on the same system as Sagacity, the script for parsing the .nasl files for plugin information should be read directly from the %ProgramData%\Tenable\Nessus\nessus\plugins directory. This saves substantial time copying the 90,000 plugins to the /tmp/nessus_plugins directory.
255 Remove cgi-bin directory copy from install.bat closed 6/14/2017 Fixed 173Summary:Developer removed all cgi-bin directory contents, however did not remove the installation script commands to copy the non-existent directory, leading to "No such file or directory" errors on install. Fix was to remove the copy lines in the install script.
256 Fix include of Excel library in import.inc closed 6/14/2017 Opened 174Summary:The PHPExcel library was deprecated and replaced with PHPSpreadsheet, however the includes for the PHPExcel library were generating
Bug No.
Title Status Date Created
LOE Rev Fixed
errors on any pages that attempted to load it. Fix was to remove include statement.
257 Site Management "Country" drop-down should populate all countries open 6/14/2017 Opened N/ASummary:Since Sagacity is going to be released publicly, the "Country" option should include all countries of the world. Currenly it only has a handful of locations.
258 ST&E Management "Eval Start Date" calendar widget should allow arbitrary scrollback
open 6/14/2017 Opened N/A
Summary:The calendar control for selecting an ST&E start date and end date fields only allows the user to scroll back one month. It should allow scrolling back to an arbitrary date. 259 update_db should look in www/tmp for default file names if --po is
specified.open 6/14/2017 Opened N/A
Summary:If update_db.php is used with the --do option (download only), it downloads the cve and cpe database files and renames them, appending the current date. Therefore, when parsing the files on an offline system using the --po option (parse only) the script looks for files with a date appended to the name. However, a user should also be able to manually download and transfer the files as an option if they choose. If files have been manually downloaded and transferred to an offline system, the files will not have been renamed with the date appended to the end and also will not have been transferred to the tmp/cpe and tmp/cve directories, which is where the script looks for them. The script should be modified to allow copying these files into /tmp and the script should look for the default file names official-cpe-dictionary_v2.3.xml.zip and allitems.xml, respectively.
260 parse_stig.php hangs on U_VVoIP_V3R10_Manual-xccdf.xml closed 6/14/2017 Opened 172Summary:Special characters in the STIG xml were preventing the parser from working properly. Fix was to use str_replace to replace the special characters with there ASCII equivalents.
261 Scan import interfaces aren't working open 6/14/2017 Opened N/ASummary:This problem proved to be a result of cached JavaScript, and a force refresh fixed the issue. However, the ticket is remaining open to see if there is anything we can do to reduce the cache lifespan of the JavaScript files.
262 Update_db.php on nasl files gives multiple "No such file or directory" errors closed 6/14/2017 Fixed 173Summary:Calls to the unlink() function to delete .nasl files following processing were failing because the script sets the working directory the document root directory, and a relative path was being used. The fix was to create an absolute path to the files to use wherever needed.
263 parse_nessus.php dies b/c no parse_config.ini file open 6/14/2017 Opened N/A
Bug No.
Title Status Date Created
LOE Rev Fixed
Summary:The parse_nessus.php script requires a file called "parse_config.ini" to specify its operating parameters. When Nessus scans are imported from the GUI, it works because the scripts create the file from the selected options, and then delete the file upon completion. However, at the command line, the parse_nessus.php script fails if the user does not first manually create the ini file. Normally a command-line script would be passed options via arguments rather than an ini file, and furthermore the documentation and help text give no clues that the file is required.
264 Unable to expand categories on ST&E Operations page closed 6/14/2017 Opened N/ASummary:Details unknown.
265 add_scan interface "Delete File" link deletes file wont-fix 6/16/2017 Opened N/ASummary:In testing, it was observed that the interface for uploading files provides a button labeled "Delete File" that deletes the file on the disk as opposed to deleting the . This was thought to be a risk as it could
266 Sourceforge Project Readme can't display PDF wont-fix 6/20/2017 Opened N/ASummary:The SourceForge SVN code tree page is attempting to load the README.pdf document in the "Read Me" area beneath the code tree. Proposed renaming the file and creating a README.txt file that could properly load, but proposal was rejected. 267 CCIs are broke closed 6/20/2017 Opened 177Summary:The values for CCI numbers were being corrupted upon ingestion into the database. This was fixed by changing the datatype in the database from integer to string and modifying the parser accordingly.
268 database.inc: get_Software() bombs when passed a software object pending 6/21/2017 Fixed N/ASummary:The database class get_Software() function attempts to access an array index to the $software_In[0] variable before verifying to check that it is an array. This is a problem because the function argument $software_In is a "mixed" data type and can be a software object rather than an array. This was fixed by adding an is_array() check before executing the array code. Fix has not yet been committed.
269 eChecklist assignment not working in bulk edit closed 6/21/2017 Opened 195Summary:The "Bulk Edit" feature enables editing properties of multiple hosts in a category at a time. The feature was not working when attempting to add or remove checklists to targets.
270 update_db incorrectly identifying .nasl files as disabled closed 6/26/2017 Fixed 173Summary:The Nessus .nasl file parser was incorrectly identifying plugins as disabled and therefore skipping them. The regex that was used to match
Bug No.
Title Status Date Created
LOE Rev Fixed
the "deprecated" string was inadvertently matching the word "deprecated" in the descriptions of vulnerabilities as well as the deprecated_version() function call, generating false positives. To remediate this, the regex was replaced with a more specific string "@DEPRECATED@" to more exactly match the way Tenable .nasl files identify deprecated plugins.
273 Need to declare Sagacity_Error object in parse_stig.php closed 7/12/2017 Opened 178Summary:The $log variable was being referenced before it had been instantiated. The references to the $log Sagacity_Error object were function calls that should have been static function calls to the Sagacity_Error class rather than the $log object.
274 Remove or relocate IAControls tag logic in parse_stig.php closed 7/13/2017 Opened 178Summary:In r176, the code to parse the IAControls tag was moved to a line after the variable holding the IAControls tag had been reduced to a substring which no longer contained the IAControls tag. Code reducing the substring was removed.
280 Eliminate duplicate port notes in interfaces.inc closed 7/25/2017 Fixed 181Summary:When parsing Nessus scan results, the parser captures interface IP addresses, host names, and open ports, as well as the banner associated with each port (the banner field of the targets.pps_list table). The script appended the banner text to the existing text in the field if the port already exists in the database. The problem observed was that a.) multiple plugins may report the same port and banner and b.) multiple scan files sometimes scan the same interface. After several plugins or scan files identifying the same port were imported, the field became quite large, and was causing database timeouts when the script attempted to save the port to the database. The fix was to add a check to ensure that the banner text from the plugin was not already in the database field before appending it.
281 Large text strings in inserts causes timeouts open 7/25/2017 Debugged N/ASummary:Some Nessus plugins generate large quantities of data which the parse_nessus.php script attempts to insert into the database. These inserts were observed to cause the database connection to timeout before the insert could complete. The problem was isolated by truncating insert, update, and replace statements at 1024 bytes and observing that the same inserts now succeed. A fix was proposed to create a configurable variable (MAX_VALUE_SIZE) which would allow users to specify a maximum size for unbounded Nessus plugin data. The lead developer also proposed reducing the number of records inserted at a time. Adjudication is still pending and futher testing is needed to determine the impact of these solutions.
282 start_time overwritten when batch importing SCC xccdf results open 7/26/2017 Opened N/ASummary:If you observe the scan.scans table while importing a large volume of results, the start_time field timestamp is being overwritten upon job completion by the time that the script was first queued. Here is a detailed description of the process to reproduce:
Bug No.
Title Status Date Created
LOE Rev Fixed
1.) Copy a large number of SCC XCCDF results to /tmp, and click "Import" on the Results page.2.) SELECT * FROM scans.scans; 3.) Observe when scripts are queued, the "start_time" field is populated with the start time representing when the script was queued. 4.) Once a file is kicked off, status changes to "RUNNING" start_time is correctly updated with the time the given result is actually kicked off once it is dequeued5.) Upon completion, the start_time will be replaced by the original queue time.
283 perc_comp not updated when parsing eChecklist open 7/27/2017 Opened N/ASummary:Eventually it was determined that this symptom is indicative of a hung eChecklist import due to incorrect column order. However, this is indicative of a need for a way of monitoring job status, gracefully catching hung import jobs and terminating them, perhaps a timeout if no other means can be devised. Furthermore, there is an issue that if the job fails once, the same file cannot be imported again even after terminating and deleting it. Root cause still unknown.
286 Multiple issues importing eChecklists wont-fix 8/14/2017 Debugged N/ASummary:eChecklists were not importing and the jobs would hang. It was determined that the eChecklists had been corrupted by users and did not match the file format expectations of the parser. The file format was fixed but Bug #313 was opened to track the need for input validation, and Bug #310 was opened to have the "Flatten eChecklists" option enabled by default on installation. The reason for this is that if "Flatten eChecklists" is disabled, the two rollup columns are hidden by default, causing users to inadvertently insert additional host columns after them. This causes problems for the parser since the columns are out of order.
304 Cache metrics on Ops page open 9/20/2017 Opened N/ASummary:The "Not a Finding/Open/Not Applicable" finding counts displayed on the ST&E Operations Page take way too long to populate with large data sets, which means every time users navigate away and back, there is a long wait for the query to complete and page to load. The data should be cached after the first query or loaded via AJAX after the query completes instead.
305 eChecklist fields that are used by the import functionality should be locked open 9/20/2017 Opened N/ASummary:This is related to the need for input validation (bug #313). The input validation issues could be mitigated by locking on export any fields in eChecklists that are used to make associations upon import. At a minimum this would include host names, column headers, and STIG/VMS IDs. We should also look at possibly doing this for all fields that we don't expect the user to need to edit (i.e., populated directly from the STIGs - check content, title, cat, control number, etc. and Excel formulas).
306 Distinct fields in eChecklists for automated vs. manual notes open 9/20/2017 Opened N/ASummary:Currently, there is only a single notes field for each STIG finding, and it is appended with notes from vulnerability scanners and also the source for each finding, which is de-normalized since sources and notes should be per-finding and per-host. Re-import of the eChecklist
Bug No.
Title Status Date Created
LOE Rev Fixed
leads to replicating this information yet again, making the notes field very polluted. At a minimum, we should have automated data generated by Nessus, SCC, or nmap stored separately from manually generated data written by analysts during testing. Ideally, it would be completely normalized, however, the eChecklist format does not currently support this.
307 eChecklist export puts classification in "Date(s) Tested field" open 9/20/2017 Opened N/ASummary:The eChecklist export script is placing the classification in the wrong field.
308 Application Server SRG incorrectly identified as Application Development STIG
open 9/20/2017 Opened N/A
Summary:Symptom is apparent on the eChecklist tab as well as the Operations screen checklist icon. Problem appears to be a greedy regex issue.
309 Truncated Short Titles in Symantec Endpoint Protection 12.1 Managed Client AV STIG
closed 9/20/2017 Opened N/A
Summary:STIG item short titles were being truncated for one specific checklist. Unable to reproduce.
310 Set "Flatten eChecklists" to enabled by default. closed 9/20/2017 Opened 195Summary:When "Flatten eChecklist" option is disabled, the two rollup columns in the eChecklists are hidden, leading people to insert columns for additional hosts after the rollup columns, which prevents the script from importing properly. Fix was to enable it by default until better input validation is implemented.
312 Exported Win 7 eChecklist generates Excel error open 9/22/2017 Opened N/ASummary:"Opening an exported Win 7 eChecklist causes the error 'We found a problem with some content in “Win_7_-_x64_SP1-eChecklist-1.xlsx’. Do you want us to try to recover as much as we can? If you trust the source of this workbook, click Yes.'If you click 'Yes', then it displays 'Removed Records: Formula from /xl/worksheets/sheetX.xml part' repeated multiple times with different sheet numbers."
313 Input validation for eChecklist import open 9/22/2017 Opened N/ASummary:If columns in eChecklists are not in a specific order, importing of eChecklists fails and import jobs hang. Input validation is needed and the code needs to be re-written such that known columns are accounted for and the remaining columns are identified as hosts, regardless of the order in which they appear.
Bug No.
Title Status Date Created
LOE Rev Fixed
314 "Delete Scan" popup needs clearer warning text open 9/22/2017 Opened N/ASummary:The JavaScript alert that pops up when deleting scans prompts "Do you want to also delete associated targets?" What is unclear is that this action permanently deletes all targets and findings from every target contained within the deleted scan - even if some of that data comes from other scans. I suggested adding the following line to the prompt:"WARNING: This will delete all targets in this scan and all associated data even if it was imported from another scan. This action is irreversible."Also this dialog should be "Yes/No" instead of "OK/Cancel"
315 Compress Help File screenshots open 9/22/2017 Opened N/ASummary:Exporting the Help to PDF is 15+ MB, which is too big to easily pass around (email attachment, downloads from the website, etc.). Compressing the screenshots would probably go a long way toward reducing this.
319 Exported .ckl files aren't importing into STIG Viewer closed 10/17/2017 Fixed 199Summary:.Ckl files exported from Sagacity don't import into STIG Viewer. STIG Viewer apparently checks for a valid UUID before importing, whereas the uuid parameter is currently set to an empty string by export-ckl.php. A pseudo-random UUID is sufficient to pass the validator.To fix, I added the attached uuid.inc to <wwwroot>/classes/ and included it in export-ckl.php. Then on line 140 in export-ckl.php changed the array instantiation for the uuid parameter to be generated by the UUID class.
320 Multiple discrepancies between Sagacity and STIG Viewer .ckl output. open 10/17/2017 Debugged 203Summary:Exported .ckl files were inconsistent with the STIG Viewer .ckl files after importing the same source data. There were four reasons identified for this. The first is that the STIG viewer rejects SCAP data that has a rule number revision mismatch (i.e., it will not import results for SV-25018r2_rule if the checklist uses SV-25018r3_rule. Since the goal of Sagacity was to reduce manual checks, the decision was to allow matching regardless of rule revision number because revisions are often merely cosmetic. The second was due to a bug in the SCC parser which did not reset the finding status variable if a check was determined not to exist in the version of the STIG being processed (i.e. the rule had been removed from the STIG in the current version of the checklist). Third, the procedure to create the XML that is used to populate the Check Content and Fix Text tabs was simply omitted from the export_ckl.php script. Finally, the database field that was being used to
Bug No.
Title Status Date Created
LOE Rev Fixed
populate the Rule Name was actually the stig.stig_id field, which is a numeric identifier rather than the STIG's GroupTitle tag content as used by the STIG Viewer. The first issue was determined not to need fixing. The second was fixed since it could lead to corrupted data by changing finding status. The third was fixed to ensure all required tags were present in the XML. The fourth was changed to use the pdi_catalog.short_title field, which is a textual short description of the STIG. This is still inconsistent with the GroupTitle tag used by the STIG Viewer, however the GroupTitle tag is not currently being imported by Sagacity, so the fix for this was deferred to future releases.