Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Logos/vmray.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
98 changes: 98 additions & 0 deletions Sample Data/ThreatIntelligence/VMRay_RawLogs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
[
{
"type": "indicator",
"spec_version": "2.1",
"id": "indicator--ce266cc0-68e0-52d8-8d80-d8293bf5defc",
"created": "2025-08-04T06:10:51.261Z",
"modified": "2025-08-04T06:10:51.261Z",
"revoked": false,
"labels": [
"sample_id: 7281260",
"submission_id: 8026575",
"incident_id: 537",
"threat_names: "
],
"confidence": "100",
"external_references": [
{
"source_name": "VMRay Threat Intelligence",
"description": "Sample ID 7281260\nSubmission ID 8026575",
"url": "https://us.cloud.vmray.com/sample/7281260#summary"
}
],
"name": "old.salina.pl",
"description": "Sample URL: https://us.cloud.vmray.com/sample/7281260#summary,\nAnalysis IDs: 10313083, 10256655, 10321854, 10414844, 10217582, 10413680, 10314196, 10399614, 10296544, 10237033, 10006499, 10354760, 10323161, 10004722, 10324610, 10251840, 10202116, 10226949, 10412430, 10262191, 10301323, 10328341, 10350233, 10007449, 10240616, 10362767, 9994106, 10230482, 10407218, 10249928, 10002741, 10405927, 10233407, 10268596, 10005625, 10353089, 10374137, 10337003, 10285060, 10418224, 10214063, 9998592, 10013498, 10386621, 10392972, 10210422, 10192455, 9983643, 10203998, 10291855, 10270367, 10190246, 10228314, 10411314, 10229596, 10266190, 10384607, 10416155, 10231532, 10274685, 10009565, 10344995, 10179114, 10280058, 9989539, 10317408, 10315505, 10205948, 10307512, 10283385, 10299757, 10320065, 10220636, 10235931, 10008576, 10245619, 10011681, 10368351, 10001436, 10403257, 10188724, 10408552, 10318365, 10215721, 10003783, 10200475, 10389234, 10253897, 10235121, 10379474, 9991427, 10404932, 10288292, 10321122, 10370506, 10357101, 10316524, 10311409, 10196623, 10333652, 9979123, 10340569, 10238561, 10303511, 10224434, 10338846, 9987701, 10410209, 10372204, 10319256, 10234257, 10010612, 10186778, 10232362,\nCategories: ",
"indicator_types": [
"domain"
],
"pattern": "[domain-name:value = 'old.salina.pl']",
"pattern_type": "stix",
"pattern_version": "2.1",
"valid_from": "2025-08-04T06:10:51.261Z",
"valid_until": "2025-09-03T06:10:51Z"
},
{
"type": "indicator",
"spec_version": "2.1",
"id": "indicator--4282c984-96c7-52b8-9772-349a1ab6b5d4",
"created": "2025-08-04T06:10:51.261Z",
"modified": "2025-08-04T06:10:51.261Z",
"revoked": false,
"labels": [
"sample_id: 7281260",
"submission_id: 8026575",
"incident_id: 537",
"threat_names: "
],
"confidence": "100",
"external_references": [
{
"source_name": "VMRay Threat Intelligence",
"description": "Sample ID 7281260\nSubmission ID 8026575",
"url": "https://us.cloud.vmray.com/sample/7281260#summary"
}
],
"name": "http://old.salina.pl/wp-content/upgrade/Earthcore_English/index.php?uid=sanitized@sanitized.com",
"description": "Sample URL: https://us.cloud.vmray.com/sample/7281260#summary,\nAnalysis IDs: 10412430, 10262191, 10301323, 10328341, 10324610, 10251840, 10323161, 10004722, 10226949, 10202116, 10399614, 10314196, 10296544, 10413680, 10006499, 10354760, 10237033, 10313083, 10414844, 10321854, 10217582, 10256655, 10291855, 10210422, 10203998, 10192455, 9983643, 10270367, 10228314, 10190246, 10013498, 10214063, 10418224, 9998592, 10386621, 10392972, 10233407, 10405927, 10374137, 10285060, 10337003, 10268596, 10353089, 10005625, 10240616, 10362767, 10350233, 10007449, 10249928, 10407218, 10002741, 9994106, 10230482, 10403257, 10188724, 10320065, 10299757, 10220636, 10205948, 10283385, 10307512, 10001436, 10235931, 10008576, 10245619, 10011681, 10368351, 10344995, 10231532, 10416155, 10274685, 10009565, 10315505, 10317408, 10280058, 10179114, 9989539, 10411314, 10229596, 10266190, 10384607, 10234257, 10372204, 10319256, 10338846, 10410209, 10186778, 10232362, 10010612, 10340569, 9979123, 10333652, 10303511, 10224434, 9987701, 10238561, 10404932, 10235121, 10389234, 10379474, 10253897, 10311409, 10370506, 10316524, 10357101, 10196623, 9991427, 10321122, 10288292, 10318365, 10215721, 10408552, 10200475, 10003783,\nCategories: Contacted, Extracted, Sample",
"indicator_types": [
"url"
],
"pattern": "[url:value = 'http://old.salina.pl/wp-content/upgrade/Earthcore_English/index.php?uid=sanitized@sanitized.com']",
"pattern_type": "stix",
"pattern_version": "2.1",
"valid_from": "2025-08-04T06:10:51.261Z",
"valid_until": "2025-09-03T06:10:51Z"
},
{
"type": "indicator",
"spec_version": "2.1",
"id": "indicator--e58f0310-75ff-56d1-a990-86e82c3eac0c",
"created": "2025-08-04T06:10:51.261Z",
"modified": "2025-08-04T06:10:51.261Z",
"revoked": false,
"labels": [
"sample_id: 7281260",
"submission_id: 8026575",
"incident_id: 537",
"threat_names: "
],
"confidence": "100",
"external_references": [
{
"source_name": "VMRay Threat Intelligence",
"description": "Sample ID 7281260\nSubmission ID 8026575",
"url": "https://us.cloud.vmray.com/sample/7281260#summary"
}
],
"name": "http://old.salina.pl/wp-content/upgrade/earthcore_english/index.php?uid=sanitized@sanitized.com",
"description": "Sample URL: https://us.cloud.vmray.com/sample/7281260#summary,\nAnalysis IDs: 10379474, 10233407, 10226949, 10005625, 10001436, 10245619, 10202116, 10368351, 10299757, 10320065, 10220636, 10324610, 10251840, 10323161, 10307512, 10283385, 10235931, 10205948, 10196623, 10011681, 10008576, 10004722, 10188724, 10328341, 9991427, 10262191, 10301323, 10403257, 10321854, 10217582, 10266190, 10384607, 10229596, 10313083, 10256655, 10006499, 9989539, 10354760, 10317408, 10315505, 10280058, 10237033, 10344995, 10399614, 10314196, 10296544, 10179114, 10231532, 10274685, 10009565, 10303511, 10224434, 9987701, 10386621, 10392972, 10238561, 9979123, 10340569, 10013498, 10333652, 10214063, 10232362, 10186778, 10010612, 9998592, 10270367, 10190246, 10228314, 10372204, 10319256, 10291855, 10234257, 10338846, 10210422, 10192455, 10203998, 10200475, 10249928, 10002741, 9983643, 10003783, 9994106, 10230482, 10318365, 10240616, 10362767, 10215721, 10350233, 10007449, 10374137, 10370506, 10337003, 10357101, 10316524, 10311409, 10288292, 10321122, 10353089, 10285060, 10268596, 10404932, 10389234, 10253897, 10235121,\nCategories: Extracted",
"indicator_types": [
"url"
],
"pattern": "[url:value = 'http://old.salina.pl/wp-content/upgrade/earthcore_english/index.php?uid=sanitized@sanitized.com']",
"pattern_type": "stix",
"pattern_version": "2.1",
"valid_from": "2025-08-04T06:10:51.261Z",
"valid_until": "2025-09-03T06:10:51Z"
}
]
35 changes: 35 additions & 0 deletions Solutions/VMRay/Data Connectors/Logo/vmray.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
69 changes: 69 additions & 0 deletions Solutions/VMRay/Data Connectors/VMRay/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""
Main Function
"""

# pylint: disable=logging-fstring-interpolation

import logging
from datetime import datetime, timedelta
from traceback import format_exc

import azure.functions as func

from .const import IOC_LIST, VMRay_CONFIG
from .utils import (
IOC_MAPPING_FUNCTION,
get_last_saved_timestamp,
get_sample_ioc,
get_submission,
save_checkpoint,
submit_indicator,
)


def main(mytimer: func.TimerRequest) -> None:
"""
Main handler function to interact with the VMRay API, triggered on a timer.

This function manages VMRay API access tokens, performs API calls including
pagination to retrieve all relevant data, and handles errors gracefully.
It is designed to run at scheduled intervals via a timer trigger.

Parameters
----------
mytimer : func.TimerRequest
Timer object that triggers the function execution on a defined schedule.
"""
try:
if mytimer.past_due:
logging.info("The timer is past due!")
return

initial_date_time = get_last_saved_timestamp() or (
datetime.now() - timedelta(days=int(VMRay_CONFIG.INITIAL_FETCH))
).strftime("%Y-%m-%dT00:00:00")
logging.info(f"last_run {get_last_saved_timestamp()}")
sample_verdict = VMRay_CONFIG.VMRAY_SAMPLE_VERDICTS
sample_verdict = sample_verdict.split(" & ")
logging.info(f"verdict {sample_verdict}")
current_date = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
submissions_list = get_submission(
sample_verdict, initial_date_time, current_date
)
for sub in submissions_list:
if sub.get("submission_finished"):
iocs = get_sample_ioc(sub.get("submission_sample_id"))
for key, value in iocs.items():
if key in IOC_LIST:
IOC_MAPPING_FUNCTION[key](
value,
sub.get("submission_sample_id"),
sub.get("submission_id"),
sample_verdict,
)
submit_indicator()
save_checkpoint(current_date)
except Exception as ex:
error_detatl = format_exc()
logging.error(f"something went wrong. Error: {ex}. Traceback {error_detatl}")

67 changes: 67 additions & 0 deletions Solutions/VMRay/Data Connectors/VMRay/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
Constant File
"""
from dataclasses import dataclass
from os import environ

# pylint: disable=invalid-name

@dataclass
class VMRayConfig:
"""
VMRay Configuration
"""
API_KEY: str
BASE_URL: str
VMRAY_SAMPLE_VERDICTS: str
INITIAL_FETCH: str
VALID_UNTIL: str
CONNECTOR_NAME: str = "VMRayThreatIntelligenceSentinel:1.0.0"
RETRIES: int = 5
BACKOFF: int = 1


VMRay_CONFIG = VMRayConfig(
API_KEY=environ.get("VmrayAPIKey", ""),
BASE_URL=environ.get("VmrayBaseURL", ""),
VMRAY_SAMPLE_VERDICTS=environ.get("VmraySampleVerdict", "Malicious & Suspicious"),
INITIAL_FETCH=environ.get("VmrayInitialFetchDate", "90"),
VALID_UNTIL=environ.get("IndicatorExpirationInDays", "30")
)


@dataclass
class APIConfig:
"""
Microsoft API Configurations
"""
APPLICATION_ID: str
APPLICATION_SECRET: str
AUTH_URL: str
URL: str
RESOURCE_APPLICATION_ID_URI: str = "https://management.azure.com"
USER_AGENT: str = "MSSentinelVMRayThreatIntelligenceSentinel:1.0.0"
SLEEP: int = 60
TIMEOUT: int = 300
MAX_TI_INDICATORS_PER_REQUEST:int = 100


SENTINEL_API = APIConfig(
APPLICATION_ID=environ.get("AzureClientID", ""),
APPLICATION_SECRET=environ.get("AzureClientSecret", ""),
AUTH_URL=f"https://login.microsoftonline.com/{environ.get('AzureTenantID', '')}/oauth2/token",
URL=f"https://api.ti.sentinel.azure.com/workspaces/{environ.get('AzureWorkspaceID', '')}/"
f"threat-intelligence-stix-objects:upload?api-version=2024-02-01-preview"
)

RETRY_STATUS_CODE = [500, 501, 502, 503, 504, 429]
IPV4REGEX = r"^(?P<ipv4>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))[:]?(?P<port>\d+)?$"
IPV6REGEX = r"^(?:(?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:(?:(:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$" # noqa: E501
CONFIDENCE = {"malicious": "100", "suspicious": "75"}
HASH_TYPE_LIST = [
("MD5", "md5_hash"),
("SHA-1", "sha1_hash"),
("SHA-256", "sha256_hash"),
]
IOC_LIST = ["domains", "ips", "urls", "files"]

11 changes: 11 additions & 0 deletions Solutions/VMRay/Data Connectors/VMRay/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"scriptFile": "app.py",
"bindings": [
{
"name": "mytimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "%Polling%"
}
]
}
65 changes: 65 additions & 0 deletions Solutions/VMRay/Data Connectors/VMRay/state_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
StateManager of Azure Function App
"""
from azure.core.exceptions import ResourceNotFoundError
from azure.storage.fileshare import ShareClient, ShareFileClient


class StateManager:
"""
Manages state persistence using Azure File Share storage.

Parameters
----------
connection_string : str
Azure Storage account connection string.
share_name : str, optional
Name of the Azure File Share to use (default is "funcstatemarkershare").
file_path : str, optional
Path of the file within the share to store the marker (default is "funcstatemarkerfile").
"""

def __init__(
self,
connection_string,
share_name="funcstatemarkershare",
file_path="funcstatemarkerfile",
):
self.share_cli = ShareClient.from_connection_string(
conn_str=connection_string, share_name=share_name, is_emulated=True
)
self.file_cli = ShareFileClient.from_connection_string(
conn_str=connection_string,
share_name=share_name,
file_path=file_path,
is_emulated=True,
)

def post(self, marker_text: str):
"""
Saves the given marker text to the Azure File Share.

Parameters
----------
marker_text : str
The content (typically a timestamp) to store in the state file.
"""
try:
self.file_cli.upload_file(marker_text)
except ResourceNotFoundError:
self.share_cli.create_share()
self.file_cli.upload_file(marker_text)

def get(self):
"""
Retrieves the stored marker text from the Azure File Share.

Returns
-------
str or None
The stored marker text.
"""
try:
return self.file_cli.download_file().readall().decode()
except ResourceNotFoundError:
return None
Loading
Loading