Intel471Ex

Copy Markdown

An Elixir client library for Intel 471's Verity API providing access to cyber threat intelligence.

Table of Contents

Installation

Add intel471_ex to your list of dependencies in mix.exs:

def deps do
  [
    {:intel471_ex, "~> 0.2.0"}
  ]
end

Configuration

This library uses system environment variables for authentication. Create an application in the Verity Developer Portal to obtain a client ID and client secret:

# Required
VERITY_CLIENT_ID=your-verity-client-id
VERITY_CLIENT_SECRET=your-verity-client-secret

# Optional
VERITY_API_URL=https://api.intel471.cloud  # Default API URL

Set them in your application:

System.put_env("VERITY_CLIENT_ID", "your-client-id")
System.put_env("VERITY_CLIENT_SECRET", "your-client-secret")

API Coverage

ServiceModuleKey Functions
ActorsIntel471Ex.Actorsstream
ASEIntel471Ex.Aselist_monitors
Brand ExposureIntel471Ex.BrandExposureMonitor CRUD, scan data, config
CredentialsIntel471Ex.CredentialsCredential/set/occurrence streams and lookups
EntitiesIntel471Ex.Entitiesstream
GIRSIntel471Ex.Girstree
IndicatorsIntel471Ex.Indicatorsstream, get_by_id
Malware IntelIntel471Ex.Malwareevents_stream, list_malware, get_malware_family, download_file
ObservablesIntel471Ex.Observablesstream
ReportsIntel471Ex.ReportsStream/detail for FINTel, Breach Alert, Geopol, Info, Spot, Malware, Vulnerability
SourcesIntel471Ex.SourcesStream/detail for data-leak-site posts, forum posts/messages, chat messages
TPRMIntel471Ex.TprmMonitor CRUD, scan data, config
WatchersIntel471Ex.Watchersalerts_stream, update_alert_status, watcher_groups, watchers

API Examples

Actors

# Stream actors matching a search term
{:ok, result} = Intel471Ex.Actors.stream(%{actor: "lazarus", size: 10})
IO.puts("Found #{result["count"]} actors")

# Stream with pagination
{:ok, page1} = Intel471Ex.Actors.stream(%{actor: "conti", size: 5})
cursor = page1["cursor_next"]
{:ok, page2} = Intel471Ex.Actors.stream(%{actor: "conti", size: 5, cursor: cursor})

# Filter by server type
{:ok, result} = Intel471Ex.Actors.stream(%{actor: "conti", server_type: "telegram"})

Reports

# Stream all report types
{:ok, result} = Intel471Ex.Reports.stream(%{text_filter: "ransomware", size: 10})

# FINTel reports
{:ok, result} = Intel471Ex.Reports.fintel_stream(%{text_filter: "malware"})
{:ok, report} = Intel471Ex.Reports.fintel_detail("report-id")

# Breach alerts
{:ok, result} = Intel471Ex.Reports.breach_alert_stream(%{text_filter: "Communications"})
{:ok, alert} = Intel471Ex.Reports.breach_alert_detail("alert-id")

# Geopolitical reports
{:ok, result} = Intel471Ex.Reports.geopol_stream(%{country: "US"})
{:ok, report} = Intel471Ex.Reports.geopol_detail("report-id")

# Info reports
{:ok, result} = Intel471Ex.Reports.info_stream(%{text_filter: "vulnerability"})

# Malware reports
{:ok, result} = Intel471Ex.Reports.malware_stream(%{malware_family: "lokibot"})

# Spot reports
{:ok, result} = Intel471Ex.Reports.spot_stream(%{text_filter: "phishing"})

# Vulnerability reports
{:ok, result} = Intel471Ex.Reports.vulnerability_stream(%{cve_name: "CVE-2024-1234"})
{:ok, vuln} = Intel471Ex.Reports.vulnerability_detail("vuln-id")

# Download vulnerability report as PDF
{:ok, %{body: pdf_data}} = Intel471Ex.Reports.vulnerability_download_pdf("vuln-id")

Credentials

# Stream credentials
{:ok, result} = Intel471Ex.Credentials.credential_stream(%{domain: "example.com", size: 10})
{:ok, credential} = Intel471Ex.Credentials.get_credential("credential-id")

# Credential occurrences
{:ok, result} = Intel471Ex.Credentials.credential_occurrence_stream(%{credential_id: "id"})
{:ok, occurrence} = Intel471Ex.Credentials.get_credential_occurrence("occurrence-id")

# Credential sets
{:ok, result} = Intel471Ex.Credentials.credential_set_stream(%{victim: "example.com"})
{:ok, set} = Intel471Ex.Credentials.get_credential_set("set-id")

# Accessed URLs
{:ok, result} = Intel471Ex.Credentials.credential_set_accessed_url_stream(%{credential_set_id: "id"})

Watchers

# Stream alerts
{:ok, result} = Intel471Ex.Watchers.alerts_stream(%{size: 10})

# Update alert status
{:ok, _} = Intel471Ex.Watchers.update_alert_status(12345, "read")

# List watcher groups
{:ok, result} = Intel471Ex.Watchers.watcher_groups()

# List watchers
{:ok, result} = Intel471Ex.Watchers.watchers(%{watcher_group_id: "group-id"})

Entities

# Stream entities
{:ok, result} = Intel471Ex.Entities.stream(%{entity: "intel.com", size: 10})

Indicators

# Stream indicators
{:ok, result} = Intel471Ex.Indicators.stream(%{type: "domain", size: 10})

# Get indicator by ID
{:ok, indicator} = Intel471Ex.Indicators.get_by_id("indicator-id")

Malware Intel

# Stream malware events
{:ok, result} = Intel471Ex.Malware.events_stream(%{malware_family_name: "lokibot", size: 10})
{:ok, event} = Intel471Ex.Malware.get_event("event-id")

# List malware families
{:ok, result} = Intel471Ex.Malware.list_malware(%{text_filter: "trickbot"})

# Get malware family detail
{:ok, family} = Intel471Ex.Malware.get_malware_family("family-id")

# Download malware file
{:ok, %{body: file_data}} = Intel471Ex.Malware.download_file("filename.exe")

Observables

# Stream observables
{:ok, result} = Intel471Ex.Observables.stream(%{observable: "8.8.8.8", size: 10})

GIRS

# Get the GIRS tree
{:ok, tree} = Intel471Ex.Girs.tree()
IO.puts("Found #{tree["count"]} GIR entries")

Sources

# Data leak site posts
{:ok, result} = Intel471Ex.Sources.data_leak_site_posts_stream(%{text_filter: "ransomware"})

# Forum posts
{:ok, result} = Intel471Ex.Sources.forums_posts_stream(%{author: "username"})
{:ok, post} = Intel471Ex.Sources.get_forum_post("post-id")

# Forum private messages
{:ok, result} = Intel471Ex.Sources.forums_private_messages_stream(%{author: "username"})

# Chat messages
{:ok, result} = Intel471Ex.Sources.chat_messages_stream(%{server_type: "telegram"})

# Get an image
{:ok, %{body: image_data}} = Intel471Ex.Sources.get_image("forum", "hash", "image.png")

ASE

# List ASE monitors
{:ok, monitors} = Intel471Ex.Ase.list_monitors()

Brand Exposure

# Monitor CRUD
{:ok, monitors} = Intel471Ex.BrandExposure.list_monitors()
{:ok, monitor} = Intel471Ex.BrandExposure.create_monitor(%{
  name: "example.com",
  targets: ["example.com"],
  labels: ["brand-monitor"],
  frequency: "daily",
  impact: "major"
})
{:ok, monitor} = Intel471Ex.BrandExposure.get_monitor("monitor-id")
{:ok, _} = Intel471Ex.BrandExposure.delete_monitor("monitor-id")

# Configuration
{:ok, config} = Intel471Ex.BrandExposure.get_config_current("base")
{:ok, schema} = Intel471Ex.BrandExposure.get_config_schema()

TPRM

# Monitor CRUD
{:ok, monitors} = Intel471Ex.Tprm.list_monitors()
{:ok, monitor} = Intel471Ex.Tprm.create_monitor(%{
  name: "vendor.com",
  targets: ["vendor.com"],
  collection_method: "passive"
})

# Configuration (uses Bearer token for writes)
{:ok, config} = Intel471Ex.Tprm.get_config_current("base")
{:ok, _} = Intel471Ex.Tprm.put_config_user("base", %{"key" => "value"}, "bearer-token")

File Downloads

# Download a file to a specific path
{:ok, path} = Intel471Ex.Downloader.download_file(
  "https://api.intel471.cloud/integrations/malware-intel/v1/malware/files/sample/download",
  "/tmp/malware_sample.zip"
)

# Auto-extract filename from URL
{:ok, path} = Intel471Ex.Downloader.download_file_auto(
  "https://api.intel471.cloud/integrations/sources/v1/data-leak-sites/file-listings/123",
  "downloads"
)

Error Handling

case Intel471Ex.Actors.stream(%{actor: "test"}) do
  {:ok, result} ->
    IO.puts("Found #{result["count"]} actors")

  {:error, %{status: status, message: message}} ->
    IO.puts("API error #{status}: #{message}")

  {:error, exception} ->
    IO.puts("Network error: #{inspect(exception)}")
end

Migration from v0.1.x (Titan API)

This version (0.2.0) is a breaking change. Key migration steps:

  1. Environment variables: Replace INTEL471_USERNAME/INTEL471_API_KEY with VERITY_CLIENT_ID/VERITY_CLIENT_SECRET
  2. API URL: Default changed from https://api.intel471.com/v1 to https://api.intel471.cloud
  3. Removed modules: Intel471Ex.Alerts, Intel471Ex.Search, Intel471Ex.Vulnerabilities
  4. New modules: Entities, Indicators, Malware, Observables, Girs, Sources, Ase, BrandExposure, Tprm
  5. API style: All endpoints now use cursor-based streaming instead of offset/count pagination