OpenCTI

Two OpenCTI connectors for Stairwell. One enriches files, domains, IPs and ASNs on demand; the other imports the files Stairwell judges malicious as indicators on a schedule.

Stairwell publishes two connectors for OpenCTI, the open-source threat intelligence platform. The Stairwell enrichment connector adds Stairwell's verdict, AI triage, variants, and infrastructure history to a file, domain, IP address, or autonomous system already in OpenCTI. The Stairwell Import connector brings the files Stairwell has judged malicious into OpenCTI as indicators, on a schedule you set. Both are part of the official OpenCTI connector catalog and run as containers beside your platform.

You can run either one on its own. Most teams start with enrichment, because it answers questions about indicators they already hold, and add the import once they know how much volume they want flowing in.

What does each connector do?

Stairwell (enrichment)Stairwell Import
OpenCTI typeInternal enrichmentExternal import
RunsWhen an analyst or a playbook asks, or automatically on new observables if you turn that onOn a schedule, once a day by default
Works onFiles, domain names, IPv4 and IPv6 addresses, autonomous systemsThe files Stairwell judges malicious that your token can see
Adds to OpenCTIA score, labels, and notes on the observable, plus related variants, domains, and IP addressesFile hash indicators, with the domains, IP addresses, and URLs found in each file as related observables

What does enrichment add to a file?

  • A score from the file's MalEval verdict. Enrichment only ever raises an observable's score, never lowers it, so a higher score set by another source is kept.
  • Labels for the verdict's severity, matched YARA rules, the malware family when Stairwell names one, and your own Stairwell tags (prefixed stairwell:tag:).
  • Notes: a Stairwell Enrichment Summary with the file's metadata, prevalence, and signing certificates; a Stairwell AI File Triage note with the AI Triage assessment; and a Stairwell Variants note.
  • Variants as related file observables, linked with derived-from, up to 25 per file by default. See Variants.
  • Sightings, only if you turn them on. Read Should I turn on sightings? first.

A hash Stairwell has never seen gets a stairwell:not-found label and a link to the Stairwell search, and nothing else.

What does enrichment add to a domain, IP address, or ASN?

A domain gets a Stairwell DNS History note with up to 50 resolutions, and the addresses it resolved to as related observables. An IP address gets a Stairwell IP Intelligence note with its WHOIS record and the hostnames that resolve to it. An autonomous system gets a Stairwell ASN WHOIS note. This is the same history described in Network Intelligence.

What do I need before I start?

  • OpenCTI 7.261109.0 or later. The Stairwell connector images are published from that release onward.
  • A Stairwell auth token. Both connectors can share one, or you can give each its own so you can revoke them separately.
  • An OpenCTI API token for the user the connectors will act as.
  • A UUID for each connector instance. Any UUIDv4 generator will do, for example uuidgen on macOS or Linux.

How do I create the Stairwell token?

  1. In Stairwell, open Settings.
  2. Under Organization, select Auth tokens.
  3. Create a token and copy it. It is shown once.

Quick Start: API Access covers the same steps in more detail. Store the token where your OpenCTI deployment keeps its other secrets, not in a compose file you commit.

How do I deploy the connectors?

If your OpenCTI deployment manages connectors from the platform, both appear in the connector catalog as Stairwell and Stairwell Import, and you fill in the same settings described below in the catalog's form.

Otherwise, add them to the Docker Compose file that runs your platform. Use the image tag that matches your OpenCTI version, as you would for any OpenCTI connector.

Enrichment

  connector-stairwell:
    image: opencti/connector-stairwell:7.261109.0
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=<your OpenCTI API token>
      - CONNECTOR_ID=<a new UUIDv4>
      - STAIRWELL_API_TOKEN=<your Stairwell auth token>
    restart: always
    depends_on:
      opencti:
        condition: service_healthy

Import

  connector-stairwell-import:
    image: opencti/connector-stairwell-import:7.261109.0
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=<your OpenCTI API token>
      - CONNECTOR_ID=<a different UUIDv4>
      - STAIRWELL_IMPORT_API_TOKEN=<your Stairwell auth token>
      - STAIRWELL_IMPORT_FIRST_RUN_WINDOW=P7D
    restart: always
    depends_on:
      opencti:
        condition: service_healthy

OPENCTI_URL is the address of the platform as the connector container sees it. In the standard OpenCTI Docker deployment that is http://opencti:8080. Each connector instance needs its own CONNECTOR_ID.

Then start them:

docker compose up -d connector-stairwell connector-stairwell-import

How do I know it's working?

Shortly after they start, both connectors appear in OpenCTI under Data, then Ingestion, then Connectors.

To test enrichment, open any file observable, select Enrichment, and choose Stairwell. When it finishes, the observable has a score, labels, and the notes described above. If it gets a stairwell:not-found label instead, the connector is working and Stairwell has no record of that hash.

The import makes its first run shortly after it starts, then runs on its schedule. Each run lands under its own Grouping, named Stairwell MalEval import with the run's date and time, so you can see exactly what one batch brought in. A run that finds nothing new produces no Grouping.

If nothing appears, read the connector's log (docker compose logs connector-stairwell). A setting that is out of range stops the connector at startup with a message that names it.

How do I configure the enrichment connector?

Set these as environment variables, or in a config.yml beside the connector. Environment variables win.

VariableDefaultWhat it does
OPENCTI_URL(required)The OpenCTI platform address
OPENCTI_TOKEN(required)The OpenCTI API token
CONNECTOR_ID(required)A UUIDv4 unique to this instance
STAIRWELL_API_TOKEN(required)Your Stairwell auth token
CONNECTOR_NAMEStairwellThe name shown in OpenCTI
CONNECTOR_SCOPEall five typesWhich of StixFile, Domain-Name, IPv4-Addr, IPv6-Addr, Autonomous-System to enrich
CONNECTOR_AUTOfalseEnrich every new observable in scope as it is created
CONNECTOR_MAX_TLPamberThe highest TLP an observable can carry and still be sent to Stairwell
CONNECTOR_LOG_LEVELerrordebug, info, warn, or error
STAIRWELL_DEFAULT_TLPamberThe TLP marking on everything the connector writes
STAIRWELL_VARIANT_LIMIT25Most variants added per file. 0 turns variants off
STAIRWELL_RESOLUTIONS_LIMIT50Most DNS resolutions per domain. 0 turns DNS history off
STAIRWELL_SIGHTINGS_LIMIT0Most assets added as sightings per file. 0, the default, turns sightings off

Should I turn on automatic enrichment?

Only if the volume of new observables in your OpenCTI instance is modest. With CONNECTOR_AUTO=true, every in-scope observable any connector creates is sent to Stairwell, including the domains and addresses a busy feed brings in by the thousand. The default, enrichment on request and from playbooks, keeps the lookups to the observables someone cares about.

What does CONNECTOR_MAX_TLP protect?

It decides what is allowed to leave OpenCTI. An observable marked above this level is never sent to Stairwell: the connector refuses it, logs why, and makes no request. An observable with no TLP marking is treated as unrestricted. In a playbook, the markings on the step's input are checked too. Set it to the level your sharing agreements allow you to query an outside service with.

Should I turn on sightings?

Sightings tell you which of your hosts have seen a file, which is often the first thing an analyst wants to know. They are off by default because turning them on writes data about your fleet into OpenCTI.

With STAIRWELL_SIGHTINGS_LIMIT above 0, each host that has seen the file becomes a Sighting in OpenCTI, with first seen, last seen, and a count, and an Identity for the host. That puts your asset names, Stairwell environment IDs, and sample file paths, which often contain usernames, into OpenCTI, marked with STAIRWELL_DEFAULT_TLP and visible to everyone who can read the file. Turn it on when everyone with access to your OpenCTI instance is entitled to see that. See Sightings for what a sighting means in Stairwell.

How do I configure the import connector?

VariableDefaultWhat it does
OPENCTI_URL(required)The OpenCTI platform address
OPENCTI_TOKEN(required)The OpenCTI API token
CONNECTOR_ID(required)A UUIDv4 unique to this instance
STAIRWELL_IMPORT_API_TOKEN(required)Your Stairwell auth token
CONNECTOR_NAMEStairwell ImportThe name shown in OpenCTI
CONNECTOR_DURATION_PERIODP1DTime between runs, as an ISO 8601 duration. PT6H is every six hours
CONNECTOR_LOG_LEVELerrordebug, info, warn, or error
STAIRWELL_IMPORT_FIRST_RUN_WINDOWP1DHow far back the first run reaches. P30D imports the last 30 days
STAIRWELL_IMPORT_MIN_BUCKETHIGHThe lowest verdict confidence imported: LOW, MEDIUM, HIGH, or VERY_HIGH
STAIRWELL_IMPORT_MAX_INDICATORS1000About how many files one run imports. The rest wait for the next run
STAIRWELL_IMPORT_TLPgreenThe TLP marking on everything imported
STAIRWELL_IMPORT_INDICATOR_VALIDITY_DAYS90How long each indicator stays valid
STAIRWELL_IMPORT_WRAPPERgroupingPut each run under a grouping or a report
STAIRWELL_IMPORT_PAGE_SIZE100Files requested from Stairwell per page

How do I choose the threshold and the first-run window?

Start with the defaults and watch a few runs. HIGH imports files Stairwell is confident are malicious, which is the right population for indicators that may end up on a blocklist. Lower it to MEDIUM if you want a wider net for hunting and your downstream consumers can tolerate more review.

The first-run window decides how much history you bring in on day one. A large window is safe: when a run reaches STAIRWELL_IMPORT_MAX_INDICATORS, it stops and the next run picks up where it left off, so a 30-day backfill arrives over several runs rather than all at once. Nothing is skipped and nothing is imported twice.

Why are the domains and IP addresses not indicators?

Because malware contains a lot of infrastructure that is not malicious. A file's strings include operating system update hosts, public DNS resolvers, certificate authorities, and XML namespaces alongside its command and control. The import makes each file hash an indicator, and links the domains, IP addresses, and URLs found in that file to it as observables. Promoting them to indicators would put that benign infrastructure on any blocklist fed from OpenCTI.

Both connectors also leave out values that would only be noise: private, loopback, link-local, multicast, and other addresses that are not publicly routable, and strings that look like hostnames but are not, such as version numbers and file names. A DNS answer left out this way still appears in the domain's DNS History note.

What does the import not pick up?

The import reads files by when Stairwell first saw them. A file first seen in a window that the import already read, whose verdict reached your threshold only afterwards, is not imported later. For a file you already have in OpenCTI, run the enrichment connector on it: enrichment always reflects the current verdict.

Troubleshooting

The connector stops at startup with a configuration error. The message names the setting. Durations must be ISO 8601 (P7D, PT12H), TLP values must be one of clear, white, green, amber, amber+strict, or red, and limits must be whole numbers no lower than their minimum.

Every enrichment fails with an authorization error. The Stairwell token is wrong, revoked, or belongs to a user without access to the data. Create a new one and replace it.

Enrichment completes but nothing changes. Check the connector log for a TLP refusal: the observable may be marked above CONNECTOR_MAX_TLP. Also check that its type is in CONNECTOR_SCOPE.

The import ran but brought in fewer files than expected. Check STAIRWELL_IMPORT_MIN_BUCKET and the first-run window, then look at the next run. A large backlog arrives in batches of about STAIRWELL_IMPORT_MAX_INDICATORS.

For anything else, contact Stairwell support with the connector log at debug level.


Did this page help you?