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:

  1. 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
  2. The tree of execution that lead to the target process - binary information about each
  3. A list of processes that have written to the target process/binary, details about each
  4. 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.