Skip to content
This repository has been archived by the owner on Jun 14, 2024. It is now read-only.

Commit

Permalink
[feedly] Turn threat actors to intrusion sets
Browse files Browse the repository at this point in the history
  • Loading branch information
SamuelHassine committed Aug 16, 2024
1 parent 9d7da67 commit b8eeea4
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 52 deletions.
15 changes: 15 additions & 0 deletions external-import/feedly/src/feedly/opencti_connector/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def fetch_bundle(self, stream_id: str, newer_than: datetime) -> dict:
).download_all()
_replace_description_with_note(bundle)
_add_main_observable_type_to_indicators(bundle)
_transform_threat_actors_to_intrusion_sets(bundle)
self.cti_helper.log_info(f"Found {_count_reports(bundle)} new reports")
return bundle

Expand Down Expand Up @@ -59,3 +60,17 @@ def _add_main_observable_type_to_indicators(bundle: dict) -> None:
o["x_opencti_main_observable_type"] = (
OpenCTIStix2Utils.stix_observable_opencti_type(stix_type)
)


def _transform_threat_actors_to_intrusion_sets(bundle: dict) -> None:
for o in bundle["objects"]:
if o["type"] == "threat-actor":
o["type"] = "intrusion-set"
o["id"] = o.get("id").replace("threat-actor", "intrusion-set")
if o["type"] == "relationship":
o["source_ref"] = o.get("source_ref").replace(
"threat-actor", "intrusion-set"
)
o["target_ref"] = o.get("target_ref").replace(
"threat-actor", "intrusion-set"
)
2 changes: 0 additions & 2 deletions external-import/greynoise-feed/src/config.yml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ connector:
type: 'EXTERNAL_IMPORT'
name: 'GreyNoise Feed'
scope: 'greynoisefeed' # MIME type or SCO
confidence_level: 80 # From 0 (Unknown) to 100 (Fully trusted)
log_level: 'info'
playbook_compatible: false

greynoisefeed:
api_key: 'ChangeMe' # set if using the "feed" option
Expand Down
126 changes: 77 additions & 49 deletions external-import/greynoise-feed/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import time
from datetime import datetime

import requests
import stix2
import yaml
from greynoise import GreyNoise
Expand Down Expand Up @@ -41,21 +40,16 @@ def __init__(self):
"GREYNOISE_INDICATOR_SCORE",
["greynoisefeed", "indicator_score"],
config,
True,
isNumber=True,
)
self.limit = get_config_variable(
"GREYNOISE_LIMIT", ["greynoisefeed", "limit"], config, True
"GREYNOISE_LIMIT", ["greynoisefeed", "limit"], config, isNumber=True
)
self.interval = get_config_variable(
"GREYNOISE_INTERVAL",
["greynoisefeed", "interval"],
config,
True,
)
self.update_existing_data = get_config_variable(
"CONNECTOR_UPDATE_EXISTING_DATA",
["connector", "update_existing_data"],
config,
isNumber=True,
)
self.identity = self.helper.api.identity.create(
type="Organization",
Expand Down Expand Up @@ -87,8 +81,12 @@ def get_feed_query(self, feed_type):

return query

def get_tag_query(self, tag):
query = "last_seen:1d tags:" + tag
return query

def run(self):
self.helper.log_info("greynoise feed dataset...")
self.helper.log_info("GreyNoise feed dataset...")
while True:
try:
# Get the current timestamp and check
Expand Down Expand Up @@ -135,11 +133,7 @@ def run(self):
scroll = response.get("scroll", "")

for item in response["data"]:
item_trimmed = {
"ip": item["ip"],
"classification": item["classification"],
}
ip_list.append(item_trimmed)
ip_list.append(item)
self.helper.log_info(
"GreyNoise Indicator Count: " + str(len(ip_list))
)
Expand All @@ -160,11 +154,7 @@ def run(self):
scroll = response.get("scroll", "")

for item in response["data"]:
item_trimmed = {
"ip": item["ip"],
"classification": item["classification"],
}
ip_list.append(item_trimmed)
ip_list.append(item)
self.helper.log_info(
"GreyNoise Indicator Count: " + str(len(ip_list))
)
Expand All @@ -185,35 +175,53 @@ def run(self):
)
for meta in metadata["metadata"]:
if meta["slug"] == tag:
tag_id = meta["id"]
tag_name = meta["name"]
cves = meta["cves"]
url = (
"https://api.greynoise.io/v3/tags/"
+ str(tag_id)
+ "/ips/download?format=txt"

query = self.get_tag_query(tag_name)
self.helper.log_info(
"Query GreyNoise API - First Results Page"
)
headers = {
"key": self.api_key,
"User-Agent": "greynoise-opencti-feed-tags-v2.0",
}
response = requests.get(url, headers=headers)
ips = response.text.split("\n")
for item in ips:
item_object = {
"ip": item,
"tag_name": tag_name,
"cves": cves,
}
ip_list.append(item_object)
response = session.query(query=query, exclude_raw=True)
complete = response.get("complete", True)
scroll = response.get("scroll", "")

for item in response["data"]:
item["cves"] = cves
item["tag_name"] = tag_name
ip_list.append(item)
self.helper.log_info(
"GreyNoise Indicator Count: " + str(len(ip_list))
)
if len(ip_list) >= self.limit:
complete = True
self.helper.log_info(
"GreyNoise Indicator Limit Reached"
)
break
# get additional indicators
while not complete:
self.helper.log_info(
"Query GreyNoise API - Next Results Page"
)
response = session.query(
query=query, scroll=scroll, exclude_raw=True
)
complete = response.get("complete", True)
scroll = response.get("scroll", "")

for item in response["data"]:
item["cves"] = cves
item["tag_name"] = tag_name
ip_list.append(item)
self.helper.log_info(
"GreyNoise Indicator Count: "
+ str(len(ip_list))
)
if len(ip_list) >= self.limit:
self.helper.log_info(
"GreyNoise Indicator Limit Reached"
)
complete = True
else:
self.helper.log_error(
"Value for source is not one of: feed, tags"
Expand Down Expand Up @@ -253,11 +261,11 @@ def run(self):
name=d["ip"],
description=description,
created_by_ref=self.identity["standard_id"],
confidence=self.helper.connect_confidence_level,
pattern_type="stix",
pattern=pattern,
external_references=[external_reference],
object_marking_refs=[stix2.TLP_WHITE],
labels=d["tags"],
custom_properties={
"x_opencti_score": self.indicator_score,
"x_opencti_main_observable_type": "IPv4-Addr",
Expand All @@ -272,10 +280,10 @@ def run(self):
"x_opencti_description": description,
"x_opencti_score": self.indicator_score,
"created_by_ref": self.identity["standard_id"],
"labels": d["tags"],
"external_references": [external_reference],
},
)

# Adding the IP to the list
stix_relationship = stix2.Relationship(
id=StixCoreRelationship.generate_id(
Expand All @@ -287,12 +295,11 @@ def run(self):
object_marking_refs=[stix2.TLP_WHITE],
)
if "cves" in d and d["cves"]:
for cve in cves:
for cve in d["cves"]:
# Generate Vulnerability
stix_vulnerability = stix2.Vulnerability(
id=Vulnerability.generate_id(cve),
name=cve,
confidence=self.helper.connect_confidence_level,
created_by_ref=self.identity["standard_id"],
allow_custom=True,
)
Expand All @@ -302,25 +309,46 @@ def run(self):
observable_to_vulnerability = stix2.Relationship(
id=StixCoreRelationship.generate_id(
"related-to",
stix_observable.id,
stix_vulnerability.id,
),
relationship_type="related-to",
source_ref=stix_observable.id,
target_ref=stix_vulnerability.id,
object_marking_refs=[stix2.TLP_WHITE],
)
bundle_objects.append(observable_to_vulnerability)
if "cve" in d and d["cve"]:
for cve in d["cve"]:
# Generate Vulnerability
stix_vulnerability = stix2.Vulnerability(
id=Vulnerability.generate_id(cve),
name=cve,
created_by_ref=self.identity["standard_id"],
allow_custom=True,
)
bundle_objects.append(stix_vulnerability)
# Generate Relationship : observable -> "related-to" -> vulnerability
observable_to_vulnerability = stix2.Relationship(
id=StixCoreRelationship.generate_id(
"related-to",
stix_observable.id,
stix_vulnerability.id,
),
relationship_type="related-to",
source_ref=stix_vulnerability.id,
target_ref=stix_observable.id,
source_ref=stix_observable.id,
target_ref=stix_vulnerability.id,
object_marking_refs=[stix2.TLP_WHITE],
)
bundle_objects.append(observable_to_vulnerability)
bundle_objects.append(stix_indicator)
bundle_objects.append(stix_observable)
bundle_objects.append(stix_relationship)
# Creating the bundle from the list
bundle = stix2.Bundle(bundle_objects, allow_custom=True)
bundle_json = bundle.serialize()
bundle = self.helper.stix2_create_bundle(bundle_objects)
# Sending the bundle
self.helper.send_stix2_bundle(
bundle_json,
update=self.update_existing_data,
bundle,
work_id=work_id,
)

Expand Down
2 changes: 1 addition & 1 deletion internal-enrichment/greynoise/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(self):
if os.path.isfile(config_file_path)
else {}
)
self.helper = OpenCTIConnectorHelper(config, True)
self.helper = OpenCTIConnectorHelper(config, playbook_compatible=True)
self.greynoise_key = get_config_variable(
"GREYNOISE_KEY", ["greynoise", "key"], config
)
Expand Down

0 comments on commit b8eeea4

Please sign in to comment.