cbapi: Carbon Black API for Python¶
Release v1.3.1.
cbapi provides a straightforward interface to the Cb Protection and Response REST APIs. This library provides a Pythonic layer to access the raw power of the REST APIs of both products, making it trivial to do the easy stuff and handling all of the “sharp corners” behind the scenes for you. Take a look:
>>> from cbapi.response import CbResponseAPI, Process, Binary, Sensor
>>> #
>>> # Create our CbAPI object
>>> #
>>> c = CbResponseAPI()
>>> #
>>> # take the first process that ran notepad.exe, download the binary and read the first two bytes
>>> #
>>> c.select(Process).where('process_name:notepad.exe').first().binary.file.read(2)
'MZ'
>>> #
>>> # if you want a specific ID, you can put it straight into the .select() call:
>>> #
>>> binary = c.select(Binary, "24DA05ADE2A978E199875DA0D859E7EB")
>>> #
>>> # select all sensors that have ran notepad
>>> #
>>> sensors = set()
>>> for proc in c.select(Process).where('process_name:evil.exe'):
... sensors.add(proc.sensor)
>>> #
>>> # iterate over all sensors and isolate
>>> #
>>> for s in sensors:
... s.network_isolation_enabled = True
... s.save()
If you’re more a Cb Protection fellow, then you’re in luck as well:
>>> from cbapi.protection.models import FileInstance
>>> from cbapi.protection import CbProtectionAPI
>>> #
>>> # Create our Cb Protection API object
>>> #
>>> p = CbProtectionAPI()
>>> #
>>> # Select the first file instance
>>> #
>>> fi = p.select(FileInstance).first()
>>> #
>>> # print that computer's hostname. This automatically "joins" with the Computer API object.
>>> #
>>> fi.computer.name
u'DOMAIN\\MYHOSTNAME'
>>> #
>>> # change the policy ID
>>> #
>>> fi.computer.policyId = 3
>>> fi.computer.save()
As of version 1.2, cbapi now provides support for Cb Defense too!
>>> from cbapi.defense.models import Device
>>> from cbapi.defense import CbDefenseAPI
>>> #
>>> # Create our Cb Defense API object
>>> #
>>> p = CbDefenseAPI()
>>> #
>>> # Select any devices that have the hostname WIN-IA9NQ1GN8OI and an internal IP address of 192.168.215.150
>>> #
>>> devices = c.select(Device).where('hostNameExact:WIN-IA9NQ1GN8OI').and_("ipAddress:192.168.215.150").first()
>>> #
>>> # Change those devices' policy into the Windows_Restrictive_Workstation policy.
>>> #
>>> for dev in devices:
>>> dev.policyName = "Restrictive_Windows_Workstation"
>>> dev.save()
Major Features¶
- Enhanced Live Response API
- The new cbapi now provides a robust interface to the Cb Response Live Response capability. Easily create Live Response sessions, initiate commands on remote hosts, and pull down data as necessary to make your Incident Response process much more efficient and automated.
- Consistent API for Cb Response, Protection and Defense platforms
- We now support Cb Response, Protection and Defense users in the same API layer. Even better, the object model is the same for both; if you know one API you can easily transition to the other. cbapi hides all the differences between the three REST APIs behind a single, consistent Python-like interface.
- Enhanced Performance
- cbapi now provides a built in caching layer to reduce the query load on the Carbon Black server. This is especially useful when taking advantage of cbapi’s new “joining” features. You can transparently access, for example, the binary associated with a given process in Cb Response. Since many processes may be associated with the same binary, it does not make sense to repeatedly request the same binary information from the server over and over again. Therefore cbapi now caches this information to avoid unnecessary requests.
- Reduce Complexity
- cbapi now provides a friendly - dare I say “fun” - interface to the data. This greatly improves developer productivity and lowers the bar to entry.
- Python 3 and Python 2 compatible
- Use all the new features and modules available in Python 3 with cbapi. This module is compatible with Python versions 2.6.6 and above, 2.7.x, 3.4.x, and 3.5.x.
- Better support for multiple Cb servers
- cbapi now introduces the concept of Credential Profiles; named collections of URL, API keys, and optional proxy configuration for connecting to any number of Cb Protection, Defense, or Response servers.
API Credentials¶
The new cbapi as of version 0.9.0 enforces the use of credential files.
In order to perform any queries via the API, you will need to get the API token for your Cb user. See the documentation on the Developer Network website on how to acquire the API token for Cb Response, Cb Protection, or Cb Defense.
Once you acquire your API token, place it in one of the default credentials file locations:
/etc/carbonblack/credentials.response
(credentials.protection
for Cb Protection, orcredentials.defense
for Cb Defense)~/.carbonblack/credentials.response
- (current working directory)
.carbonblack/credentials.response
Credentials found in a later path will overwrite earlier ones.
The credentials are stored in INI format. The name of each credential profile is enclosed in square brackets, followed by key-value pairs providing the necessary credential information:
[default]
url=https://localhost
token=abcdef0123456789abcdef
ssl_verify=False
[prod]
url=https://cbserver.prod.corp.com
token=aaaaaa
ssl_verify=True
[otheruser]
url=https://localhost
token=bbbbbb
ssl_verify=False
The possible options for each credential profile are:
- url: The base URL of the Cb server. This should include the protocol (https) and the hostname, and nothing else.
- token: The API token for the user ID. More than one credential profile can be specified for a given server, with different tokens for each.
- ssl_verify: True or False; controls whether the SSL/TLS certificate presented by the server is validated against the local trusted CA store.
- proxy: A proxy specification that will be used when connecting to the Cb server. The format is:
http://myusername:mypassword@proxy.company.com:8001/
where the hostname of the proxy isproxy.company.com
, port 8001, and using username/passwordmyusername
andmypassword
respectively. - ignore_system_proxy: If you have a system-wide proxy specified, setting this to True will force cbapi to bypass the proxy and directly connect to the Cb server.
Future versions of cbapi will also provide the ability to “pin” the TLS certificate so as to provide certificate verification on self-signed or internal CA signed certificates.
Backwards & Forwards Compatibility¶
The previous versions (0.8.x and earlier) of cbapi and bit9Api are now deprecated and will no longer receive updates. However, existing scripts will work without change as cbapi includes both in its legacy package. The legacy package is imported by default and placed in the top level cbapi namespace when the cbapi module is imported on a Python 2.x interpreter. Therefore, scripts that expect to import cbapi.CbApi will continue to work exactly as they had previously.
Since the old API was not compatible with Python 3, the legacy package is not importable in Python 3.x and therefore legacy scripts cannot run under Python 3.
Once cbapi 1.0.0 is released, the old cbapi.legacy.CbApi
will be deprecated and removed entirely no earlier
than January 2017.
New scripts should use the cbapi.response.rest_api.CbResponseAPI
(for Cb Response), cbapi.protection.rest_api.CbProtectionAPI
(for Cb Protection), or cbapi.defense.rest_api.CbDefenseAPI
API entry points.
The API is frozen as of version 1.0; afterward, any changes in the 1.x version branch will be additions/bug fixes only. Breaking changes to the API will increment the major version number (2.x).
User Guide¶
Let’s get started with cbapi. Once you’ve mastered the concepts here, then you can always hop over to the API Documentation (below) for detailed information on the objects and methods exposed by cbapi.
Installation¶
Before installing cbapi, make sure that you have access to a working Cb Response or Cb Protection server. The server can be either on-premise or in the cloud. Cb Response clusters are also supported. Once you have access to a working can use the standard Python packaging tools to install cbapi on your local machine.
Feel free to follow along with this document or watch the Development Environment Setup video on the Developer Network website.
If you already have Python installed, you can skip right down to “Using Pip”.
Installing Python¶
Obviously the first thing you’ll need to do is install Python on your workstation or server. For best compatibility, install the latest version of Python 2.7 (as of this writing, that is version 2.7.11). Linux and Mac OS X systems will most likely have Python installed; it will have to be installed on Windows separately.
Note that cbapi is compatible with both Python 2.7 and Python 3.x. If you already have Python 3 installed on your system, you’re good to go!
If you believe you have Python installed already, run the following two commands at a command prompt:
$ python --version
Python 2.7.10
$ pip --version
pip 7.1.2 from /Users/jgarman/Desktop/Reno/homebrew/lib/python2.7/site-packages (python 2.7)
If “python” reports back a version of 2.6.x, 2.7.x, or 3.x.x, you’re in luck. If “pip” is not found, don’t worry, we’ll install that shortly.
If you’re on Windows, and Python is not installed yet, download the latest Python installer from the python.org website. The direct link for the Python 2.7.11 installer for Windows 64-bit platforms is https://www.python.org/ftp/python/2.7.11/python-2.7.11.amd64.msi.
Install the MSI for “all users” and in the configuration options ensure that the “Add python.exe to Path” option is installed (you will have to scroll to the end of the customization options to find this).
If for some reason you do not have pip installed, follow the instructions at this handy guide.
Using Pip¶
Once Python and Pip are installed, then open a command prompt and type:
$ pip install cbapi
This will download and install the latest version of cbapi from the Python PyPI packaging server.
Getting the Source Code¶
cbapi is actively developed on GitHub and the code is available from the carbonblack GitHub repository. The version of cbapi on GitHub will reflect the latest development version of cbapi and may contain bugs not present in the currently released version. On the other hand, it may contain exactly the goodies you’re looking for (or you’d like to contribute back; we are happy to accept pull requests!)
To clone the latest version of the cbapi repository from GitHub:
$ git clone https://github.com/carbonblack/cbapi-python.git
Once you have a copy of the source, you can install it in “development” mode into your Python site-packages:
$ cd cbapi-python
$ python setup.py develop
This will link the version of cbapi-python you checked out into your Python site-packages directory. Any changes you make to the checked out version of cbapi will be reflected in your local Python installation. This is a good choice if you are thinking of changing or developing on cbapi itself.
Getting Started¶
First, let’s make sure that your API authentication tokens have been imported into cbapi. Once that’s done, then read on for the key concepts that will explain how to interact with Carbon Black APIs via cbapi.
Feel free to follow along with this document or watch the Development Environment Setup video on the Developer Network website.
API Authentication¶
Cb Response and Cb Protection use a per-user API secret token to authenticate requests via the API. The API token confers the same permissions and authorization as the user it is associated with, so protect the API token with the same care as a password.
To learn how to obtain the API token for a user, see the Developer Network website: there you will find instructions for obtaining an API token for Cb Response and Cb Protection.
Once you have the API token, cbapi helps keep your credentials secret by enforcing the use of a credential file. To encourage sharing of scripts across the community while at the same time protecting the security of our customers, cbapi strongly discourages embedding credentials in individual scripts. Instead, you can place credentials for several Cb Response or Cb Protection servers inside the API credential file and select which “profile” you would like to use at runtime.
To create the initial credential file, a simple-to-use script is provided. Just run the cbapi-response
or
cbapi-protection
script with the configure
argument. On Mac OS X and Linux:
$ cbapi-response configure
Alternatively, if you’re using Windows (change c:\python27
if Python is installed in a different directory):
C:\> python c:\python27\scripts\cbapi-response configure
This configuration script will walk you through entering your API credentials and will save them to your current user’s
credential file location, which is located in the .carbonblack
directory in your user’s home directory.
Your First Query¶
Now that you have cbapi installed and configured, let’s run a simple query to make sure everything is functional:
$ python
Python 2.7.10 (default, Jun 22 2015, 12:25:23)
[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from cbapi.response import *
>>> c = CbResponseAPI()
>>> print(c.select(Process).first().cmdline)
C:\Windows\system32\services.exe
That’s it! Now on to the next step, learning the concepts behind cbapi.
Concepts¶
There are a few critical concepts that will make understanding and using the cbapi easier. These concepts are explained below, and also covered in a slide deck presented at the Carbon Black regional User Exchanges in 2016. You can see the slide deck here.
At a high level, the cbapi tries to represent data in Cb Response or Cb Protection as Python objects. If you’ve worked with SQL Object-relational Mapping (ORM) frameworks before, then this structure may seem familiar – cbapi was designed to operate much like an ORM such as SQLAlchemy or Ruby’s ActiveRecord. If you haven’t worked with one of these libraries, don’t worry! The concepts will become clear after a little practice.
Model Objects¶
Everything in cbapi is represented in terms of “Model Objects”. A Model Object in cbapi represents a single instance
of a specific type of data in Cb Response or Protection. For example, a process document from Cb Response (as seen
on an Analyze Process page in the Web UI) is represented as a cbapi.response.models.Process
Model Object.
Similarly, a file instance in Cb Protection is represented as a cbapi.protection.models.FileInstance
Model Object.
Once you have an instance of a Model Object, you can access all of the data contained within as Python properties.
For example, if you have a Process Model Object named proc
and you want to print its command line (which is stored
in the cmdline
property), you would write the code:
>>> print(proc.cmdline)
This would automatically retrieve the cmdline
attribute of the process and print it out to your screen.
The data in Cb Response and Protection may change rapidly, and so a comprehensive list of valid properties is difficult to keep up-to-date. Therefore, if you are curious what properties are available on a specific Model Object, you can print that Model Object to the screen. It will dump all of the available properties and their current values. For example:
>>> print(binary)
cbapi.response.models.Binary:
-> available via web UI at https://cbserver/#binary/08D1631FAF39538A133D94585644D5A8
host_count : 1
digsig_result : Signed
observed_filename : [u'c:\\windows\\syswow64\\appwiz.cpl']
product_version : 6.2.9200.16384
legal_copyright : © Microsoft Corporation. All rights reserved.
digsig_sign_time : 2012-07-26T08:56:00Z
orig_mod_len : 669696
is_executable_image : False
is_64bit : False
digsig_publisher : Microsoft Corporation
...
In this example, host_count
, orig_mod_len
, etc. are all properties available on this Binary Model Object.
Sometimes, properties are not available on every instance of a Model Object. In this case, you can use the .get()
method to retrieve the property, and return a default value if the property does not exist on the Model Object:
>>> print(binary.get("product_version", "<unknown>"))
6.2.9200.16384
In summary, Model Objects contain all the data associated with a specific type of API call. In this example, the
cbapi.response.models.Binary
Model Object reflects all the data available via the
/api/v1/binary
API route on a Cb Response server.
Joining Model Objects¶
Many times, there are relationships between different Model Objects. To make navigating these relationships easy,
cbapi provides special properties to “join” Model Objects together. For example, a cbapi.response.models.Process
Model Object can reference the cbapi.response.models.Sensor
or cbapi.response.models.Binary
associated with this Process.
In this case, special “join” properties are provided for you. When you use one of these properties, cbapi will automatically retrieve the associated Model Object, if necessary.
This capability may sound like a performance killer, causing many unnecessary API calls in order to gather this data. However, cbapi has extensive Model Object caching built-in, so multiple requests for the same data will be eliminated and an API request is only made if the cache does not already contain the requested data.
For example, to print the name of the Sensor Group assigned to the Sensor that ran a specific Process:
>>> print(proc.sensor.group.name)
Default Group
Behind the scenes, this makes at most two API calls: one to obtain the Sensor associated with the Process, then another to obtain the Sensor Group that Sensor is part of. If either the Sensor or Sensor Group are already present in cbapi’s internal cache, the respective API call is not made and the data is returned directly from the internal cache.
In summary, some Model Objects have special “join” properties that provide easy access to related Model Objects. A list of “join” properties is included as part of the documentation for each Model Object.
Queries¶
Now that we’ve covered how to get data out of a specific Model Object, we now need to learn how to obtain Model Objects in the first place! To do this, we have to create and execute a Query. cbapi Queries use the same query syntax accepted by Cb Response or Protection’s APIs, and add a few little helpful features along the way.
To create a query in cbapi, use the .select()
method on the CbResponseAPI or CbProtectionAPI object. Pass the
Model Object type as a parameter to the .select()
call and optionally add filtering criteria with .where()
clauses.
Let’s start with a simple query for Cb Response:
>>> from cbapi.response import *
>>> cb = CbResponseAPI()
>>> cb.select(Process).where("process_name:cmd.exe")
<cbapi.response.rest_api.Query object at 0x1068815d0>
This returns a prepared Query object with the query string process_name:cmd.exe
.
Note that at this point no API calls have been made. The cbapi Query objects are “lazy” in that they are only
evaluated when you use them. If you create a Query object but never attempt to retrieve any results, no API call is
ever made (I suppose that answers the age-old question; if a Query object is created, but nobody uses it, it does
not make a sound, after all).
What can we do with a Query? The first thing we can do is compose new Queries. Most Query types in cbapi can be
“composed”; that is, you can create a new query from more than one query string. This can be useful if you have a
“base” query and want to add additional filtering criteria. For example, if we take the query above and add the
additional filtering criteria (filemod:*.exe or filemod:*.dll)
, we can write:
>>> base_query = cb.select(Process).where("process_name:cmd.exe")
>>> composed_query = base_query.where("(filemod:*.exe or filemod:*.dll")
Now the composed_query
is equivalent to a query of process_name:cmd.exe (filemod:*.exe or filemod:*.dll)
.
You can also add sorting criteria to a query:
>>> sorted_query = composed_query.sort("last_update asc")
Now when we execute the sorted_query
, the results will be sorted by the last server update time in ascending order.
Ok, now we’re ready to actually execute a query and retrieve the results. You can think of a Query as a kind of “infinite” Python list. Generally speaking, you can use all the familiar ways to access a Python list to access the results of a cbapi query. For example:
>>> len(base_query) # How many results were returned for the query?
3
>>> base_query[:2] # I want the first two results
[<cbapi.response.models.Process: id 00000003-0000-036c-01d2-2efd3af51186-00000001> @ https://cbserver,
<cbapi.response.models.Process: id 00000003-0000-07d4-01d2-2efcd4949dfc-00000001> @ https://cbserver]
>>> base_query[-1:] # I want the last result
[<cbapi.response.models.Process: id 00000002-0000-0f2c-01d2-2a57625ca0dd-00000001> @ https://cbserver]
>>> for proc in base_query: # Loop over all the results
>>> print(proc.cmdline)
"C:\Windows\system32\cmd.exe"
"C:\Windows\system32\cmd.exe"
"C:\Windows\system32\cmd.exe"
>>> procs = list(base_query) # Just make a list of all the results
In addition to using a Query object as an array, two helper methods are provided as common shortcuts. The first
method is .one()
. The .one()
method is useful when you know only one result should match your query; it
will throw a MoreThanOneResultError
exception if there are zero or more than one results for the query. The
second method is .first()
, which will return the first result from the result set, or None if there are no results.
Every time you access a Query object, it will perform a REST API query to the Carbon Black server. For large result sets, the results are retrieved in batches- by default, 100 results per API request on Cb Response and 1,000 results per API request on Cb Protection. The search queries themselves are not cached, but the resulting Model Objects are.
Retrieving Objects by ID¶
Every Model Object (and in fact any object addressable via the REST API) has a unique ID associated with it. If you
already have a unique ID for a given Model Object, for example, a Process GUID for Cb Response, or a Computer ID
for Cb Protection, you can ask cbapi to give you the associated Model Object for that ID by passing that ID to the
.select()
call. For example:
>>> binary = cb.select(Binary, "CA4FAFFA957C71C006B59E29DFE3EB8B")
>>> print(binary.file_desc)
PNRP Name Space Provider
Note that retrieving an object via .select()
with the ID does not automatically request the object from the server
via the API. If the Model Object is already in the local cache, the locally cached version is returned. If it is not,
a “blank” Model Object is created and is initialized only when an attempt is made to read a property. Therefore,
assuming an empty cache, in the example above, the REST API query would not happen until the second line
(the print
statement). If you want to ensure that an object exists at the time you call .select()
, add the
force_init=True
keyword parameter to the .select()
call. This will cause cbapi to force a refresh of the
object and if it does not exist, cbapi will throw a ObjectNotFoundError
exception.
Creating New Objects¶
The Cb Response and Protection REST APIs provide the ability to insert new data under certain circumstances. For
example, the Cb Response REST API allows you to insert a new banned hash into its database. Model Objects that
represent these data types can be “created” in cbapi by using the create()
method:
>>> bh = cb.create(BannedHash)
If you attempt to create a Model Object that cannot be created, you will receive a ApiError
exception.
Once a Model Object is created, it’s blank (it has no data). You will need to set the required properties and then call the
.save()
method:
>>> bh = cb.create(BannedHash)
>>> bh.text = "Banned from API"
>>> bh.md5sum = "CA4FAFFA957C71C006B59E29DFE3EB8B"
>>> bh.save()
If you don’t fill out all the properties required by the API, then you will receive an InvalidObjectError
exception with a list of the properties that are required and not currently set.
Once the .save()
method is called, the appropriate REST API call is made to create the object. The Model Object
is then updated to the current state returned by the API, which may include additional data properties initialized
by Cb Response or Protection.
Modifying Existing Objects¶
The same .save()
method can be used to modify existing Model Objects if the REST API provides that capability.
If you attempt to modify a Model Object that cannot be changed, you will receive a ApiError
exception.
For example, if you want to change the “jgarman” user’s password to “cbisawesome”:
>>> user = cb.select(User, "jgarman")
>>> user.password = "cbisawesome"
>>> user.save()
Deleting Objects¶
Simply call the .delete()
method on a Model Object to delete it (again, if you attempt to delete a Model Object
that cannot be deleted, you will receive a ApiError
exception).
Example:
>>> user = cb.select(User, "jgarman")
>>> user.delete()
Tracking Changes to Objects¶
Internally, Model Objects track all changes between when they were last refreshed from the server up until .save()
is called. If you’re interested in what properties have been changed or added, simply print
the Model Object.
You will see a display like the following:
>>> user = cb.create(User)
>>> user.username = "jgarman"
>>> user.password = "cbisawesome"
>>> user.first_name = "Jason"
>>> user.last_name = "Garman"
>>> user.teams = []
>>> user.global_admin = False
>>> print(user)
User object, bound to https://cbserver.
Partially initialized. Use .refresh() to load all attributes
-------------------------------------------------------------------------------
(+) email: jgarman@carbonblack.com
(+) first_name: Jason
(+) global_admin: False
id: None
(+) last_name: Garman
(+) password: cbisawesome
(+) teams: []
(+) username: jgarman
Here, the (+)
symbol before a property name means that the property will be added the next time that .save()
is called. Let’s call .save()
and modify one of the Model Object’s properties:
>>> user.save()
>>> user.first_name = "J"
>>> print(user)
print(user)
User object, bound to https://cbserver.
Last refreshed at Mon Nov 7 16:54:00 2016
-------------------------------------------------------------------------------
auth_token: 8b2dcf9d59b7da1a0b2b4ec50a77d8ca3d7dcb9c
email: jgarman@carbonblack.com
(*) first_name: J
global_admin: False
id: jgarman
last_name: Garman
teams: []
username: jgarman
The (*)
symbol means that a property value will be changed the next time that .save()
is called. This time,
let’s forget about our changes by calling .reset()
instead:
>>> user.reset()
>>> print(user.first_name)
Jason
Now the user Model Object has been restored to the original state as it was retrieved from the server.
Logging & Diagnostics¶
The cbapi provides extensive logging facilities to track down issues communicating with the REST API and understand potential performance bottlenecks.
Enabling Logging¶
The cbapi uses Python’s standard logging
module for logging. To enable debug logging for the cbapi, you
can do the following:
>>> import logging
>>> root = logging.getLogger()
>>> root.addHandler(logging.StreamHandler())
>>> logging.getLogger("cbapi").setLevel(logging.DEBUG)
All REST API calls, including the API endpoint, any data sent via POST or PUT, and the time it took for the call to complete:
>>> user.save()
Creating a new User object
Sending HTTP POST /api/user with {"email": "jgarman@carbonblack.com", "first_name": "Jason", "global_admin": false, "id": null, "last_name": "Garman", "password": "cbisawesome", "teams": [], "username": "jgarman"}
HTTP POST /api/user took 0.079s (response 200)
Received response: {u'result': u'success'}
HTTP GET /api/user/jgarman took 0.011s (response 200)
Cb Response API Examples¶
Now that we’ve covered the basics, let’s step through a few examples using the Cb Response API. In these examples, we will assume the following boilerplate code to enable logging and establish a connection to the “default” Cb Response server in our credential file:
>>> import logging
>>> root = logging.getLogger()
>>> root.addHandler(logging.StreamHandler())
>>> logging.getLogger("cbapi").setLevel(logging.DEBUG)
>>> from cbapi.response import *
>>> cb = CbResponseAPI()
With that boilerplate out of the way, let’s take a look at a few examples.
Download a Binary from Cb Response¶
Let’s grab a binary that Cb Response has collected from one of the endpoints. This can be useful if you want to
send this binary for further automated analysis or pull it down for manual reverse engineering. You can see a full
example with command line options in the examples directory: binary_download.py
.
Let’s step through the example:
>>> import shutil
>>> md5 = "7FB55F5A62E78AF9B58D08AAEEAEF848"
>>> binary = cb.select(Binary, md5)
>>> shutil.copyfileobj(binary.file, open(binary.original_filename, "wb"))
First, we select the binary by its primary key: the MD5 hash of the binary contents. The third line requests the
binary file data by accessing the file
property on the Binary Model Object. The file
property acts as a
read-only, Python file-like object.
In this case, we use the Python shutil
library to copy one file object to another. The
advantage of using shutil
is that the file is copied in chunks, and the full file does not have to be read
into memory before saving it to disk.
Another way to use the file
property is to call .read()
on it just like any other Python file object. The
following code will read the first two bytes from the Binary:
>> binary.file.read(2)
"MZ"
Ban a Binary¶
Now let’s take this binary and add a Banning rule for it. To do this, we create a new BannedHash Model Object:
>>> bh = cb.create(BannedHash)
>>> bh.md5hash = binary.md5
>>> bh.text = "Banned from API"
>>> bh.enabled = True
>>> bh.save()
Creating a new BannedHash object
Sending HTTP POST /api/v1/banning/blacklist with {"md5hash": "7FB55F5A62E78AF9B58D08AAEEAEF848", "text": "banned from API"}
HTTP POST /api/v1/banning/blacklist took 0.035s (response 200)
Received response: {u'result': u'success'}
HTTP GET /api/v1/banning/blacklist/7FB55F5A62E78AF9B58D08AAEEAEF848 took 0.039s (response 200)
Note that if the hash is already banned in Cb Response, then you will receive a ServerError exception with the message that the banned hash already exists.
Isolate a Sensor¶
Switching gears, let’s take a Sensor and quarantine it from the network. The Cb Response network isolation functionality allows administrators to isolate endpoints that may be actively involved in an incident, while preserving access to perform Live Response on that endpoint and collect further endpoint telemetry.
To isolate a sensor, we first need to acquire its Sensor Model Object:
>>> sensor = cb.select(Sensor).where("hostname:HOSTNAME").first()
This will select the first sensor that matches the hostname HOSTNAME
. Now we can isolate that machine:
>>> sensor.isolate()
Updating Sensor with unique ID 4
Sending HTTP PUT /api/v1/sensor/4 with {"boot_id": "0", "build_id": 5, "build_version_string": "005.002.000.61003", ...}
HTTP PUT /api/v1/sensor/4 took 0.129s (response 204)
HTTP GET /api/v1/sensor/4 took 0.050s (response 200)
...
True
The .isolate()
method will keep polling the Cb Response server until the sensor has confirmed that it is now
isolated from the network. If the sensor is offline or otherwise unreachable, this call could never return. Therefore,
there is also a timeout=
keyword parameter that can be used to set an optional timeout that, if reached,
will throw a TimeoutError
exception. The .isolate()
function returns True when the sensor is successfully
isolated.
When you’re ready to restore full network connectivity to the sensor, simply call the .unisolate()
method:
>>> sensor.unisolate()
Updating Sensor with unique ID 4
Sending HTTP PUT /api/v1/sensor/4 with {"boot_id": "0", "build_id": 5, "build_version_string": "005.002.000.61003", ...}
HTTP PUT /api/v1/sensor/4 took 0.077s (response 204)
HTTP GET /api/v1/sensor/4 took 0.020s (response 200)
...
True
Again, once the sensor is back on the network, the .unisolate()
method will return True. Just like .isolate()
,
you can optionally specify a timeout using the timeout=
keyword parameter.
Querying Processes and Events¶
Now, let’s do some queries into the Cb Response database. The true power of Cb Response is its continuous recording
and powerful query language that allows you to go back in time and track the root cause of any security incident on
your endpoints. Let’s start with a simple query to find instances of a specific behavioral IOC, where our attacker
used the built-in Windows tool net.exe
to mount an internal network share. We will iterate over all uses
of net.exe
to mount our target share, printing out the parent processes that led to the execution of the offending
command:
>>> query = cb.select(Process).where("process_name:net.exe").and_(r"cmdline:\\test\blah").group_by("id")
>>> def print_details(proc, depth):
... print("%s%s: %s ran %s" % (" "*depth, proc.start, proc.username, proc.cmdline))
...
>>> for proc in query:
... print_details(proc, 0)
... proc.walk_parents(print_details)
...
HTTP GET /api/v1/process?cb.urlver=1&facet=false&q=process_name%3Anet.exe+cmdline%3A%5C%5Ctest%5Cblah&rows=100&sort=last_update+desc&start=0 took 0.462s (response 200)
2016-11-11 20:59:31.631000: WIN-IA9NQ1GN8OI\bit9rad ran net use y: \\test\blah
HTTP GET /api/v3/process/00000003-0000-036c-01d2-2efd3af51186/1/event took 0.036s (response 200)
2016-10-25 20:20:29.790000: WIN-IA9NQ1GN8OI\bit9rad ran "C:\Windows\system32\cmd.exe"
HTTP GET /api/v3/process/00000003-0000-0c34-01d2-2ec94f09cae6/1/event took 0.213s (response 200)
2016-10-25 14:08:49.651000: WIN-IA9NQ1GN8OI\bit9rad ran C:\Windows\Explorer.EXE
HTTP GET /api/v3/process/00000003-0000-0618-01d2-2ec94edef208/1/event took 0.013s (response 200)
2016-10-25 14:08:49.370000: WIN-IA9NQ1GN8OI\bit9rad ran C:\Windows\system32\userinit.exe
HTTP GET /api/v3/process/00000003-0000-02ec-01d2-2ec9412b4b70/1/event took 0.017s (response 200)
2016-10-25 14:08:26.382000: SYSTEM ran winlogon.exe
HTTP GET /api/v3/process/00000003-0000-02b0-01d2-2ec94115df7a/1/event took 0.012s (response 200)
2016-10-25 14:08:26.242000: SYSTEM ran \SystemRoot\System32\smss.exe 00000001 00000030
HTTP GET /api/v3/process/00000003-0000-0218-01d2-2ec93f813429/1/event took 0.021s (response 200)
2016-10-25 14:08:23.590000: SYSTEM ran \SystemRoot\System32\smss.exe
HTTP GET /api/v3/process/00000003-0000-0004-01d2-2ec93f7c7181/1/event took 0.081s (response 200)
2016-10-25 14:08:23.559000: SYSTEM ran c:\windows\system32\ntoskrnl.exe
HTTP GET /api/v3/process/00000003-0000-0000-01d2-2ec93f6051ee/1/event took 0.011s (response 200)
2016-10-25 14:08:23.374000: ran c:\windows\system32\ntoskrnl.exe
HTTP GET /api/v3/process/00000003-0000-0004-01d2-2ec93f6051ee/1/event took 0.011s (response 200)
2016-11-11 20:59:25.667000: WIN-IA9NQ1GN8OI\bit9rad ran net use z: \\test\blah
2016-10-25 20:20:29.790000: WIN-IA9NQ1GN8OI\bit9rad ran "C:\Windows\system32\cmd.exe"
2016-10-25 14:08:49.651000: WIN-IA9NQ1GN8OI\bit9rad ran C:\Windows\Explorer.EXE
2016-10-25 14:08:49.370000: WIN-IA9NQ1GN8OI\bit9rad ran C:\Windows\system32\userinit.exe
2016-10-25 14:08:26.382000: SYSTEM ran winlogon.exe
2016-10-25 14:08:26.242000: SYSTEM ran \SystemRoot\System32\smss.exe 00000001 00000030
2016-10-25 14:08:23.590000: SYSTEM ran \SystemRoot\System32\smss.exe
2016-10-25 14:08:23.559000: SYSTEM ran c:\windows\system32\ntoskrnl.exe
2016-10-25 14:08:23.374000: ran c:\windows\system32\ntoskrnl.exe
That was a lot in one code sample, so let’s break it down part-by-part.
First, we set up the query
variable by creating a new Query
object using the .where()
and .and_()
methods. Next, we define a function that will get called on each parent process all the way up the chain to the system
kernel loading during the boot process. This function, print_details
, will print a few data points about each
process: namely, the local endpoint time when that process started, the user who spawned the process, and the
command line for the process.
Finally, we execute our query by looping over the result set with a Python for loop. For each process that matches
the query, first we print details of the process itself (the process that called net.exe
with a command line
argument of our target share \\test\blah
), then calls the .walk_parents()
helper method to walk up the chain
of all parent processes. Each level of parent process (the “depth”) is represented by an extra space; therefore, reading
backwards, you can see that ntoskrnl.exe
spawned smss.exe
, which in turn spawned winlogon.exe
, and so on.
You can see the full backwards chain of events that ultimately led to the execution of each of these net.exe
calls.
Remember that we have logging turned on for these examples, so you see each of the HTTP GET requests to retrieve process
event details as they happen. Astute observers will note that walking the parents of the second net.exe
command,
where the \\test\blah
share was mounted on the z:
drive, did not trigger additional HTTP GET requests. This
is thanks to cbapi’s caching layer. Since both net.exe
commands ran as part of the same command shell session, the
parent processes are shared between the two executions. Since the parent processes were already requested as part of
the previous walk up the chain of parent processes, cbapi did not re-request the data from the server, instead using its
internal cache to satisfy the process information requests from this script.
New Filters: Group By, Time Restrictions¶
In the query above, there is an extra .group_by()
method. This method is new in cbapi 1.1.0 and is part of five
new query filters available when communicating with a Cb Response 6.1 server. These filters are accessible via methods
on the Process
Query object. These new methods are:
.group_by()
- Group the result set by a field in the response. Typically you will want to group byid
, which will ensure that the result set only has one result per process rather than one result per event segment. For more information on processes, process segments, and how segments are stored in Cb Response 6.0, see the Process API Changes for Cb Response 6.0 page on the Developer Network website..min_last_update()
- Only return processes that have events after a given date/time stamp (relative to the individual sensor’s clock).max_last_update()
- Only return processes that have events before a given date/time stamp (relative to the individual sensor’s clock).min_last_server_update()
- Only return processes that have events after a given date/time stamp (relative to the Cb Response server’s clock).max_last_server_update()
- Only return processes that have events before a given date/time stamp (relative to the Cb Response server’s clock)
Cb Response 6.1 uses a new way of recording process events that greatly increases the speed and scale of collection, allowing you to store and search data for more endpoints on the same hardware. Details on the new database format can be found on the Developer Network website at the Process API Changes for Cb Response 6.0 page.
The Process
Model Object traditionally referred to a single “segment” of events in the Cb Response database. In
Cb Response versions prior to 6.0, a single segment will include up to 10,000 individual endpoint events, enough to
handle over 95% of the typical event activity for a given process. Therefore, even though a Process
Model Object
technically refers to a single segment in a process, since most processes had less than 10,000 events and therefore
were only comprised of a single segment, this distinction wasn’t necessary.
However, now that processes are split across many segments, a better way of handling this is necessary. Therefore,
Cb Response 6.0 introduces the new .group_by()
method.
More on Filters¶
Querying for a process will return all segments that match. For example, if you search for process_name:cmd.exe
,
the result set will include all segments of all cmd.exe
processes. Therefore, Cb Response 6.1 introduced
the ability to “group” result sets by a field in the result. Typically you will want to group by the internal process
id (the id
field), and this is what we did in the query above. Grouping by the id
field will ensure that only
one result is returned per process rather than per segment.
Let’s take a look at an example:
>>> from datetime import datetime, timedelta
>>> yesterday = datetime.utcnow() - timedelta(days=1) # Get "yesterday" in GMT
>>> for proc in c.select(Process).where("process_name:cmd.exe").min_last_update(yesterday):
... print proc.id, proc.segment
DEBUG:cbapi.connection:HTTP GET /api/v1/process?cb.min_last_update=2017-05-21T18%3A41%3A58Z&cb.urlver=1&facet=false&q=process_name%3Acmd.exe&rows=100&sort=last_update+desc&start=0 took 2.164s (response 200)
00000001-0000-0e48-01d2-c2a397f4cfe0 1495465643405
00000001-0000-0e48-01d2-c2a397f4cfe0 1495465407157
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463680155
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463807694
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463543944
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463176570
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463243492
Notice that the “same” process ID is returned seven times, but with seven different segment IDs. Cb Response will
return every process event segment that matches a given query, in this case, any event segment that contains the
process command name cmd.exe
.
That is, however, most likely not what you wanted. Instead, you’d like a list of the unique processes associated with
the command name cmd.exe
. Just add the .group_by("id")
filter to your query:
>>> for proc in c.select(Process).where("process_name:cmd.exe").min_last_update(yesterday).group_by("id"):
... print proc.id, proc.segment
DEBUG:cbapi.connection:HTTP GET /api/v1/process?cb.group=id&cb.min_last_update=2017-05-21T18%3A41%3A58Z&cb.urlver=1&facet=false&q=process_name%3Acmd.exe&rows=100&sort=last_update+desc&start=0 took 2.163s (response 200)
00000001-0000-0e48-01d2-c2a397f4cfe0 1495465643405
Feed and Watchlist Maintenance¶
The cbapi provides several helper functions to assist in creating watchlists and
Watchlists are simply saved Queries that are automatically run on the Cb Response server on a periodic basis. Results
of the watchlist are tagged in the database and optionally trigger alerts. Therefore, a cbapi Query can easily be
converted into a watchlist through the Query .create_watchlist()
function:
>>> new_watchlist = query.create_watchlist("[WARN] Attempts to mount internal share")
Creating a new Watchlist object
Sending HTTP POST /api/v1/watchlist with {"id": null, "index_type": "events", "name": "[WARN] Attempts to mount internal share", "search_query": "facet=false&q=process_name%3Anet.exe+cmdline%3A%5C%5Ctest%5Cblah&cb.urlver=1&sort=last_update+desc"}
HTTP POST /api/v1/watchlist took 0.510s (response 200)
Received response: {u'id': 222}
Only received an ID back from the server, forcing a refresh
HTTP GET /api/v1/watchlist/222 took 0.034s (response 200)
This helper function will automatically create a watchlist from the Query object with the given name.
If you have a watchlist that already exists, the Watchlist Model Object can help you extract the human-readable
query from the watchlist. Just select the watchlist and access the .query
property on the Watchlist Model Object:
>>> my_watchlist = cb.select(Watchlist).where("name:[WARN] Attempts to mount internal share").one()
>>> print(my_watchlist.query)
process_name:net.exe cmdline:\\test\blah
You can also execute the query straight from the Watchlist Model Object:
>>> len(my_watchlist.search())
HTTP GET /api/v1/process?cb.urlver=1&facet=false&q=process_name%3Anet.exe+cmdline%3A%5C%5Ctest%5Cblah&rows=0&start=0 took 0.477s (response 200)
2
And finally, you can of course enable and disable Watchlists:
>>> my_watchlist.enabled = False
>>> my_watchlist.save()
Updating Watchlist with unique ID 222
Sending HTTP PUT /api/v1/watchlist/222 with {"alliance_id": null, "date_added": "2016-11-15 23:48:27.615993-05:00", "enabled": false, "from_alliance": false, "group_id": -1, "id": "222", "index_type": "events", "last_hit": "2016-11-15 23:50:08.448685-05:00", "last_hit_count": 2, "name": "[WARN] Attempts to mount internal share", "readonly": false, "search_query": "facet=false&q=process_name%3Anet.exe%20cmdline%3A%5C%5Ctest%5Cblah&cb.urlver=1", "search_timestamp": "2016-11-16T04:50:01.750240Z", "total_hits": "2", "total_tags": "2"}
HTTP PUT /api/v1/watchlist/222 took 0.036s (response 200)
Received response: {u'result': u'success'}
HTTP GET /api/v1/watchlist/222 took 0.029s (response 200)
You can see more examples of Feed and Watchlist maintenance in the feed_operations.py
and watchlist_operations.py
example scripts.
Managing Threat Reports & Alerts¶
The cbapi provides helper functions to manage alerts and threat reports in bulk. The Query objects associated with the ThreatReport and Alert Model Objects provide a few bulk operations to help manage large numbers of Threat Reports and Alerts, respectively.
To mark a large number of Threat Reports as false positives, create a query that matches the Reports you’re interested in. For example, if every Report from the Feed named “SOC” that contains the word “FUZZYWOMBAT” in the report title should be considered a false positive (and no longer trigger Alerts), you can write the following code to do so:
>>> feed = c.select(Feed).where("name:SOC").one()
>>> report_query = feed.reports.where("title:FUZZYWOMBAT")
>>> report_query.set_ignored()
Similar actions can be taken on Alerts. The AlertQuery object exposes three helper methods to perform bulk operations
on sets of Alerts: .set_ignored()
, .assign_to()
, and .change_status()
.
Joining Everything Together¶
Now that we’ve examined how to request information on binaries, sensors, and processes through cbapi, let’s chain
this all together using the “join” functionality of cbapi’s Model Objects. Let’s just tweak the print_details
function from above to add a few more contextual details. Our new function will now include the following data points
for each process:
- The hostname the process was executed on
- The sensor group that host belongs to
- If the binary was signed, also print out:
- The number of days between when the binary was signed and it was executed on the endpoint
- The verified publisher name from the digital signature
We can transparently “join” between the Process Model Object and the Sensor, Sensor Group, and Binary Model Objects using the appropriately named helper properties. Here’s the new function:
>>> import pytz
>>> def print_details(proc, depth):
... print("On host {0} (part of sensor group {1}):".format(proc.hostname, proc.sensor.group.name))
... print("- At {0}, process {1} was executed by {2}".format(proc.start, proc.cmdline, proc.username))
... if proc.binary.signed:
... # force local timestamp into UTC, we're just looking for an estimate here.
... utc_timestamp = proc.start.replace(tzinfo=pytz.timezone("UTC"))
... days_since_signed = (utc_timestamp - proc.binary.signing_data.sign_time).days
... print("- That binary ({0}) was signed by {1} {2} days before it was executed.".format(proc.process_md5,
... proc.binary.signing_data.publisher, days_since_signed))
Now if we run our for loop from above again:
>>> for proc in query:
... print_details(proc, 0)
... proc.walk_parents(print_details)
...
HTTP GET /api/v1/process?cb.urlver=1&facet=false&q=process_name%3Anet.exe+cmdline%3A%5C%5Ctest%5Cblah&rows=100&sort=last_update+desc&start=0 took 0.487s (response 200)
HTTP GET /api/v1/sensor/3 took 0.037s (response 200)
HTTP GET /api/group/1 took 0.022s (response 200)
On host WIN-IA9NQ1GN8OI (part of sensor group Default Group):
- At 2016-11-11 20:59:31.631000, process net use y: \\test\blah was executed by WIN-IA9NQ1GN8OI\bit9rad
HTTP GET /api/v1/binary/79B6D4C5283FC806387C55B8D7C8B762/summary took 0.016s (response 200)
- That binary (79b6d4c5283fc806387c55b8d7c8b762) was signed by Microsoft Corporation 1569 days before it was executed.
HTTP GET /api/v3/process/00000003-0000-036c-01d2-2efd3af51186/1/event took 0.045s (response 200)
On host WIN-IA9NQ1GN8OI (part of sensor group Default Group):
- At 2016-10-25 20:20:29.790000, process "C:\Windows\system32\cmd.exe" was executed by WIN-IA9NQ1GN8OI\bit9rad
HTTP GET /api/v1/binary/BF93A2F9901E9B3DFCA8A7982F4A9868/summary took 0.015s (response 200)
- That binary (bf93a2f9901e9b3dfca8a7982f4a9868) was signed by Microsoft Corporation 1552 days before it was executed.
Those few lines of Python above are jam-packed with functionality. Now for each process execution, we have added
contextual information on the source host, the group that host is part of, and details about the signing status of the
binary that was executed. The magic is performed behind the scenes when we use the .binary
and .sensor
properties
on the Process Model Object. Just like our previous example, cbapi’s caching layer ensures that we do not overload
the Cb Response server with duplicate requests for the same data. In this example, multiple redundant requests for sensor,
sensor group, and binary data are all eliminated by cbapi’s cache.
Facets¶
The cbapi also provides functionality to pull facet information from the database. You can use the .facet()
method
on a Query object to retrieve facet (ie. “group”) information for a given query result set. Here’s an example that
pulls the most common process names for our sample host:
>>> def print_facet_histogram(facets):
... for entry in facets:
... print("%15s: %5s%% %s" % (entry["name"][:15], entry["ratio"], u"\u25A0"*(int(entry["percent"])/2)))
...
>>> facet_query = cb.select(Process).where("hostname:WIN-IA9NQ1GN8OI").and_("username:bit9rad")
>>> print_facet_histogram(facet_query.facets("process_name")["process_name"])
HTTP GET /api/v1/process?cb.urlver=1&facet=true&facet.field=process_name&facet.field=username&q=hostname%3AWIN-IA9NQ1GN8OI+username%3Abit9rad&rows=0&start=0 took 0.024s (response 200)
chrome.exe: 23.4% ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
thumbnailextrac: 15.4% ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
adobearm.exe: 8.6% ■■■■■■■■■■■■■■■■■■
taskhost.exe: 6.0% ■■■■■■■■■■■■
conhost.exe: 4.7% ■■■■■■■■■
ping.exe: 4.0% ■■■■■■■■
wermgr.exe: 3.5% ■■■■■■■
In the above example, we just pulled one facet: the process_name
; you can ask the server for faceting on multiple
fields in one query by simply listing the fields in the call to .facet()
: for example, .facet("username", "process_name")
will produce a dictionary with two top-level keys: username
and process_name
.
Administrative Tasks¶
In addition to querying data, you can also perform various administrative tasks using cbapi.
Let’s create a user on our Cb Response server:
>>> user = cb.create(User)
>>> user.username = "jgarman"
>>> user.password = "cbisawesome"
>>> user.first_name = "Jason"
>>> user.last_name = "Garman"
>>> user.teams = []
>>> user.global_admin = False
Creating a new User object
Sending HTTP POST /api/user with {"email": "jgarman@carbonblack.com", "first_name": "Jason", "global_admin": false, "id": null, "last_name": "Garman", "password": "cbisawesome", "teams": [], "username": null}
HTTP POST /api/user took 0.608s (response 200)
Received response: {u'result': u'success'}
How about moving a sensor to a new Sensor Group:
>>> sg = cb.create(SensorGroup)
>>> sg.name = "Critical Endpoints"
>>> sg.site = 1
>>> sg.save()
Creating a new SensorGroup object
Sending HTTP POST /api/group with {"id": null, "name": "Critical Endpoints", "site_id": 1}
HTTP POST /api/group took 0.282s (response 200)
Received response: {u'id': 2}
Only received an ID back from the server, forcing a refresh
HTTP GET /api/group/2 took 0.011s (response 200)
>>> sensor = cb.select(Sensor).where("hostname:WIN-IA9NQ1GN8OI").first()
>>> sensor.group = sg
>>> sensor.save()
Updating Sensor with unique ID 3
Sending HTTP PUT /api/v1/sensor/3 with {"boot_id": "2", "build_id": 2, "build_version_string": "005.002.000.60922", ...
HTTP PUT /api/v1/sensor/3 took 0.087s (response 204)
HTTP GET /api/v1/sensor/3 took 0.030s (response 200)
CbAPI and Live Response¶
Working with the Cb Live Response REST API directly can be difficult. Thankfully, just like the rest of Carbon Black’s REST APIs, cbapi provides Pythonic APIs to make working with the Live Response API much easier.
In addition to easy-to-use APIs to call into Live Response, cbapi also provides a “job-based” interface that allows cbapi to intelligently schedule large numbers of concurrent Live Response sessions across multiple sensors. Your code can then be notified when the jobs are complete, returning the results of the job if it succeeded or the Exception if it failed.
Getting Started with Live Response¶
The cbapi Live Response API is built around establishing a
cbapi.response.live_response.LiveResponseSession
object from a cbapi.response.models.Sensor
Model
Object. Then you can call methods on the LiveResponseSession
object to perform Live Response actions on the
target host. These calls are synchronous, meaning that they will wait until the action is complete and a result is
available, before returning back to your script. Here’s an example:
>>> from cbapi.response import *
>>> cb = CbResponseAPI()
>>> sensor = cb.select(Sensor).where("hostname:WIN-IA9NQ1GN8OI").first()
>>> with sensor.lr_session() as session:
... print(session.get_file(r"c:\test.txt"))
this is a test
Since the Live Response API is synchronous, the script will not continue until either the Live Response session is established and the file contents are retrieved, or an exception occurs (in this case, either a timeout error or an error reading the file).
As seen in the example above, the .lr_session()
method is context-aware. Cb Response has a limited number of
concurrent Live Response session slots (by default, only ten). By wrapping the .lr_session()
A full listing of methods in the cbapi Live Response API is available in the documentation for
the cbapi.live_response_api.CbLRSessionBase
class.
Live Response Errors¶
There are four classes of errors that you will commonly encounter when working with the Live Response API:
- A
cbapi.errors.TimeoutError
is raised if a timeout is encountered when waiting for a response for a Live Response API request. - A
cbapi.response.live_response_api.LiveResponseError
is raised if an error is returned during the execution of a Live Response command on an endpoint. TheLiveResponseError
includes detailed information about the error that occurred, including the exact error code that was returned from the endpoint and a textual description of the error. - A
cbapi.errors.ApiError
is raised if you attempt to execute a command that is not supported by the sensor; for example, attempting to acquire a memory dump from a sensor running a pre-5.1 version of the agent will fail with anApiError
exception. - A
cbapi.errors.ServerError
is raised if any other error occurs; for example, a 500 Internal Server Error is returned from the Live Response API.
Job-Based API¶
The basic Synchronous API described above in the Getting Started section works well for small tasks, targeting one sensor at a time. However, if you want to execute the same set of Live Response commands across a larger number of sensors, the cbapi provides a Job-Based Live Response API. The Job-Based Live Response API provides a straightforward API to submit Live Response jobs to a scheduler, schedule those Live Response jobs on individual endpoints concurrently, and return results and any errors back to you when the jobs complete. The Job-Based Live Response API is a natural fit with the Event-Based API to create IFTTT-style pipelines; if an event is received via the Event API, then perform Live Response actions on the affected endpoint via the Live Response Job-Based API.
The Job-Based API works by first defining a reusable “job” to perform on the endpoint. The Job is simply a class or function that takes a Live Response session object as input and performs a series of commands. Jobs can be as simple as retrieving a registry key, or as complex as collecting the Chrome browser history for any currently logged-in users.
Let’s look at an example Job to retrieve a registry key. This example job is pulled from the get_reg_autoruns.py
example script:
class GetRegistryValue(object):
def __init__(self, registry_key):
self.registry_key = registry_key
def run(self, session):
reg_info = session.get_registry_value(self.registry_key)
return time.time(), session.sensor_id, self.registry_key, reg_info["value_data"]
To submit this job, you instantiate an instance of a GetRegistryValue
class with the registry key you want to pull
back from the endpoint, and submit the .run()
method to the Live Response Job API:
>>> job = GetRegistryValue(regmod_path)
>>> registry_job = cb.live_response.submit_job(job.run, sensor_id)
Your script resumes execution immediately after the call to .submit_job()
. The job(s) that you’ve submitted will
be executed in a set of background threads managed by cbapi.
CbAPI Changelog¶
CbAPI 1.3.1 - Released August 3, 2017¶
This is a bugfix release with minor changes:
- Cb Response
- Add
partition_operations.py
script to demonstrate the use of the StoragePartition model object. - Fix errors when accessing the
.start
attribute of child processes. - Fix errors generated by the
walk_children.py
example script. The output has been changed as well to indicate the process lifetime, console UI link, and command lines. - Add an
.end
attribute to the Process model object. This attribute reports back eitherNone
if the process is still executing, or the last event time associated with the process if it has exited. See thewalk_children.py
script for an example of how to calculate process lifetime. - Fix errors when using the
.parents
attribute of a Process. - Add
wait_for_completion
flag tocreate_process
Live Response method, and default toTrue
. Thecreate_process
method will now wait for the target process to complete before returning.
- Add
- Cb Defense
- Add
wait_for_completion
flag tocreate_process
Live Response method, and default toTrue
. Thecreate_process
method will now wait for the target process to complete before returning.
- Add
CbAPI 1.3.0 - Released July 27, 2017¶
This release introduces the Live Response API for Cb Defense. A sample cblr_cli.py
script is now included in the
examples
directory for both Cb Response and Cb Defense.
Other changes:
- Cb Protection
- You can now create new
FileRule
andPolicy
model objects in cbapi.
- You can now create new
- Cb Response
- Added
watchlist_exporter.py
andwatchlist_importer.py
scripts to the Cb Response examples directory. These scripts allow you to export Watchlist data in a human- and machine-readable JSON format and then re-import them into another Cb Response server. - The
Sensor
Model Object now uses the non-paginated (v1) API by default. This fixes any issues encountered when iterating over all the sensors and receiving duplicate and/or missing sensors. - Fix off-by-one error in
CbCrossProcess
object. - Fix issue iterating through
Process
Model Objects when accessing processes generated from a 5.2 server after upgrading to 6.1. - Reduce number of API requests required when accessing sibling information (parents, children, and siblings) from the
Process
Model Object. - Retrieve all events for a process when using
segment
ID of zero on a Cb Response 6.1 server. - Behavior of
Process.children
attribute has changed:- Only one entry is present per child (before there were up to two; one for the spawn event, one for the terminate event)
- The timestamp is derived from the start time of the process, not the timestamp from the spawn event. the two timestamps will be off by a few microseconds.
- The old behavior is still available by using the
Process.childprocs
attribute instead. This incurs a performance penalty as another API call will have to be made to collect the childproc information.
Binary
Model Object now returns False for.is_signed
attribute if it is set to(Unknown)
.
- Added
- Moved the
six
Python module into cbapi and removed the external dependency.
CbAPI 1.2.0 - Released June 22, 2017¶
This release introduces compatibility with our new product, Cb Defense, as well as adding new Model Objects introduced in the Cb Protection 8.0 APIs.
Other changes:
- Cb Response
- New method
synchronize()
added to theFeed
Model Object
- New method
- Bug fixes and documentation improvements
CbAPI 1.1.1 - Released June 2, 2017¶
This release includes compatibility fixes for Cb Response 6.1. Changes from 1.0.1 include:
- Substantial changes to the
Process
Model Object for Cb Response 6.1. See details below. - New
StoragePartition
Model Object to control Solr core loading/unloading in Cb Response 6.1. - New
IngressFilter
Model Object to control ingress filter settings in Cb Response 6.1. - Fix issues with
event_export.py
example script. - Add
.all_events
property to theProcess
Model Object to expose a list of all events across all segments. - Add example script to perform auto-banning based on watchlist hits from Cb Event Forwarder S3 output files.
- Add bulk operations to the
ThreatReport
andAlert
Query objects:- You can now call
.set_ignored()
,.assign()
, and.change_status()
on anAlert
Query object to change the respective fields for every Alert that matches the query. - You can now call
.set_ignored()
on aThreatReport
Query object to set or clear the ignored flag for every ThreatReport that matches the query.
- You can now call
Changes to Process
Model Object for Cb Response 6.1¶
Cb Response 6.1 uses a new way of recording process events that greatly increases the speed and scale of collection, allowing you to store and search data for more endpoints on the same hardware. Details on the new database format can be found on the Developer Network website at the Process API Changes for Cb Response 6.0 page.
The Process
Model Object traditionally referred to a single “segment” of events in the Cb Response database. In
Cb Response versions prior to 6.0, a single segment will include up to 10,000 individual endpoint events, enough to
handle over 95% of the typical event activity for a given process. Therefore, even though a Process
Model Object
technically refers to a single segment in a process, since most processes had less than 10,000 events and therefore
were only comprised of a single segment, this distinction wasn’t necessary.
However, now that processes are split across many segments, a better way of handling this is necessary. Therefore,
Cb Response 6.0 introduces the new .group_by()
method. This method is new in cbapi 1.1.0 and is part of five
new query filters available when communicating with a Cb Response 6.1 server. These filters are accessible via methods
on the Process
Query object. These new methods are:
.group_by()
- Group the result set by a field in the response. Typically you will want to group byid
, which will ensure that the result set only has one result per process rather than one result per event segment. For more information on processes, process segments, and how segments are stored in Cb Response 6.0, see the Process API Changes for Cb Response 6.0 page on the Developer Network website..min_last_update()
- Only return processes that have events after a given date/time stamp (relative to the individual sensor’s clock).max_last_update()
- Only return processes that have events before a given date/time stamp (relative to the individual sensor’s clock).min_last_server_update()
- Only return processes that have events after a given date/time stamp (relative to the Cb Response server’s clock).max_last_server_update()
- Only return processes that have events before a given date/time stamp (relative to the Cb Response server’s clock)
Examples for new Filters¶
Let’s take a look at an example:
>>> from datetime import datetime, timedelta
>>> yesterday = datetime.utcnow() - timedelta(days=1) # Get "yesterday" in GMT
>>> for proc in c.select(Process).where("process_name:cmd.exe").min_last_update(yesterday):
... print proc.id, proc.segment
DEBUG:cbapi.connection:HTTP GET /api/v1/process?cb.min_last_update=2017-05-21T18%3A41%3A58Z&cb.urlver=1&facet=false&q=process_name%3Acmd.exe&rows=100&sort=last_update+desc&start=0 took 2.164s (response 200)
00000001-0000-0e48-01d2-c2a397f4cfe0 1495465643405
00000001-0000-0e48-01d2-c2a397f4cfe0 1495465407157
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463680155
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463807694
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463543944
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463176570
00000001-0000-0e48-01d2-c2a397f4cfe0 1495463243492
Notice that the “same” process ID is returned seven times, but with seven different segment IDs. Cb Response will
return every process event segment that matches a given query, in this case, any event segment that contains the
process command name cmd.exe
.
That is, however, most likely not what you wanted. Instead, you’d like a list of the unique processes associated with
the command name cmd.exe
. Just add the .group_by("id")
filter to your query:
>>> for proc in c.select(Process).where("process_name:cmd.exe").min_last_update(yesterday).group_by("id"):
... print proc.id, proc.segment
DEBUG:cbapi.connection:HTTP GET /api/v1/process?cb.group=id&cb.min_last_update=2017-05-21T18%3A41%3A58Z&cb.urlver=1&facet=false&q=process_name%3Acmd.exe&rows=100&sort=last_update+desc&start=0 took 2.163s (response 200)
00000001-0000-0e48-01d2-c2a397f4cfe0 1495465643405
API Documentation¶
Once you’ve taken a look at the User Guide, read through some of the examples on GitHub, and maybe even written some code of your own, the API documentation can help you get the most out of cbapi by documenting all of the methods available to you.
Cb Response API¶
This page documents the public interfaces exposed by cbapi when communicating with a Carbon Black Enterprise Response server.
Main Interface¶
To use cbapi with Carbon Black Response, you will be using the CbResponseAPI.
The CbResponseAPI object then exposes two main methods to access data on the Carbon Black server: select
and create
.
-
class
cbapi.response.rest_api.
CbResponseAPI
(*args, **kwargs)¶ The main entry point into the Carbon Black Enterprise Response API. Note that calling this will automatically connect to the Carbon Black server in order to verify connectivity and get the server version.
Parameters: - profile (str) – (optional) Use the credentials in the named profile when connecting to the Carbon Black server. Uses the profile named ‘default’ when not specified.
- url (str) – (optional, discouraged) Instead of using a credential profile, pass URL and API token to the constructor.
- token (str) – (optional, discouraged) API token
- ssl_verify (bool) – (optional, discouraged) Enable or disable SSL certificate verification
Usage:
>>> from cbapi import CbEnterpriseResponseAPI >>> cb = CbEnterpriseResponseAPI(profile="production")
-
create
(cls, data=None)¶ Creates a new object.
Parameters: cls (class) – The Model class (only some models can be created, for example, Feed, Notification, ...) Returns: An empty instance of the Model class Raises: ApiError – if the Model cannot be created
-
create_new_partition
()¶ Create a new Solr time partition for event storage. Available in Cb Response 6.1 and above. This will force roll-over current hot partition into warm partition (by renaming it to a time-stamped name) and create a new hot partition (“writer”).
Returns: Nothing if successful.
Raises: - ApiError – if there was an error creating the new partition.
- ServerError – if there was an error creating the new partition.
-
from_ui
(uri)¶ Retrieve a Carbon Black Enterprise Response object based on URL from the Carbon Black Enterprise Response web user interface.
For example, calling this function with
https://server/#/analyze/00000001-0000-0554-01d1-3bc4553b8c9f/1
as theuri
argument will return a new :py:class: cbapi.response.models.Process class initialized with the process GUID from the URL.Parameters: uri (str) – Web browser URL from the Cb web interface Returns: the appropriate model object for the URL provided Raises: ApiError – if the URL does not correspond to a recognized model object
-
info
()¶ Retrieve basic version information from the Carbon Black Enterprise Response server.
Returns: Dictionary with information retrieved from the /api/info
API routeReturn type: dict
-
license_request
()¶ Retrieve license request block from the Carbon Black Enterprise Response server.
Returns: License request block Return type: str
-
select
(cls, unique_id=None, *args, **kwargs)¶ Prepares a query against the Carbon Black data store.
Parameters: - cls (class) – The Model class (for example, Computer, Process, Binary, FileInstance) to query
- unique_id – (optional) The unique id of the object to retrieve, to retrieve a single object by ID
Returns: An instance of the Model class if a unique_id is provided, otherwise a Query object
-
update_license
(license_block)¶ Upload new license to the Carbon Black Enterprise Response server.
Parameters: license_block (str) – Licence block provided by Carbon Black support Raises: ServerError – if the license is not accepted by the Carbon Black server
Queries¶
-
class
cbapi.response.query.
Query
(doc_class, cb, query=None, raw_query=None)¶ Represents a prepared query to the Carbon Black Enterprise Response server.
This object is returned as part of a
CbEnterpriseResponseAPI.select()
operation on Process and Binary objects from the Carbon Black Enterprise Response server. You should not have to create this class yourself.The query is not executed on the server until it’s accessed, either as an iterator (where it will generate values on demand as they’re requested) or as a list (where it will retrieve the entire result set and save to a list). You can also call the Python built-in
len()
on this object to retrieve the total number of items matching the query.The syntax for query :py:meth:where and :py:meth:sort methods can be found in the Query Reference posted on the Carbon Black Developer Network website.
Examples:
>>> cb = CbEnterpriseResponseAPI() >>> query = cb.select(Process) # returns a Query object matching all Processes >>> query = query.where("process_name:notepad.exe") # add a filter to this Query >>> query = query.sort("last_update desc") # sort by last update time, most recent first >>> for proc in query: # uses the iterator to retrieve all results >>> print("{0} {1}".format(proc.username, proc.hostname)) >>> processes = query[:10] # retrieve the first ten results >>> len(query) # retrieve the total count
- Notes:
- The slicing operator only supports start and end parameters, but not step.
[1:-1]
is legal, but[1:2:-1]
is not. - You can chain where clauses together to create AND queries; only objects that match all
where
clauses will be returned.
- The slicing operator only supports start and end parameters, but not step.
-
and_
(new_query)¶ Add a filter to this query. Equivalent to calling
where()
on this object.Parameters: new_query (str) – Query string - see the Query Reference.
Returns: Query object Return type: Query
-
facets
(*args)¶ Retrieve a dictionary with the facets for this query.
Parameters: args – Any number of fields to use as facets Returns: Facet data Return type: dict
-
sort
(new_sort)¶ Set the sort order for this query.
Parameters: new_sort (str) – New sort order - see the Query Reference.
Returns: Query object Return type: Query
-
where
(new_query)¶ Add a filter to this query.
Parameters: new_query (str) – Query string - see the Query Reference.
Returns: Query object Return type: Query
-
class
cbapi.response.models.
ProcessQuery
(doc_class, cb, query=None, raw_query=None)¶ -
group_by
(field_name)¶ Set the group-by field name for this query. Typically, you will want to set this to ‘id’ if you only want one result per process.
This method is only available for Cb Response servers 6.0 and above. Calling this on a Query object connected to a Cb Response 5.x server will simply result in a no-op.
Parameters: field_name (str) – Field name to group the result set by. Returns: Query object Return type: ProcessQuery
-
max_last_server_update
(v)¶ Set the maximum last update time (relative to server) for this query. The timestamp can be expressed either as a
datetime
like object or as an ISO 8601 string formatted timestamp such as 2017-04-29T04:21:18Z. If adatetime
like object is provided, it is assumed to be in GMT time zone.This option will limit the number of Solr cores that need to be searched for events that match the query.
This method is only available for Cb Response servers 6.0 and above. Calling this on a Query object connected to a Cb Response 5.x server will simply result in a no-op.
Parameters: v (str) – Timestamp (either string or datetime object). Returns: Query object Return type: ProcessQuery
-
max_last_update
(v)¶ Set the maximum last update time (relative to sensor) for this query. The timestamp can be expressed either as a
datetime
like object or as an ISO 8601 string formatted timestamp such as 2017-04-29T04:21:18Z. If adatetime
like object is provided, it is assumed to be in GMT time zone.This option will limit the number of Solr cores that need to be searched for events that match the query.
This method is only available for Cb Response servers 6.0 and above. Calling this on a Query object connected to a Cb Response 5.x server will simply result in a no-op.
Parameters: v (str) – Timestamp (either string or datetime object). Returns: Query object Return type: ProcessQuery
-
min_last_server_update
(v)¶ Set the minimum last update time (relative to server) for this query. The timestamp can be expressed either as a
datetime
like object or as an ISO 8601 string formatted timestamp such as 2017-04-29T04:21:18Z. If adatetime
like object is provided, it is assumed to be in GMT time zone.This option will limit the number of Solr cores that need to be searched for events that match the query.
This method is only available for Cb Response servers 6.0 and above. Calling this on a Query object connected to a Cb Response 5.x server will simply result in a no-op.
Parameters: v (str) – Timestamp (either string or datetime object). Returns: Query object Return type: ProcessQuery
-
min_last_update
(v)¶ Set the minimum last update time (relative to sensor) for this query. The timestamp can be expressed either as a
datetime
like object or as an ISO 8601 string formatted timestamp such as 2017-04-29T04:21:18Z. If adatetime
like object is provided, it is assumed to be in GMT time zone.This option will limit the number of Solr cores that need to be searched for events that match the query.
This method is only available for Cb Response servers 6.0 and above. Calling this on a Query object connected to a Cb Response 5.x server will simply result in a no-op.
Parameters: v (str) – Timestamp (either string or datetime object). Returns: Query object Return type: ProcessQuery
-
-
class
cbapi.response.models.
ThreatReportQuery
(doc_class, cb, query=None, raw_query=None)¶
-
class
cbapi.response.models.
AlertQuery
(doc_class, cb, query=None, raw_query=None)¶
Models¶
-
class
cbapi.response.models.
Process
(cb, procguid, segment=None, initial_data=None, force_init=False, suppressed_process=False)¶ -
all_events
¶ Returns a list of all events associated with this process across all segments, sorted by timestamp
Returns: list of CbEvent objects
-
all_events_segment
¶ Returns a list of all events associated with this process segment, sorted by timestamp
Returns: list of CbEvent objects
-
binary
¶ Joins this attribute with the
Binary
object associated with this Process objectExample: >>> process_obj = c.select(Process).where('process_name:svch0st.exe')[0] >>> binary_obj = process_obj.binary >>> print(binary_obj.signed) False
-
childprocs
¶ Generator that returns
CbChildProcEvent
objects associated with this process
-
children
¶ Generator that returns
CbChildProcEvent
objects associated with this process
-
cmdline
¶ Returns: Returns the command line of the process Return type: string
-
comms_ip
¶ Returns ascii representation of the ip address used to communicate with the Cb Response Server
-
crossprocs
¶ Generator that returns
CbCrossProcEvent
objects associated with this process
-
depth
¶ Returns the depth of this process from the “root” system process
Returns: integer representing the depth of the process (0 is the root system process). To prevent infinite recursion, a maximum depth of 500 processes is enforced.
-
end
¶ Returns the end time of the process (based on the last event received). If the process has not yet exited, “end” will return None.
Returns: datetime object of the last event received for the process, if it has terminated. Otherwise, None.
-
filemods
¶ Generator that returns
CbFileModEvent
objects associated with this process
-
find_file_writes
(filename)¶ Returns a list of file writes with the specified filename
Parameters: filename (str) – filename to match on file writes Returns: Returns a list of file writes with the specified filename Return type: list
-
interface_ip
¶ Returns ascii representation of the ip address of the interface used to communicate with the Cb Response server. If using NAT, this will be the “internal” IP address of the sensor.
-
last_server_update
¶ Returns a pretty version of when this process last updated
-
last_update
¶ Returns a pretty version of when this process last updated
-
max_last_server_update
¶ Returns a pretty version of the latest event in this process segment
-
max_last_update
¶ Returns a pretty version of the latest event in this process segment
-
min_last_server_update
¶ Returns a pretty version of the earliest event in this process segment
-
min_last_update
¶ Returns a pretty version of the earliest event in this process segment
-
modloads
¶ Generator that returns :py:class:CbModLoadEvent associated with this process
-
netconns
¶ Generator that returns
CbNetConnEvent
objects associated with this process
-
parent
¶ Returns the parent Process object if one exists
-
regmods
¶ Generator that returns
CbRegModEvent
objects associated with this process
-
sensor
¶ Joins this attribute with the
Sensor
object associated with this Process objectExample: >>> process_obj = c.select(Process).where('process_name:svch0st.exe')[0] >>> sensor_obj = process.sensor >>> print(sensor_obj.computer_dns_name) hyperv-win7-x86
-
start
¶ Returns the start time of the process
-
unsigned_modloads
¶ Returns all unsigned module loads. This is useful to filter out all Microsoft signed DLLs
-
username
¶ Returns the username of the owner of this process
-
walk_children
(callback, max_depth=0, depth=0)¶ Walk down the execution chain while calling the specified callback function at each depth.
Example: >>> def proc_callback(parent_proc, depth): ... print(parent_proc.cmdline, depth) >>> >>> process = c.select(Process).where('process_name:svch0st.exe')[0] >>> process.walk_children(proc_callback, depth=2) (u'cmd.exe \c ipconfig', 2) (u'cmd.exe \\c ipconfig', 2) (u'cmd.exe /c ipconfig', 2) (u'ipconfig', 3) (u'cmd.exe /c ipconfig.exe /all', 2) (u'cmd.exe \c ipconfig', 2) (u'cmd.exe \\c ipconfig', 2) (u'cmd.exe /c ipconfig', 2) (u'ipconfig', 3) (u'cmd.exe /c ipconfig.exe /all', 2)
Parameters: - callback (func) – Callback function used for execution at each depth. This function is executed with the parent process object and depth as parameters.
- max_depth (int) – Max number of iterations down the execution chain.
- depth (int) – Number of iterations down the execution chain
Returns: None
-
walk_parents
(callback, max_depth=0, depth=0)¶ Walk up the execution chain while calling the specified callback function at each depth.
Example: >>> def proc_callback(parent_proc, depth): ... print(parent_proc.cmdline, depth) >>> >>> process = c.select(Process).where('process_name:ipconfig.exe')[0] >>> process.walk_parents(proc_callback) (u'cmd.exe /c ipconfig.exe', 0) (u'c:\windows\carbonblack\cb.exe', 1) (u'C:\Windows\system32\services.exe', 2) (u'wininit.exe', 3) (u'\SystemRoot\System32\smss.exe 00000000 00000040 ', 4) (u'\SystemRoot\System32\smss.exe', 5) (u'', 6)
Parameters: - callback (func) – Callback function used for execution at each depth. This function is executed with the parent process object and depth as parameters.
- max_depth (int) – Max number of iterations up the execution chain
- depth (int) – Number of iterations up the execution chain.
Returns: None
-
webui_link
¶ Returns the Cb Response Web UI link associated with this process
-
-
class
cbapi.response.models.
Binary
(cb, md5sum, initial_data=None, force_init=False)¶ -
class
FrequencyData
¶ Class containing frequency information about a binary
Parameters: - computer_count (int) – Number of endpoints this binary resides
- process_count (int) – Number of executions
- all_process_count (int) – Number of all process documents
- module_frequency (int) – process_count / all_process_count
-
class
Binary.
SigningData
¶ Class containing binary signing information
Parameters: - result (str) – Signed or Unsigned
- publisher (str) – Singnature publisher
- issuer (str) – Signature issuer
- subject (str) – Signing subject
- sign_time (str) – Binary signed time
- program_name (str) – Binary program name
-
class
Binary.
VersionInfo
¶ Class containing versioning information about a binary
Parameters: - file_desc (str) – File description
- file_version (str) – File version
- product_name (str) – Product Name
- product_version (str) – Product version
- company_name (str) – Company Name
- legal_copyright (str) – Copyright
- original_filename (str) – Original File name of this binary
-
class
Binary.
VirusTotal
¶ Class containing information associated with a Virus Total Score
Parameters: - score (int) – Virus Total score
- link (str) – Virus Total link for this md5
-
Binary.
banned
¶ Returns BannedHash object if this Binary’s hash has been whitelisted (Banned), otherwise returns False
-
Binary.
digsig_issuer
¶ Returns the Digital Signature Issuer
-
Binary.
digsig_prog_name
¶ Returns the Digital Signature Program Name
-
Binary.
digsig_publisher
¶ Returns the Digital Signature Publisher
-
Binary.
digsig_sign_time
¶ Returns the Digital Signature signing time
-
Binary.
digsig_subject
¶ Returns the Digital Signature subject
-
Binary.
endpoints
¶ Return a list of endpoints this binary resides
-
Binary.
file
¶ Returns a file pointer to this binary
Example: >>> process_obj = c.select(Process).where("process_name:svch0st.exe").first() >>> binary_obj = process_obj.binary >>> print(binary_obj.file.read(2)) MZ
-
Binary.
frequency
¶ Returns
FrequencyData
information about the binary.Example: >>> process_obj = c.select(Process).where('process_name:svch0st.exe').first() >>> binary_obj = process_obj.binary >>> print(binary_obj.frequency) FrequencyData(computer_count=1, process_count=5, all_process_count=4429, module_frequency=0.001128923007450892)
-
Binary.
icon
¶ Returns the raw icon of this Binary. This data is not encoded.
-
Binary.
is_64bit
¶ Returns True if the Binary is an AMD64 or x64 (64-bit) Executable
-
Binary.
is_executable_image
¶ Returns True if the Binary is executable
-
Binary.
observed_filenames
¶ Returns a list of all observed file names associated with this Binary
-
Binary.
signed
¶ Returns True if the binary is signed.
-
Binary.
signing_data
¶ Returns
SigningData
object which contains: Digital Signature Result, Digital Signature publisher, Issuer, Subject, Signing Time, Program Name
-
Binary.
size
¶ Returns the size of the Binary
-
Binary.
version_info
¶ Returns a
VersionInfo
object containing detailed information: File Descritpion, File Version, Product Name, Product Version, Company Name, Legal Copyright, and Original FileName
-
Binary.
virustotal
¶ Returns a
VirusTotal
object containing detailed Virus Total information about this binary.
-
Binary.
webui_link
¶ Returns the Cb Response Web UI link associated with this Binary object
-
class
-
class
cbapi.response.models.
Sensor
(*args, **kwargs)¶ Represents a Sensor object in the Carbon Black server.
-
class
NetworkAdapter
(macaddr, ipaddr)¶ -
ipaddr
¶ Alias for field number 1
-
macaddr
¶ Alias for field number 0
-
-
Sensor.
activity_stats
¶ Returns a list of activity statistics from the associated Cb Response Sensor
-
Sensor.
dns_name
¶ Returns the DNS name associated with this sensor object. This is the same as ‘computer_dns_name’.
-
Sensor.
flush_events
()¶ Performs a flush of events for this Cb Response Sensor
Warning: This may cause a significant amount of network traffic from this sensor to the Cb Response Server
-
Sensor.
group
¶ Getter: Returns the sensor’s group id.
Setter: Allows access to set the sensor’s group id
-
Sensor.
hostname
¶ Returns the hostname associated with this sensor object. This is the same as ‘computer_name’
-
Sensor.
isolate
(timeout=None)¶ Turn on network isolation for this Cb Response Sensor.
This function will block and only return when the isolation is complete, or if a timeout is reached. By default, there is no timeout. You can specify a timeout period (in seconds) in the “timeout” parameter to this function. If a timeout is specified and reached before the sensor is confirmed isolated, then this function will throw a TimeoutError.
Returns: True if sensor is isolated Raises: TimeoutError – if sensor does not isolate before timeout is reached
-
Sensor.
lr_session
()¶ Retrieve a Live Response session object for this Sensor.
Returns: Live Response session object Return type: cbapi.live_response_api.LiveResponseSession
Raises: ApiError – if there is an error establishing a Live Response session for this Sensor
-
Sensor.
network_interfaces
¶ Returns a list of networks adapters on the sensor
-
Sensor.
os
¶ Returns the operating system display string of the sensor
-
Sensor.
queued_stats
¶ Returns a list of status and size of the queued event logs from the associated Cb Response Sensor
Example: >>> sensor_obj = c.select(Sensor).where("ip:192.168").first() >>> pprint.pprint(sensor_obj.queued_stats) [{u'id': u'355509', u'num_eventlog_bytes': u'0', u'num_eventlogs': u'0', u'num_storefile_bytes': u'0', u'num_storefiles': 0, u'sensor_id': 1, u'timestamp': u'2016-10-17 19:08:09.645294-05:00'}]
-
Sensor.
resource_status
¶ Returns a list of memory statistics used by the Cb Response Sensor
-
Sensor.
sid
¶ Security Identifier being used by the Cb Response Sensor
-
Sensor.
unisolate
(timeout=None)¶ Turn off network isolation for this Cb Response Sensor.
This function will block and only return when the isolation is removed, or if a timeout is reached. By default, there is no timeout. You can specify a timeout period (in seconds) in the “timeout” parameter to this function. If a timeout is specified and reached before the sensor is confirmed unisolated, then this function will throw a TimeoutError.
Returns: True if sensor is unisolated Raises: TimeoutError – if sensor does not unisolate before timeout is reached
-
Sensor.
webui_link
¶ Returns the Cb Response Web UI link associated with this Sensor
-
class
-
class
cbapi.response.models.
Feed
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a Feed object in the Carbon Black server.
-
actions
¶ Returns: Returns all FeedAction
objects associated with this feedReturn type: response.rest_api.Query
-
search_binaries
(min_score=None, max_score=None)¶ Perform a Binary search within this feed that satisfies min_score and max_score :param min_score: minimum feed score :param max_score: maximum feed score :return: Returns a
response.rest_api.Query
object within the appropriate search parameters for binaries :rtype:response.rest_api.Query
-
search_processes
(min_score=None, max_score=None)¶ Perform a Process search within this feed that satisfies min_score and max_score
Parameters: - min_score – minimum feed score
- max_score – maximum feed score
Returns: Returns a
response.rest_api.Query
object with the appropriate search parameters for processesReturn type: response.rest_api.Query
-
-
class
cbapi.response.models.
BannedHash
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a BannedHash object in the Carbon Black server.
-
class
cbapi.response.models.
Watchlist
(*args, **kwargs)¶ Represents a Watchlist object in the Carbon Black server.
Variables: - search_query – URL encoded search query associated with this watchlist.
- index_type – Index to search for this watchlist. Must be either ‘events’ (Processes) or ‘modules’ (Binaries)
-
facets
¶ Returns facets from the search associated with the watchlist query
Returns: dictionary of facets as keys Return type: dict
-
query
¶ Getter: Returns the query associated with this watchlist.
Setter: Allows access to set the query associated with this watchlist
-
search
()¶ Creates a search based on the watchlist’s search parameter
Returns: a Process response.rest_api.Query
or Binaryresponse.rest_api.Query
Return type: response.rest_api.Query
-
class
cbapi.response.models.
Alert
(cb, alert_id, initial_data=None)¶ Represents a Alert object in the Carbon Black server.
Live Response¶
-
class
cbapi.live_response_api.
CbLRSessionBase
(cblr_manager, session_id, sensor_id, session_data=None)¶
File Operations¶
-
CbLRSessionBase.
get_file
(file_name)¶ Retrieve contents of the specified file name
Parameters: file_name (str) – Name of the file Returns: Content of the specified file name Return type: str
-
CbLRSessionBase.
delete_file
(filename)¶ Delete the specified file name
Parameters: filename (str) – Name of the file Returns: None
-
CbLRSessionBase.
put_file
(infp, remote_filename)¶ Create a new file on the remote endpoint with the specified data
Example: >>> with c.select(Sensor, 1).lr_session() as lr_session: ... lr_session.put_file('File Data', new_remote_file)
Parameters: - infp (str) – File data to put on the remote endpoint
- remote_filename (str) – File name to create on the remote endpoint
Returns: None
-
CbLRSessionBase.
list_directory
(dir_name)¶ List the contents of a directory
Example: >>> with c.select(Sensor, 1).lr_session() as lr_session: ... pprint.pprint(lr_session.list_directory('C:\\temp\\')) [{u'attributes': [u'DIRECTORY'], u'create_time': 1471897244, u'filename': u'.', u'last_access_time': 1476390670, u'last_write_time': 1476390670, u'size': 0}, {u'attributes': [u'DIRECTORY'], u'create_time': 1471897244, u'filename': u'..', u'last_access_time': 1476390670, u'last_write_time': 1476390670, u'size': 0}, {u'attributes': [u'ARCHIVE'], u'create_time': 1476390668, u'filename': u'test.txt', u'last_access_time': 1476390668, u'last_write_time': 1476390668, u'size': 0}]
Parameters: dir_name (str) – Directory to list. This parameter should end with ‘’ Returns: Returns a directory listing Return type: list
-
CbLRSessionBase.
create_directory
(dir_name)¶ Create a directory on the remote endpoint
Parameters: dir_name (str) – New directory name Returns: None
-
CbLRSessionBase.
walk
(top, topdown=True, onerror=None, followlinks=False)¶ Perform a full directory walk with recursion into subdirectories
Example: >>> with c.select(Sensor, 1).lr_session() as lr_session: ... for entry in lr_session.walk(directory_name): ... print(entry) ('C:\temp\', [u'dir1', u'dir2'], [u'file1.txt'])
Parameters: - top (str) – Directory to recurse
- topdown (bool) – if True, start output from top level directory
- onerror (bool) – Callback if an error occurs. This function is called with one argument (the exception that occurred)
- followlinks (bool) – Follow symbolic links
Returns: Returns output in the follow tuple format: (Directory Name, [dirnames], [filenames])
Return type: tuple
Registry Operations¶
-
CbLRSessionBase.
get_registry_value
(regkey)¶ Returns the associated value of the specified registry key
Example: >>> with c.select(Sensor, 1).lr_session() as lr_session: >>> pprint.pprint(lr_session.get_registry_value('HKLM\SYSTEM\CurrentControlSet\services\ACPI\Start')) {u'value_data': 0, u'value_name': u'Start', u'value_type': u'REG_DWORD'}
Parameters: regkey (str) – The registry key to retrieve Returns: Returns a dictionary with keys of: value_data, value_name, value_type Return type: dict
-
CbLRSessionBase.
set_registry_value
(regkey, value, overwrite=True, value_type=None)¶ Set a registry value of the specified registry key
Example: >>> with c.select(Sensor, 1).lr_session() as lr_session: ... lr_session.set_registry_value('HKLM\\SYSTEM\\CurrentControlSet\\services\\ACPI\\testvalue', 1)
Parameters: - regkey (str) – They registry key to set
- value (obj) – The value data
- overwrite (bool) – Overwrite value if True
- value_type (str) – The type of value. Examples: REG_DWORD, REG_MULTI_SZ, REG_SZ
Returns: None
-
CbLRSessionBase.
delete_registry_value
(regkey)¶ Delete a registry value
Parameters: regkey (str) – the registry value to delete Returns: None
-
CbLRSessionBase.
create_registry_key
(regkey)¶ Create a new registry
Parameters: regkey (str) – The registry key to create Returns: None
-
CbLRSessionBase.
delete_registry_key
(regkey)¶ Delete a registry key
Parameters: regkey (str) – The registry key to delete Returns: None
-
CbLRSessionBase.
list_registry_keys_and_values
(regkey)¶ Enumerate subkeys and values of the specified registry key.
Example: >>> with c.select(Sensor, 1).lr_session() as lr_session: >>> pprint.pprint(lr_session.list_registry_keys_and_values('HKLM\SYSTEM\CurrentControlSet\services\ACPI')) {'sub_keys': [u'Parameters', u'Enum'], 'values': [{u'value_data': 0, u'value_name': u'Start', u'value_type': u'REG_DWORD'}, {u'value_data': 1, u'value_name': u'Type', u'value_type': u'REG_DWORD'}, {u'value_data': 3, u'value_name': u'ErrorControl', u'value_type': u'REG_DWORD'}, {u'value_data': u'system32\drivers\ACPI.sys', u'value_name': u'ImagePath', u'value_type': u'REG_EXPAND_SZ'}, {u'value_data': u'Microsoft ACPI Driver', u'value_name': u'DisplayName', u'value_type': u'REG_SZ'}, {u'value_data': u'Boot Bus Extender', u'value_name': u'Group', u'value_type': u'REG_SZ'}, {u'value_data': u'acpi.inf_x86_neutral_ddd3c514822f1b21', u'value_name': u'DriverPackageId', u'value_type': u'REG_SZ'}, {u'value_data': 1, u'value_name': u'Tag', u'value_type': u'REG_DWORD'}]}
Parameters: regkey (str) – The registry key to enumerate Returns: returns a dictionary with 2 keys (sub_keys and values) Return type: dict
-
CbLRSessionBase.
list_registry_keys
(regkey)¶ Enumerate all registry values from the specified registry key.
Parameters: regkey – The registry key to enumearte Returns: returns a list of values Return type: list
Process Operations¶
-
CbLRSessionBase.
kill_process
(pid)¶ Terminate a process on the remote endpoint
Parameters: pid – Process ID to terminate Returns: True if success, False if failure Return type: bool
-
CbLRSessionBase.
create_process
(command_string, wait_for_output=True, remote_output_file_name=None, working_directory=None, wait_timeout=30, wait_for_completion=True)¶ Create a new process with the specified command string.
Example: >>> with c.select(Sensor, 1).lr_session() as lr_session: ... print(lr_session.create_process(r'cmd.exe /c "ping.exe 192.168.1.1"')) Pinging 192.168.1.1 with 32 bytes of data: Reply from 192.168.1.1: bytes=32 time<1ms TTL=64
Parameters: - command_string (str) – command string used for the create process operation
- wait_for_output (bool) – Block on output from the new process (execute in foreground)
- remote_output_file_name (str) – The remote output file name used for process output
- working_directory (str) – The working directory of the create process operation
- wait_timeout (int) – Time out used for this live response command
- wait_for_completion (bool) – Wait until the process is completed before returning
Returns: returns the output of the command string
Return type: str
-
CbLRSessionBase.
list_processes
()¶ List currently running processes
Example: >>> with c.select(Sensor, 1).lr_session() as lr_session: ... print(lr_session.list_processes()[0]) {u'command_line': u'', u'create_time': 1476260500, u'parent': 0, u'parent_guid': u'00000001-0000-0000-0000-000000000000', u'path': u'', u'pid': 4, u'proc_guid': u'00000001-0000-0004-01d2-2461a85e4546', u'sid': u's-1-5-18', u'username': u'NT AUTHORITY\SYSTEM'}
Returns: returns a list of running processes Return type: list
Cb Protection API¶
This page documents the public interfaces exposed by cbapi when communicating with a Carbon Black Enterprise Protection server.
Main Interface¶
To use cbapi with Carbon Black Protection, you will be using the CbProtectionAPI. The CbProtectionAPI object then exposes two main methods to select data on the Carbon Black server:
-
class
cbapi.protection.rest_api.
CbProtectionAPI
(*args, **kwargs)¶ The main entry point into the Carbon Black Enterprise Protection API.
Parameters: profile (str) – (optional) Use the credentials in the named profile when connecting to the Carbon Black server. Uses the profile named ‘default’ when not specified. Usage:
>>> from cbapi import CbEnterpriseProtectionAPI >>> cb = CbEnterpriseProtectionAPI(profile="production")
-
create
(cls, data=None)¶ Creates a new object.
Parameters: cls (class) – The Model class (only some models can be created, for example, Feed, Notification, ...) Returns: An empty instance of the Model class Raises: ApiError – if the Model cannot be created
-
select
(cls, unique_id=None, *args, **kwargs)¶ Prepares a query against the Carbon Black data store.
Parameters: - cls (class) – The Model class (for example, Computer, Process, Binary, FileInstance) to query
- unique_id – (optional) The unique id of the object to retrieve, to retrieve a single object by ID
Returns: An instance of the Model class if a unique_id is provided, otherwise a Query object
-
Queries¶
-
class
cbapi.protection.rest_api.
Query
(doc_class, cb, query=None)¶ Represents a prepared query to the Carbon Black Enterprise Protection server.
This object is returned as part of a
CbEnterpriseProtectionAPI.select()
operation on models requested from the Carbon Black Enterprise Protection server. You should not have to create this class yourself.The query is not executed on the server until it’s accessed, either as an iterator (where it will generate values on demand as they’re requested) or as a list (where it will retrieve the entire result set and save to a list). You can also call the Python built-in
len()
on this object to retrieve the total number of items matching the query.The syntax for query :py:meth:where and :py:meth:sort methods can be found in the Enterprise Protection API reference posted on the Carbon Black Developer Network website.
Examples:
>>> from cbapi.protection import CbEnterpriseProtectionAPI, Computer >>> cb = CbEnterpriseProtectionAPI() >>> query = cb.select(Computer) # returns a Query object matching all Computers >>> query = query.where("ipAddress:10.201.2.*") # add a filter to this Query >>> query = query.sort("processorSpeed DESC") # sort by computer processor speed, descending >>> for comp in query: # uses the iterator to retrieve all results >>> print(comp.name) >>> comps = query[:10] # retrieve the first ten results >>> len(query) # retrieve the total count
- Notes:
- The slicing operator only supports start and end parameters, but not step.
[1:-1]
is legal, but[1:2:-1]
is not. - You can chain where clauses together to create AND queries; only objects that match all
where
clauses will be returned.
- The slicing operator only supports start and end parameters, but not step.
-
and_
(q)¶ Add a filter to this query. Equivalent to calling
where()
on this object.Parameters: q (str) – Query string - see the Enterprise Protection API reference. Returns: Query object Return type: Query
-
sort
(new_sort)¶ Set the sort order for this query.
Parameters: new_sort (str) – Sort order - see the Enterprise Protection API reference. Returns: Query object Return type: Query
-
where
(q)¶ Add a filter to this query.
Parameters: q (str) – Query string - see the Enterprise Protection API reference. Returns: Query object Return type: Query
Models¶
-
class
cbapi.protection.models.
AppCatalog
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a AppCatalog object in the Carbon Black server.
-
urlobject
= '/api/bit9platform/v1/appCatalog'¶
-
-
class
cbapi.protection.models.
AppTemplate
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a AppTemplate object in the Carbon Black server.
-
urlobject
= '/api/bit9platform/v1/appTemplate'¶
-
-
class
cbapi.protection.models.
ApprovalRequest
(cb, model_unique_id, initial_data=None)¶ -
ResolutionApproved
= 2¶
-
ResolutionInstaller
= 4¶
-
ResolutionNotResolved
= 0¶
-
ResolutionOther
= 7¶
-
ResolutionPublisher
= 6¶
-
ResolutionRejected
= 1¶
-
ResolutionRuleChange
= 3¶
-
ResolutionUpdater
= 5¶
-
StatusClosed
= 3¶
-
StatusOpen
= 2¶
-
StatusSubmitted
= 1¶
-
computer
¶
-
fileCatalog
¶
-
installerFileCatalog
¶
-
processFileCatalog
¶
-
urlobject
= '/api/bit9platform/v1/approvalRequest'¶
-
-
class
cbapi.protection.models.
Certificate
(cb, model_unique_id, initial_data=None)¶ -
StateApproved
= 2¶
-
StateBanned
= 3¶
-
StateMixed
= 4¶
-
StateUnapproved
= 1¶
-
firstSeenComputer
¶
-
parent
¶
-
publisher
¶
-
urlobject
= '/api/bit9platform/v1/certificate'¶
-
-
class
cbapi.protection.models.
Computer
(cb, model_unique_id, initial_data=None)¶ Represents a Computer object in the Carbon Black server.
-
fileInstances
¶
-
policy
¶
-
resetCLIPassword
()¶
-
template
¶
-
urlobject
= '/api/bit9platform/v1/computer'¶
-
-
class
cbapi.protection.models.
Connector
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a Connector object in the Carbon Black server.
Variables: - analysisEnabled – True if analysis component of this connector is enabled
- isInternal – True if this is internal connector
- analysisName – Name for analysis component of the connector (can be same as the name field)
- connectorVersion – Version of this connector
- name – Name of the connector. Note that only non-internal connectors can be renamed
- analysisTargets – Array of possible analysis targets. Analysis targets are required when creating new fileAnalysis. They usualy represent different OS and configurations and are available only for some internal connectors.
- id – Unique connector Id
- canAnalyze – True if this connector can analyze files
- enabled – True if connector is enabled
-
analysisEnabled
= None¶
-
analysisName
= None¶
-
analysisTargets
= []¶
-
canAnalyze
= None¶
-
connectorVersion
= None¶
-
enabled
= None¶
-
id
= None¶
-
isInternal
= None¶
-
name
= None¶
-
pendingAnalyses
¶
-
urlobject
= '/api/bit9platform/v1/connector'¶
-
class
cbapi.protection.models.
DriftReport
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a DriftReport object in the Carbon Black server.
-
urlobject
= '/api/bit9platform/v1/driftReport'¶
-
-
class
cbapi.protection.models.
DriftReportContents
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a DriftReportContents object in the Carbon Black server.
-
urlobject
= '/api/bit9platform/v1/driftReportContents'¶
-
-
class
cbapi.protection.models.
EnforcementLevel
¶ -
LevelHigh
= 20¶
-
LevelLow
= 40¶
-
LevelMedium
= 30¶
-
LevelNone
= 80¶
-
-
class
cbapi.protection.models.
Event
(cb, model_unique_id, initial_data=None)¶ Represents a Event object in the Carbon Black server.
-
fileCatalog
¶
-
urlobject
= '/api/bit9platform/v1/event'¶
-
-
class
cbapi.protection.models.
FileAnalysis
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/fileAnalysis'¶
-
-
class
cbapi.protection.models.
FileCatalog
(cb, model_unique_id, initial_data=None)¶ Represents a FileCatalog object in the Carbon Black server.
-
certificate
¶
-
computer
¶
-
fileHash
¶
-
publisher
¶
-
urlobject
= '/api/bit9platform/v1/fileCatalog'¶
-
-
class
cbapi.protection.models.
FileInstance
(cb, model_unique_id, initial_data=None)¶ Represents a FileInstance object in the Carbon Black server.
-
computer
¶
-
fileCatalog
¶
-
urlobject
= '/api/bit9platform/v1/fileInstance'¶
-
-
class
cbapi.protection.models.
FileInstanceDeleted
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/fileInstanceDeleted'¶
-
-
class
cbapi.protection.models.
FileInstanceGroup
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/fileInstanceGroup'¶
-
-
class
cbapi.protection.models.
FileRule
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a FileRule object in the Carbon Black server.
Variables: - fileName – File name associated with this rule. Note that file name will be available only if rule was created through file name. If rule was created through fileCatalogId or hash, this field will be empty.
- visible – If rule should be visible in the UI or not
- createdBy – User that created this object
- description – Description of this rule.
- reputationApprovalsEnabled – True if reputation approvals are enabled for this file
- hash – Hash associated with this rule. Note that hash will be available only if rule was created through md5 or sha-1 hash. If rule was created through fileName, fileCatalogId or sha-256 hash that exists in the catalog, this field will be empty.
- policyIds – List of IDs of policies where this rule applies. Value will be empty if this is a global rule
- sourceId – Id of source of this rule. Can be event rule id or trusted directory id
- modifiedByUserId – Id of user that last modified this object
- unifiedFlag – Local override flag for unified rule (0 - if rule is not unified, 1 - no override allowed, 3 - local override allowed)
- sourceType – Mechanism that created this rule. Can be one of: 1 = Manual 2 = Trusted Directory 3 = Reputation 4 = Imported 5 = External (API) 6 = Event Rule 7 = Application Template 8 = Unified Management
- unifiedSource – Unified server name that created this rule
- dateModified – Date/time when this object was last modified (UTC)
- modifiedBy – User that last modified this object
- idUnique – Unique GUID of this rule
- forceNotInstaller – True if this file is forced to act as ‘not installer’, even if product detected it as installer
- name – Name of this rule.
- fileRuleType – Text description of file rule type
- clVersion – CL version associated with this file rule
- forceInstaller – True if this file is forced to act as installer, even if product detected it as ‘not installer’
- dateCreated – Date/time when this rule was created (UTC)
- lazyApproval – This filed is valid only when creating approvals. When set to true, it will cause approval to be sent to agent only if file is marked as installer or if it blocked on any agent. This is useful when proactively creating lot of approvals that might or might not be required, since it is using less resources. Note that, as soone as lazy approval is sent to agents, this field will changed to ‘false’.
- fileCatalogId – Id of fileCatalog entry associated with this fileRule. Can be null if file hasn’t been seen on any endpoints yet. This is foreign key and can be expanded to expose fields from the related fileCatalog object
- id – Unique id of this fileRule
- origIdUnique – Unique GUID of the original rule
- version – Version of this file rule
- platformFlags – Set of platform flags where this file rule will be valid. combination of: 1 = Windows 2 = Mac 4 = Linux
- createdByUserId – Id of user that created this object
- reportOnly – True if this has a report-only ban
- fileState – File state for this rule. Can be one of: 1=Unapproved 2=Approved 3=Banned
-
PlatformLinux
= 4¶
-
PlatformMac
= 2¶
-
PlatformWindows
= 1¶
-
SourceTypeApplicationTemplate
= 7¶
-
SourceTypeEventRule
= 6¶
-
SourceTypeExternal
= 5¶
-
SourceTypeImported
= 4¶
-
SourceTypeManual
= 1¶
-
SourceTypeReputation
= 3¶
-
SourceTypeTrustedDirectory
= 2¶
-
SourceTypeUnifiedManagement
= 8¶
-
StateApproved
= 2¶
-
StateBanned
= 3¶
-
StateUnapproved
= 1¶
-
clVersion
= None¶
-
createdBy
= None¶
-
createdByUser
¶
-
createdByUserId
= None¶
-
dateCreated
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
dateModified
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
description
= None¶
-
fileCatalog
¶
-
fileCatalogId
= None¶
-
fileName
= None¶
-
fileRuleType
= None¶
-
fileState
= None¶
-
forceInstaller
= None¶
-
forceNotInstaller
= None¶
-
hash
= None¶
-
id
= None¶
-
idUnique
= None¶
-
lazyApproval
= None¶
-
modifiedBy
= None¶
-
modifiedByUserId
= None¶
-
name
= None¶
-
origIdUnique
= None¶
-
platformFlags
= None¶
-
policyIds
= None¶
-
reportOnly
= None¶
-
reputationApprovalsEnabled
= None¶
-
sourceId
= None¶
-
sourceType
= None¶
-
unifiedFlag
= None¶
-
unifiedSource
= None¶
-
urlobject
= '/api/bit9platform/v1/fileRule'¶
-
version
= None¶
-
visible
= None¶
-
class
cbapi.protection.models.
FileUpload
(cb, model_unique_id, initial_data=None)¶ -
file
¶
-
urlobject
= '/api/bit9platform/v1/fileUpload'¶
-
-
class
cbapi.protection.models.
GrantedUserPolicyPermission
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a GrantedUserPolicyPermission object in the Carbon Black server.
-
urlobject
= '/api/bit9platform/v1/grantedUserPolicyPermission'¶
-
-
class
cbapi.protection.models.
InternalEvent
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/fileInstance'¶
-
-
class
cbapi.protection.models.
MeteredExecution
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/meteredExecution'¶
-
-
class
cbapi.protection.models.
Notification
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a Notification object in the Carbon Black server.
Variables: - fileAnalysisId – Id of fileAnalysis object associated with the notification. This should be available if notification came as a result of the file analysis
- connectorId – Id of connector object that sent the notification
- time – Date/time of the notification (UTC)
- analysisResult – Analysis result. Can be one of: 0 = Unknown, 1 = Not malicious, 2 = Potential risk, 3 = Malicious
-
ResultClean
= 1¶
-
ResultMalicious
= 3¶
-
ResultNotAvailable
= 0¶
-
ResultPotentialThreat
= 2¶
-
analysisResult
= None¶
-
anomaly
= None¶
-
appliance
= None¶
-
connectorId
= None¶
-
destIp
= None¶
-
destUsername
= None¶
-
directories
= []¶
-
externalId
= None¶
-
externalUrl
= None¶
-
fileAnalysisId
= None¶
-
fileName
= None¶
-
files
= []¶
-
flags
= None¶
-
httpHeader
= None¶
-
malwareName
= None¶
-
malwareType
= None¶
-
md5
= None¶
-
msgFormat
= None¶
-
product
= None¶
-
regKeys
= []¶
-
severity
= None¶
-
sha1
= None¶
-
sha256
= None¶
-
srcHost
= None¶
-
srcIp
= None¶
-
srcUsername
= None¶
-
status
= None¶
-
targetApp
= None¶
-
targetOS
= None¶
-
time
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
type
= None¶
-
urlobject
= '/api/bit9platform/v1/notification'¶
-
version
= None¶
-
class
cbapi.protection.models.
Notifier
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/notifier'¶
-
-
class
cbapi.protection.models.
PendingAnalysis
(cb, model_unique_id, initial_data=None)¶ -
ResultClean
= 1¶
-
ResultMalicious
= 3¶
-
ResultNotAvailable
= 0¶
-
ResultPotentialThreat
= 2¶
-
StatusAnalyzed
= 3¶
-
StatusCancelled
= 5¶
-
StatusError
= 4¶
-
StatusProcessed
= 2¶
-
StatusScheduled
= 0¶
-
StatusSubmitted
= 1¶
-
create_notification
(**kwargs)¶
-
file
¶
-
fileCatalog
¶
-
fileHash
¶
-
urlobject
= '/api/bit9platform/v1/pendingAnalysis'¶
-
-
class
cbapi.protection.models.
Policy
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a Policy object in the Carbon Black server.
Variables: - packageName – Name of installer package for this policy
- disconnectedEnforcementLevel – Target enforcement level for disconnected computers. Can be one of: 20=High (Block Unapproved) 30=Medium (Prompt Unapproved) 40=Low (Monitor Unapproved) 60=None (Visibility) 80=None (Disabled)
- dateCreated – Date/time when this rule was created (UTC)
- fileTrackingEnabled – True if file tracking enabled in this policy
- automatic – True if AD mapping is enabled for this policy
- customLogo – True if notifiers in this policy use custom logo
- allowAgentUpgrades – True if agents can be upgraded for this policy
- description – Description of this policy.
- readOnly – True if this policy is read-only
- reputationEnabled – True if reputation approvals are enabled in this policy
- loadAgentInSafeMode – True if agents in this policy will be loaded when machine is booted in ‘safe mode’
- modifiedByUserId – Id of user that last modified this object
- hidden – True if this policy is hidden in the UI
- atEnforcementComputers – Number of computers that are at target enforcement level in this policy
- dateModified – Date/time when this object was last modified (UTC)
- connectedComputers – Number of connected computers in this policy
- imageUrl – Image logo URL for notifiers in this policy
- totalComputers – Total number of computers in this policy
- name – Name of this policy.
- clVersionMax – Max target CL version for agents in this policy
- helpDeskUrl – Helpdesk URL for notifiers in this policy
- enforcementLevel – Target enforcement level. Can be one of: 20=High (Block Unapproved) 30=Medium (Prompt Unapproved) 40=Low (Monitor Unapproved) 60=None (Visibility) 80=None (Disabled)
- automaticApprovalsOnTransition – True if agents in this policy will automatically locally approve files when transitioning into High Enforcement
- createdByUserId – Id of user that created this object
- id – Unique id of this policy
-
allowAgentUpgrades
= None¶
-
atEnforcementComputers
= None¶
-
automatic
= None¶
-
automaticApprovalsOnTransition
= None¶
-
clVersionMax
= None¶
-
connectedComputers
= None¶
-
createdByUserId
= None¶
-
customLogo
= None¶
-
dateCreated
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
dateModified
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
description
= None¶
-
disconnectedEnforcementLevel
= None¶
-
enforcementLevel
= None¶
-
fileTrackingEnabled
= None¶
-
helpDeskUrl
= None¶
-
id
= None¶
-
imageUrl
= None¶
-
loadAgentInSafeMode
= None¶
-
modifiedByUserId
= None¶
-
name
= None¶
-
packageName
= None¶
-
readOnly
= None¶
-
reputationEnabled
= None¶
-
totalComputers
= None¶
-
urlobject
= '/api/bit9platform/v1/policy'¶
-
class
cbapi.protection.models.
Publisher
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/publisher'¶
-
-
class
cbapi.protection.models.
PublisherCertificate
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a PublisherCertificate object in the Carbon Black server.
-
urlobject
= '/api/bit9platform/v1/publisherCertificate'¶
-
-
class
cbapi.protection.models.
ScriptRule
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a ScriptRule object in the Carbon Black server.
-
urlobject
= '/api/bit9platform/v1/scriptRule'¶
-
-
class
cbapi.protection.models.
ServerConfig
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/serverConfig'¶
-
-
class
cbapi.protection.models.
ServerPerformance
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/serverPerformance'¶
-
-
class
cbapi.protection.models.
TrustedDirectory
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a TrustedDirectory object in the Carbon Black server.
-
urlobject
= '/api/bit9platform/v1/trustedDirectory'¶
-
-
class
cbapi.protection.models.
TrustedUser
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a TrustedUser object in the Carbon Black server.
Variables: - clVersion – CL version associated with this trustedUser
- modifiedBy – User that last modified this object
- userSid – Id of the user that will be trusted on the endpoint. This field can be user name, user SID (Security identifier) on Windows platforms or user’s ID on Linux and Mac platforms
- dateCreated – Date/time when this object was created (UTC)
- createdBy – User that created this object
- description – Description of this rule
- dateModified – Date/time when this object was last modified (UTC)
- name – Name of the user as it will appear on the console. This is not the name that will be enforced on the endpoint
- id – Unique id of this trustedUser
- modifiedByUserId – Id of user that last modified this object. This is foreign key and can be expanded to expose fields from the related user object
- createdByUserId – Id of user that created this object. This is foreign key and can be expanded to expose fields from the related user object
- platformId – Platform where this trustedUser will be valid. it is one of: 1 = Windows, 2 = Mac, 4 = Linux
-
clVersion
= None¶
-
createdBy
= None¶
-
createdByUserId
= None¶
-
dateCreated
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
dateModified
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
description
= None¶
-
id
= None¶
-
modifiedBy
= None¶
-
modifiedByUserId
= None¶
-
name
= None¶
-
platformId
= None¶
-
urlobject
= '/api/bit9platform/v1/trustedUser'¶
-
userSid
= None¶
-
class
cbapi.protection.models.
Updater
(cb, model_unique_id, initial_data=None)¶ -
urlobject
= '/api/bit9platform/v1/updater'¶
-
-
class
cbapi.protection.models.
User
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a User object in the Carbon Black server.
Variables: - title – Title of this user
- userGroupIds – Comma-separated list of IDs of corresponding userGroup objects
- backupPager – User’s secondary pager number
- lastName – Last name of this user
- passwordSalt – Salt used to generate password hash
- apiToken – API token for this user
- unified – True if this user’s token is already connected to a remote unified environment (token should not be changed)
- id – Unique id of this user
- comments – Comments for this user
- pager – User’s pager number
- cellPhone – User’s cell phone
- adminComments – Administrator’s comments for this user
- registrationDate – Date this user was first registered (UTC)
- homePhone – User’s home phone
- firstName – First name of this user
- department – Department this user belongs to
- automatic – True if this user’s roles are assigned automatically through mappings (valid only for external users)
- name – Name of the user
- readOnly – True if this user is one of internal users (System or Cb Collective Defense Cloud Service) or AD user. These users cannot be modified through the API
- enabled – True if this user is enabled
- backupCellPhone – User’s secondary cell phone
- eMailAddress – EMail address of this user
- passwordHash – Hash of user password
- salutation – Salutation of this user
- external – True if this is externally generated user (e.g. from AD)
-
adminComments
= None¶
-
apiToken
= None¶
-
automatic
= None¶
-
backupCellPhone
= None¶
-
backupPager
= None¶
-
cellPhone
= None¶
-
comments
= None¶
-
department
= None¶
-
eMailAddress
= None¶
-
enabled
= None¶
-
external
= None¶
-
firstName
= None¶
-
homePhone
= None¶
-
id
= None¶
-
lastName
= None¶
-
name
= None¶
-
pager
= None¶
-
passwordHash
= None¶
-
passwordSalt
= None¶
-
readOnly
= None¶
-
registrationDate
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
salutation
= None¶
-
title
= None¶
-
unified
= None¶
-
urlobject
= '/api/bit9platform/v1/user'¶
-
userGroupIds
= None¶
-
class
cbapi.protection.models.
UserGroup
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a UserGroup object in the Carbon Black server.
Variables: - dateModified – Date/time when this object was last modified (UTC)
- modifiedBy – User that last modified this object
- editable – True if this userGroup is editable
- policyIds – List of IDs of policies where this user group applies. Value will be empty if this is a global user group
- createdByUserId – Id of user that created this object. This is foreign key and can be expanded to expose fields from the related user object
- description – Description of this user group
- automaticCount – Number of users that belong to this group and have been assigned through AD rule (doesn’t include internal users)
- dateCreated – Date/time when this object was created (UTC)
- manualCount – Number of users that belong to this group and have been assigned manually (doesn’t include internal users)
- createdBy – User that created this object
- id – Unique id of this user group
- modifiedByUserId – Id of user that last modified this object. This is foreign key and can be expanded to expose fields from the related user object
- permissions – Permissions associated with users of this user group as a hexadecimal string. See https://developer.carbonblack.com/reference/enterprise-protection/8.0/rest-api/#usergroup for more information.
- name – Name of the user group
- enabled – True if this userGroup is enabled
-
automaticCount
= None¶
-
createdBy
= None¶
-
createdByUserId
= None¶
-
dateCreated
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
dateModified
= datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzlocal())¶
-
description
= None¶
-
editable
= None¶
-
enabled
= None¶
-
id
= None¶
-
manualCount
= None¶
-
modifiedBy
= None¶
-
modifiedByUserId
= None¶
-
name
= None¶
-
permissions
= None¶
-
policyIds
= None¶
-
urlobject
= '/api/bit9platform/v1/userGroup'¶
Cb Defense API¶
This page documents the public interfaces exposed by cbapi when communicating with a Cb Defense server.
Main Interface¶
To use cbapi with Carbon Black Defense, you will be using the CbDefenseAPI. The CbDefenseAPI object then exposes two main methods to select data on the Carbon Black server:
-
class
cbapi.defense.rest_api.
CbDefenseAPI
(*args, **kwargs)¶ The main entry point into the Cb Defense API.
Parameters: profile (str) – (optional) Use the credentials in the named profile when connecting to the Carbon Black server. Uses the profile named ‘default’ when not specified. Usage:
>>> from cbapi import CbDefenseAPI >>> cb = CbDefenseAPI(profile="production")
-
create
(cls, data=None)¶ Creates a new object.
Parameters: cls (class) – The Model class (only some models can be created, for example, Feed, Notification, ...) Returns: An empty instance of the Model class Raises: ApiError – if the Model cannot be created
-
get_notifications
()¶ Retrieve queued notifications (alerts) from the Cb Defense server. Note that this can only be used with a ‘SIEM’ key generated in the Cb Defense console.
Returns: list of dictionary objects representing the notifications, or an empty list if none available.
-
notification_listener
(interval=60)¶ Generator to continually poll the Cb Defense server for notifications (alerts). Note that this can only be used with a ‘SIEM’ key generated in the Cb Defense console.
-
select
(cls, unique_id=None, *args, **kwargs)¶ Prepares a query against the Carbon Black data store.
Parameters: - cls (class) – The Model class (for example, Computer, Process, Binary, FileInstance) to query
- unique_id – (optional) The unique id of the object to retrieve, to retrieve a single object by ID
Returns: An instance of the Model class if a unique_id is provided, otherwise a Query object
-
Queries¶
-
class
cbapi.defense.rest_api.
Query
(doc_class, cb, query=None)¶ Represents a prepared query to the Cb Defense server.
This object is returned as part of a
CbDefenseAPI.select()
operation on models requested from the Cb Defense server. You should not have to create this class yourself.The query is not executed on the server until it’s accessed, either as an iterator (where it will generate values on demand as they’re requested) or as a list (where it will retrieve the entire result set and save to a list). You can also call the Python built-in
len()
on this object to retrieve the total number of items matching the query.Examples:
>>> from cbapi.defense import CbDefenseAPI >>> cb = CbDefenseAPI()
- Notes:
- The slicing operator only supports start and end parameters, but not step.
[1:-1]
is legal, but[1:2:-1]
is not. - You can chain where clauses together to create AND queries; only objects that match all
where
clauses will be returned.
- The slicing operator only supports start and end parameters, but not step.
-
and_
(q)¶ Add a filter to this query. Equivalent to calling
where()
on this object.Parameters: q (str) – Query string Returns: Query object Return type: Query
-
where
(q)¶ Add a filter to this query.
Parameters: q (str) – Query string Returns: Query object Return type: Query
Models¶
-
class
cbapi.defense.models.
DefenseMutableModel
(cb, model_unique_id=None, initial_data=None, force_init=False, full_doc=False)¶ Represents a DefenseMutableModel object in the Carbon Black server.
-
class
cbapi.defense.models.
Device
(cb, model_unique_id, initial_data=None)¶ Represents a Device object in the Carbon Black server.
-
activationCode
= None¶
-
activationCodeExpiryTime
= None¶
-
assignedToId
= None¶
-
assignedToName
= None¶
-
avEngine
= None¶
-
avLastScanTime
= None¶
-
avMaster
= None¶
-
avStatus
= []¶
-
avUpdateServers
= []¶
-
createTime
= None¶
-
deregisteredTime
= None¶
-
deviceGuid
= None¶
-
deviceId
= None¶
-
deviceOwnerId
= None¶
-
deviceSessionId
= None¶
-
deviceType
= None¶
-
email
= None¶
-
firstName
= None¶
-
firstVirusActivityTime
= None¶
-
info_key
= 'deviceInfo'¶
-
lastContact
= None¶
-
lastExternalIpAddress
= None¶
-
lastInternalIpAddress
= None¶
-
lastLocation
= None¶
-
lastName
= None¶
-
lastReportedTime
= None¶
-
lastResetTime
= None¶
-
lastShutdownTime
= None¶
-
lastVirusActivityTime
= None¶
-
linuxKernelVersion
= None¶
-
lr_session
()¶ Retrieve a Live Response session object for this Device.
Returns: Live Response session object Return type: cbapi.defense.cblr.LiveResponseSession
Raises: ApiError – if there is an error establishing a Live Response session for this Device
-
messages
= []¶
-
middleName
= None¶
-
name
= None¶
-
organizationId
= None¶
-
organizationName
= None¶
-
osVersion
= None¶
-
passiveMode
= None¶
-
policyId
= None¶
-
policyName
= None¶
-
primary_key
= 'deviceId'¶
-
quarantined
= None¶
-
registeredTime
= None¶
-
rootedByAnalytics
= None¶
-
rootedByAnalyticsTime
= None¶
-
rootedBySensor
= None¶
-
rootedBySensorTime
= None¶
-
scanLastActionTime
= None¶
-
scanLastCompleteTime
= None¶
-
scanStatus
= None¶
-
sensorStates
= []¶
-
sensorVersion
= None¶
-
status
= None¶
-
targetPriorityType
= None¶
-
testId
= None¶
-
uninstalledTime
= None¶
-
urlobject
= '/integrationServices/v3/device'¶
-
vdiBaseDevice
= None¶
-
windowsPlatform
= None¶
-
Exceptions¶
If an error occurs, the API attempts to roll the error into an appropriate Exception class.
Exception Classes¶
-
exception
cbapi.errors.
ApiError
(message=None, original_exception=None)¶
-
exception
cbapi.errors.
CredentialError
(message=None, original_exception=None)¶
-
exception
cbapi.errors.
ServerError
(error_code, message, result=None, original_exception=None)¶ A ServerError is raised when an HTTP error code is returned from the Carbon Black server.
-
exception
cbapi.errors.
ObjectNotFoundError
(uri, message=None, original_exception=None)¶ The requested object could not be found in the Carbon Black datastore.
-
exception
cbapi.errors.
MoreThanOneResultError
(message=None, original_exception=None)¶ Only one object was requested, but multiple matches were found in the Carbon Black datastore.
-
exception
cbapi.errors.
InvalidObjectError
(message=None, original_exception=None)¶
-
exception
cbapi.errors.
TimeoutError
(uri=None, error_code=None, message=None, original_exception=None)¶