OpenCTI #4 - Connectors

Discover OpenCTI in this series. This fourth post will discuss connectors to add, enrich or share data on the platform.

OpenCTI's connectors panel
OpenCTI's connectors panel

You heard about them in the previous posts on OpenCTI, notably in the administration guide. Now this is the time to dig deeper on what makes the OpenCTI platform so powerful: connectors.

Connectors are little programs that connect to OpenCTI's dedicated API. They can import or export data in bulk and directly change data on the platform. A set of connectors is already defined on the platform by default. You can see them in Data -> Connectors.

Connectors will interact with OpenCTI to keep their state, authenticate and fulfill their role. To keep their state they can use a data slot dedicated to each connector. It can contain a brief JSON document. Most of the time, a connector will keep a cursor or a last run time to only download new data.

It is possible to reset the state of any connector by clicking the associated button in the Connectors interface. The color of the connector at the beginning of the line shows if the connector is still live or not.

Connectors will also have works associated. Works correspond to data that is not completely committed in the platform yet. They can also be controlled from the platform interface, this is useful if one was to hang.

Configure a connector

If you adhered to the guide, you do not have yet basic data with which you could work. We can remediate to that by adding the OpenCTI connector (which provides basic data such as country information and not any connection to another OpenCTI instance as one could think) and the MITRE connector (which provides the Att&ck Enterprise framework data).

Let's start with the OpenCTI connector. The same principles will apply with the MITRE connector so this will be let to you as an exercise.

Most of OpenCTI's connectors are available in a unique Github repository. They are grouped by type:

  • external-import: connectors that automatically fetch data from external sources to feed it into OpenCTI
  • internal-enrichement: connectors that fetch data from external sources to enrich already existing data. This is typically used by users when clicking the enrichment buttons
  • internal-export-file: connectors that allow to export data from OpenCTI to a file. They are triggered when a user asks for an export from the platform
  • internal-import-file: connectors that allow to import data from a file. They are triggered when a user imports a file into the platform
  • stream: connectors adapting OpenCTI data sharing streams, typically used to send data to tools incompatible with standard feeds (SIEMs, SOARs, ...)

Both the OpenCTI and the MITRE connectors are under the external-import type, so go to external-import -> opencti. You will be greeted by a brief documentation.

The most practical way to run connectors is using Docker. In my deployments I like to have at least 2 stacks: one for OpenCTI and on for its connectors. This way, I don't have to restart OpenCTI everytime I want to update a connector.

Unfortunately, not every connector is well-documented. Most of the time, you'll have to look for parameters in the docker-compose.yml file or even the source code. If we look into the docker-compose.yml file, we'll see parameters not specified into the brief documentation.

Most parameters are self-explanatory. I will only dive in the few that you will find in nearly all connectors:

  • OPENCTI_URL: the base URL of your OpenCTI platform. In a Docker Stack, it may be more efficient to use the internal Docker hostname (e.g. http://opencti:8000)
  • OPENCTI_TOKEN: the token that will be used by the connector to authenticate against OpenCTI's API, it is provided on the user administration page
  • CONNECTOR_ID: the connector ID is an UUIDv4 identifier that you have to generate randomly. It uniquely identifies the connector on the platform (in some circumstances you will have several times the same connector running but with different parameters)
  • CONNECTOR_TYPE: specifies the type of the connector. Constant for a given connector to my knowledge (e.g. EXTERNAL_IMPORT)
  • CONNECTOR_NAME: human name for the connector. This name will be displayed in the Connectors tab in the GUI
  • CONNECTOR_SCOPE: object types that will be affected by the connector

As you see above, we'll need a token to authenticate. A default role and group already exist in the platform for connectors. So let's first create a user a put it into this group (Settings -> Security -> Users):

💡
Some connectors require the token of the built-in administrator user. Most of them are already specified in the official OpenCTI docker-compose.yml file. Generally speaking it is better to apply the principle of least privilege and only allow necessary permissions for the connector as any user.

Note that when creating the user there are 3 things to keep in mind:

  • The user is first assigned to the default group, you have to modify it to put it into the Connectors group
  • You have to set up a password, even if it won't be used: so use a password generator, and forget it
  • You'll want to keep a consistent naming convention. I use the [C] pattern for connectors and [S] for stream access accounts

Once the user is created and properly assigned to a group, you will be able to copy its token to use it in the connector configuration:

Authentication token displayed for a user

Let's implement our new connector (for my example, I will use the same stack as the OpenCTI one but remember to put them apart in production). I'll add the following configuration:

connector-opencti:
    image: opencti/connector-opencti:5.11.13
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=ac2f3df4-d8f0-43f7-999a-b0d55bcb8d85 # The token from the user page
      - CONNECTOR_ID=cfc052aa-a068-46bc-8202-6aeae5ede425 # A random UUIDv4 you should generate for each new connector
      - CONNECTOR_TYPE=EXTERNAL_IMPORT
      - "CONNECTOR_NAME=OpenCTI Datasets"
      - CONNECTOR_SCOPE=marking-definition,identity,location
      - CONNECTOR_CONFIDENCE_LEVEL=100
      - CONNECTOR_UPDATE_EXISTING_DATA=true
      - CONNECTOR_RUN_AND_TERMINATE=false
      - CONNECTOR_LOG_LEVEL=error
      - CONFIG_SECTORS_FILE_URL=https://raw.githubusercontent.com/OpenCTI-Platform/datasets/master/data/sectors.json
      - CONFIG_GEOGRAPHY_FILE_URL=https://raw.githubusercontent.com/OpenCTI-Platform/datasets/master/data/geography.json
      - CONFIG_COMPANIES_FILE_URL=https://raw.githubusercontent.com/OpenCTI-Platform/datasets/master/data/companies.json
      - CONFIG_REMOVE_CREATOR=false
      - CONFIG_INTERVAL=7 # In days
    restart: always

Relaunch the stack and... that's it! Your new connector should appear under Data -> Connectors:

Our new connector in action in the GUI

It will process messages just after launch because it will automatically download and import datasets. You can see its status by clicking on it:

Connector details

On the screenshot above you'll see:

  • The connector type
  • The State of the connector (here the last run date)
  • The queues used for data processing (each connector has dedicated queues)
  • The works in progress and the ones finished. Here we have one specifying that we processed 723 objects

Getting back in the platform objects you will see populated:

  • Some well-known organizations
  • World regions
  • Countries
  • Sectors
Example of an imported country

We still miss basic data such as attack patterns, well-known intrusion sets and malware. Those can be provided using the MITRE connector. I will let you install it as an exercise. Just know that this is an external-import connector.

Example of an attack-pattern object imported by the MITRE connector
💡
Compared to the OpenCTI Datasets connector, the MITRE connector imports way more data. It will take longer for the platform to process the whole dataset.

Connector baseline

Along the OpenCTI and MITRE connectors, there is a set of connectors I like to think as a baseline to get a first dataset and basic enrichment features on which you can work later:

  • Obviously: OpenCTI and MITRE
  • CVE (external-import): imports the whole National Vulnerability Database. A way to get all existing CVEs into the vulnerability database
  • CISA (external-import): gets more details on vulnerabilities that are known to be exploited from the Know Exploited Vulnerabilities catalog
  • Malpedia (external-import): gets knowledge on malware and intrusion sets
  • google-dns (internal-enrichment): allows to automatically resolve domain observable by adding the associated IP address observables and the resolves-to relationships
  • All import and export connectors provided in the official docker-compose.yml file

Conclusion

Connectors provide a powerful way to kickstart a platform and automatically ingest, enrich and export data. They can assist you in many ways but take care to carefully select your connectors and their configuration as they have a significant impact on the integrity of the data.

Next, we'll get back into the platform to discover how to handle containers such as reports and groupings.