This commit is contained in:
Diego Ramirez 2024-07-15 14:51:23 -04:00
Родитель 64e95691e1
Коммит 6f780c820b
32 изменённых файлов: 414 добавлений и 335 удалений

Просмотреть файл

@ -0,0 +1 @@
.venv

Двоичный файл не отображается.

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,18 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_advanced_dark_web(
zerofox, created_after=query_from
)
batches = get_cti_advanced_dark_web(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -37,16 +39,21 @@ async def main(mytimer: func.TimerRequest) -> None:
)
async with sentinel:
batches = get_cti_botnet_compromised_credentials(
zerofox, created_after=query_from
)
zerofox, created_after=query_from
)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
user = os.environ.get("ZeroFoxUsername")

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_botnet(
zerofox, listed_after=query_from
)
batches = get_cti_botnet(zerofox, listed_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
user = os.environ.get("ZeroFoxUsername")

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_breaches(
zerofox, created_after=query_from
)
batches = get_cti_breaches(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
user = os.environ.get("ZeroFoxUsername")

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_c2_domains(
zerofox, created_after=query_from
)
batches = get_cti_c2_domains(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
user = os.environ.get("ZeroFoxUsername")

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_compromised_credentials(
zerofox, created_after=query_from
)
batches = get_cti_compromised_credentials(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
@ -55,8 +59,7 @@ def get_zf_client():
return ZeroFoxClient(user, token)
def get_cti_compromised_credentials(
client: ZeroFoxClient, created_after: str):
def get_cti_compromised_credentials(client: ZeroFoxClient, created_after: str):
url_suffix = "compromised-credentials/"
params = dict(created_after=created_after)
return client.cti_request(

Просмотреть файл

@ -46,16 +46,18 @@ class SentinelConnector:
if not data:
return
split_data = self._split_big_request(data)
await asyncio.gather(*[
self._post_data(
session=self.session,
customer_id=self.customer_id,
shared_key=self.shared_key,
body=d,
log_type=self.log_type
)
for d in split_data
])
await asyncio.gather(
*[
self._post_data(
session=self.session,
customer_id=self.customer_id,
shared_key=self.shared_key,
body=d,
log_type=self.log_type,
)
for d in split_data
]
)
async def __aenter__(self):
return self
@ -88,20 +90,20 @@ class SentinelConnector:
bytes_to_hash = bytes(string_to_hash, encoding="utf-8")
decoded_key = base64.b64decode(shared_key)
encoded_hash = base64.b64encode(
hmac.new(decoded_key, bytes_to_hash,
digestmod=hashlib.sha256).digest()
hmac.new(decoded_key, bytes_to_hash, digestmod=hashlib.sha256).digest()
).decode()
authorization = f"SharedKey {customer_id}:{encoded_hash}"
return authorization
async def _post_data(self, session: aiohttp.ClientSession, customer_id, shared_key, body, log_type):
async def _post_data(
self, session: aiohttp.ClientSession, customer_id, shared_key, body, log_type
):
events_number = len(body)
body = json.dumps(body)
method = "POST"
content_type = "application/json"
resource = "/api/logs"
rfc1123date = datetime.now(timezone.utc).strftime(
"%a, %d %b %Y %H:%M:%S GMT")
rfc1123date = datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S GMT")
content_length = len(body)
signature = self._build_signature(
customer_id,
@ -122,7 +124,7 @@ class SentinelConnector:
}
async with session.post(uri, data=body, headers=headers) as response:
if (200 <= response.status <= 299):
if 200 <= response.status <= 299:
logging.info(
f"{events_number} events have been successfully sent to Microsoft Sentinel"
)

Просмотреть файл

@ -3,6 +3,7 @@ from typing import Dict
import requests
from connections.exceptions import ApiResponseException
TIMEOUT = 30
@ -59,8 +60,7 @@ class ZeroFoxClient:
**kwargs,
)
if response.status_code != ok_code:
logging.error(
f"Failed to {method} {url}. Response: {response.text}")
logging.error(f"Failed to {method} {url}. Response: {response.text}")
raise ApiResponseException(method, url=url, res=response)
if response.status_code == requests.codes["no_content"]:
return None

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_credit_cards(
zerofox, created_after=query_from
)
batches = get_cti_credit_cards(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
@ -55,9 +59,7 @@ def get_zf_client():
return ZeroFoxClient(user, token)
def get_cti_credit_cards(
client: ZeroFoxClient, created_after: str
):
def get_cti_credit_cards(client: ZeroFoxClient, created_after: str):
url_suffix = "credit-cards/"
params = dict(created_after=created_after)
return client.cti_request(

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_dark_web(
zerofox, created_after=query_from
)
batches = get_cti_dark_web(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_discord(
zerofox, timestamp_after=query_from
)
batches = get_cti_discord(zerofox, timestamp_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
user = os.environ.get("ZeroFoxUsername")

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_disruption(
zerofox, created_after=query_from
)
batches = get_cti_disruption(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
user = os.environ.get("ZeroFoxUsername")

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_email_addresses(
zerofox, created_after=query_from
)
batches = get_cti_email_addresses(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
user = os.environ.get("ZeroFoxUsername")

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_exploits(
zerofox, created_after=query_from
)
batches = get_cti_exploits(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():

Просмотреть файл

@ -8,9 +8,9 @@
}
},
"logLevel": {
"default": "Debug",
"Host.Results": "Debug",
"Function": "Debug",
"default": "Information",
"Host.Results": "Information",
"Function": "Information",
"Host.Aggregator": "Information"
}
},

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,18 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_irc(
zerofox, timestamp_after=query_from
)
batches = get_cti_irc(zerofox, timestamp_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_malware(
zerofox, created_after=query_from
)
batches = get_cti_malware(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_national_ids(
zerofox, created_after=query_from
)
batches = get_cti_national_ids(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
@ -55,9 +59,7 @@ def get_zf_client():
return ZeroFoxClient(user, token)
def get_cti_national_ids(
client: ZeroFoxClient, created_after: str
):
def get_cti_national_ids(client: ZeroFoxClient, created_after: str):
url_suffix = "national-ids/"
params = dict(created_after=created_after)
return client.cti_request(

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_phishing(
zerofox, scanned_after=query_from
)
batches = get_cti_phishing(zerofox, scanned_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_phone_numbers(
zerofox, created_after=query_from
)
batches = get_cti_phone_numbers(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
@ -55,9 +59,7 @@ def get_zf_client():
return ZeroFoxClient(user, token)
def get_cti_phone_numbers(
client: ZeroFoxClient, created_after: str
):
def get_cti_phone_numbers(client: ZeroFoxClient, created_after: str):
url_suffix = "phone-numbers/"
params = dict(created_after=created_after)
return client.cti_request(

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_ransomware(
zerofox, created_after=query_from
)
batches = get_cti_ransomware(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,18 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_telegram(
zerofox, timestamp_after=query_from
)
batches = get_cti_telegram(zerofox, timestamp_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
@ -56,9 +60,7 @@ def get_zf_client():
return ZeroFoxClient(user, token)
def get_cti_telegram(
client: ZeroFoxClient, timestamp_after: str
):
def get_cti_telegram(client: ZeroFoxClient, timestamp_after: str):
url_suffix = "telegram/"
params = dict(timestamp_after=timestamp_after)
return client.cti_request(

Просмотреть файл

@ -13,8 +13,8 @@ SECOND_PAGE_URL = "https://second_page"
URL = "https://api.zerofox.com"
class TestZeroFoxCTI():
class TestZeroFoxCTI:
@responses.activate
def test_cti_generator_is_provided(self):
zerofox = ZeroFoxClient(user=USER, token=TOKEN)
@ -30,8 +30,8 @@ class TestZeroFoxCTI():
"""Prepare mock responses for queries through the requests package."""
responses.post(
url=f"{URL}/auth/token/",
match=[matchers.urlencoded_params_matcher(
dict(username=USER, password=TOKEN))
match=[
matchers.urlencoded_params_matcher(dict(username=USER, password=TOKEN))
],
json=dict(access=CTI_TOKEN),
)
@ -43,18 +43,17 @@ class TestZeroFoxCTI():
}
endpoint_first_page_json = dict(
next=SECOND_PAGE_URL, results=[
dict(index=f"r{i}") for i in range(2)]
next=SECOND_PAGE_URL, results=[dict(index=f"r{i}") for i in range(2)]
)
responses.get(
url=f"{URL}/cti/{ENDPOINT}", headers=cti_header,
json=endpoint_first_page_json
url=f"{URL}/cti/{ENDPOINT}",
headers=cti_header,
json=endpoint_first_page_json,
)
endpoint_second_page_json = dict(
next=None, results=[dict(index=f"r{i}") for i in range(2, 4)]
)
responses.get(
url=SECOND_PAGE_URL, headers=cti_header,
json=endpoint_second_page_json
url=SECOND_PAGE_URL, headers=cti_header, json=endpoint_second_page_json
)

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,18 +38,20 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_threat_actors(
zerofox, created_after=query_from
)
batches = get_cti_threat_actors(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():

Просмотреть файл

@ -6,13 +6,12 @@ import aiohttp
import azure.functions as func
from connections.sentinel import SentinelConnector
from connections.zerofox import ZeroFoxClient
from dateutil import parser
async def main(mytimer: func.TimerRequest) -> None:
now = datetime.now(timezone.utc)
utc_timestamp = (
now.isoformat()
)
utc_timestamp = now.isoformat()
if mytimer.past_due:
logging.info("The timer is past due!")
@ -20,8 +19,11 @@ async def main(mytimer: func.TimerRequest) -> None:
customer_id = os.environ.get("WorkspaceID")
shared_key = os.environ.get("WorkspaceKey")
query_from = max(
mytimer.schedule_status["Last"], (now - timedelta(days=1)).isoformat())
query_from = (
max(parse_last_update(mytimer), (now - timedelta(days=1)))
.replace(tzinfo=None)
.isoformat()
)
logging.info(f"Querying ZeroFox since {query_from}")
zerofox = get_zf_client()
@ -36,17 +38,19 @@ async def main(mytimer: func.TimerRequest) -> None:
log_type=log_type,
)
async with sentinel:
batches = get_cti_vulnerabilities(
zerofox, created_after=query_from
)
batches = get_cti_vulnerabilities(zerofox, created_after=query_from)
for batch in batches:
await sentinel.send(batch)
if sentinel.failed_sent_events_number:
logging.error(
f"Failed to send {sentinel.failed_sent_events_number} events"
)
logging.info(f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel.")
logging.error(f"Failed to send {sentinel.failed_sent_events_number} events")
logging.info(
f"Connector {log_type} ran at {utc_timestamp}, \
sending {sentinel.successfull_sent_events_number} events to Sentinel."
)
def parse_last_update(mytimer):
return parser.parse(mytimer.schedule_status["Last"])
def get_zf_client():
@ -55,9 +59,7 @@ def get_zf_client():
return ZeroFoxClient(user, token)
def get_cti_vulnerabilities(
client: ZeroFoxClient, created_after: str
):
def get_cti_vulnerabilities(client: ZeroFoxClient, created_after: str):
url_suffix = "vulnerabilities/"
params = dict(created_after=created_after)
return client.cti_request(

Просмотреть файл

@ -1,8 +1,10 @@
# Do not include azure-functions-worker in this file
# The Python Worker is managed by the Azure Functions platform
# Manually managing azure-functions-worker may cause unexpected issues
requests==2.32.2
azure-functions==1.19.0
responses==0.25.0
pytest==8.2.0
aiohttp==3.9.5
python-dateutil==2.9.0.post0

Двоичные данные
Solutions/ZeroFox/Package/3.0.0.zip

Двоичный файл не отображается.

Двоичные данные
Solutions/ZeroFox/Package/3.1.0.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -63,13 +63,6 @@
"text": "This Solution installs the data connector for ZeroFox. You can get ZeroFox custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view."
}
},
{
"name": "dataconnectors2-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This Solution installs the data connector for ZeroFox. You can get ZeroFox custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view."
}
},
{
"name": "dataconnectors-link2",
"type": "Microsoft.Common.TextBlock",

Просмотреть файл

@ -1158,10 +1158,10 @@
"status": "Available",
"requiredDataConnectors": [
{
"connectorId": "ZeroFox_Alert_Polling",
"dataTypes": [
"ZeroFoxAlertPoller_CL"
],
"connectorId": "ZeroFox_Alert_Polling"
]
}
],
"tactics": [
@ -1268,10 +1268,10 @@
"status": "Available",
"requiredDataConnectors": [
{
"connectorId": "ZeroFox_Alert_Polling",
"dataTypes": [
"ZeroFoxAlertPoller_CL"
],
"connectorId": "ZeroFox_Alert_Polling"
]
}
],
"tactics": [
@ -1378,10 +1378,10 @@
"status": "Available",
"requiredDataConnectors": [
{
"connectorId": "ZeroFox_Alert_Polling",
"dataTypes": [
"ZeroFoxAlertPoller_CL"
],
"connectorId": "ZeroFox_Alert_Polling"
]
}
],
"tactics": [
@ -1488,10 +1488,10 @@
"status": "Available",
"requiredDataConnectors": [
{
"connectorId": "ZeroFox_Alert_Polling",
"dataTypes": [
"ZeroFoxAlertPoller_CL"
],
"connectorId": "ZeroFox_Alert_Polling"
]
}
],
"tactics": [