Cb Reporting released
Posted on August 8, 2017
We are pleased to announce the release of an updated Cb Reporting script.
https://github.com/carbonblack/cb-reporting/blob/master/incident_report.py
The incident report script is an example python program that demonstrates how to build a basic incident report using the Cb API bindings for python.
The incident report uses the Cb API to trace information about the lifetime of a process of interest:
- Target process event information: module loads, cross process interactions, file modifications, registry modifications (windows) as well as intelligence feed hits, and the hosts/paths on which the target was seen
- The tree of execution that lead to the target process - binary information about each
- A list of processes that have written to the target process/binary, details about each
- The child processes of the target process + corresponding binaries
The only dependencies are on the Jinja2 templating engine module for python (2.6+), and the Cb API bindings for python V1.3.1+ - available via pip/pypi
At a high level, Incident_report.py defines a IncidentReportGenerator class that manipulates the Cb API bindings and exposes a generate_report(guid) method for generating reports as HTML.
Report generation begins by using the Cb API to retrieve Process information from the server for the Target GUID.
#build the report directory path and lookup the target process by GUID
output_directory = os.path.join("reports", guid)
process = self.cb.select(Process, guid)
Most of the information needed for this report can be accessed directly from the ProcessModel object.
Walking the child-process tree for this target process is as easy as iterating over the children generator (Here used to write the icons for each child)
# walk children of the target process and write icons
for child in process.children:
write_iconfile(output_directory, child.process)
… similar syntax is used to quickly walk the tree of execution up to its top:
# walk execution tree/parents and write icons
for parent in process.parents:
write_iconfile(output_directory, parent)
A query with a where-clause is used to find the writers - or processes which have written to the target process’s binary.
# find processes that have written to the target process's binary
writers = []
writers.extend(self.cb.select(Process).where("filemod:{} and hostname:{} and process_md5:*"
.format(process.path, process.hostname)))
The report uses the facets associated with the process to capture what hosts and paths the target has been seen on.
# build a list of hostname/filepath facets for this process-binary-by-md5
facets = self.cb.select(Process).where("process_md5:" + process.process_md5).facets()
filepaths = [{"filepath": e['name'], "percentage": e['ratio']} for e in facets.get('path_full')]
hostnames = [{'hostname': e['name'], 'percentage': e['ratio']} for e in facets.get('hostname')]
A list of intelligence feed hits is calculated on the fly:
# process alliance threat intelligence feed hits + write icons for feeds
feed_hits = []
for feed_name in process.tags:
# A Process has fields like "alliance_score_tor,alliance_data_tor" for each
alliance_score_n = "alliance_score_{}".format(feed_name)
alliance_data_n = "alliance_data_{}".format(feed_name)
feed = self.cb.select(Feed).where("name:" + feed_name).first()
write_file(output_directory, feed.name, ".png", feed.icon_small)
feed_hits.append({"feed": feed.name,
"url": feed.provider_url,
"score": getattr(process, alliance_score_n),
"data": getattr(process, alliance_data_n)})
After using the Cb API to query information about the process of interest, the aggregated metadata is used to generate a report from the provided incident report template:
def output_report_from_template(cbserver, output_directory, process, writers=None,
feed_hits=None, hostnames=None, filepaths=None):
template_vars = {"process": process,
"sensor": process.sensor,
"writers": writers if writers else [],
"children": [child for child in process.children],
"parents": [p for p in process.parents],
"modloads": [modload for modload in process.modloads],
"netconns": [nc for nc in process.netconns],
"regmods": [rm for rm in process.regmods],
"crossprocs": [cp for cp in process.crossprocs],
"binary": process.binary,
"feed_hits": feed_hits if feed_hits else [],
"time_generated": datetime.now(),
"cbserver": cbserver,
"hostnames": hostnames if hostnames else [],
"filepaths": filepaths if filepaths else []}
j2_env = Environment(loader=FileSystemLoader("."),
trim_blocks=True)
report_htmlfile = file(os.path.join(output_directory, "index.html"), 'wb')
report_htmlfile.write(j2_env.get_template("incident_report.j2").render(template_vars).encode("UTF-8"))
The file incident_report.j2 is a jinja2 template that outlines a generic incident report format in html. Here is a snippet showing how the section listing child processes is built. The existing template can be easily modified to change the format and contents of the report.
-
How to run
$ ./incident-report --guid <process-guid>
-
Example
$ ./incident-report --guid <process-guid>
-
How to build from source
-
clone cb-reporting.git
$ git clone https://github.com/carbonblack/cb-reporting.git
-
Install all needed requirements:
$ sudo pip install -r requirements.txt
-
Run the script with specified parameters
$ python incident_report.py -guid <process-guid>
A report will be generated in ./reports/<process-guid>/index.html
for the specified process GUID.