Merge pull request #9802 from FortiNDR-Integration/FortiNDR-Cloud-Sentinel-initialization

Fortinet FortiNDR Cloud Initialization
This commit is contained in:
v-atulyadav 2024-01-30 12:39:05 +05:30 коммит произвёл GitHub
Родитель 57861532ed f1dd900db9
Коммит 65a9bfb713
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
48 изменённых файлов: 6441 добавлений и 22 удалений

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

@ -0,0 +1,126 @@
{
"Name": "FncEventsDetections_CL",
"Properties": [
{
"Name": "vendor_s",
"Type": "String"
},
{
"Name": "product_s",
"Type": "String"
},
{
"Name": "signal_version_s",
"Type": "String"
},
{
"Name": "event_type_s",
"Type": "String"
},
{
"Name": "subject_s",
"Type": "String"
},
{
"Name": "timestamp_t",
"Type": "DateTime"
},
{
"Name": "device_ip_s",
"Type": "String"
},
{
"Name": "name_s",
"Type": "String"
},
{
"Name": "severity_s",
"Type": "String"
},
{
"Name": "confidence_s",
"Type": "String"
},
{
"Name": "sensor_id_s",
"Type": "String"
},
{
"Name": "muted_b",
"Type": "Boolean"
},
{
"Name": "muted_rule_b",
"Type": "Boolean"
},
{
"Name": "rule_uuid_g",
"Type": "String"
},
{
"Name": "muted_comment_s",
"Type": "String"
},
{
"Name": "first_seen_t",
"Type": "DateTime"
},
{
"Name": "last_seen_t",
"Type": "DateTime"
},
{
"Name": "created_t",
"Type": "DateTime"
},
{
"Name": "updated_t",
"Type": "DateTime"
},
{
"Name": "uuid_g",
"Type": "String"
},
{
"Name": "status_s",
"Type": "String"
},
{
"Name": "indicators_s",
"Type": "String"
},
{
"Name": "customer_id_s",
"Type": "String"
},
{
"Name": "primary_pdns_hostnames_s",
"Type": "String"
},
{
"Name": "other_pdns_hostnames_s",
"Type": "String"
},
{
"Name": "primary_dhcp_machost_pairs_s",
"Type": "String"
},
{
"Name": "other_dhcp_machost_pairs_s",
"Type": "String"
},
{
"Name": "Category",
"Type": "String"
},
{
"Name": "Type",
"Type": "String"
},
{
"Name": "TimeGenerated",
"Type": "DateTime"
}
]
}

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

@ -0,0 +1,226 @@
{
"Name": "FncEventsObservation_CL",
"Properties": [
{
"Name": "timestamp_t",
"Type": "DateTime"
},
{
"Name": "uuid_g",
"Type": "String"
},
{
"Name": "event_type_s",
"Type": "String"
},
{
"Name": "customer_id_s",
"Type": "String"
},
{
"Name": "sensor_id_s",
"Type": "String"
},
{
"Name": "source_s",
"Type": "String"
},
{
"Name": "evidence_start_timestamp_t",
"Type": "DateTime"
},
{
"Name": "evidence_end_timestamp_t",
"Type": "DateTime"
},
{
"Name": "observation_uuid_g",
"Type": "String"
},
{
"Name": "title_s",
"Type": "String"
},
{
"Name": "confidence_s",
"Type": "String"
},
{
"Name": "src_ip_s",
"Type": "String"
},
{
"Name": "dst_ip_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_internal_b",
"Type": "Boolean"
},
{
"Name": "src_ip_enrichments_geo_location_lat_d",
"Type": "Double"
},
{
"Name": "src_ip_enrichments_geo_location_lon_d",
"Type": "Double"
},
{
"Name": "src_ip_enrichments_geo_country_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_geo_subdivision_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_geo_city_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_asn_asn_d",
"Type": "Int"
},
{
"Name": "src_ip_enrichments_asn_org_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_asn_isp_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_asn_asn_org_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_applications_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_environments_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_locations_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_owners_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_roles_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_tags_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_internal_b",
"Type": "Boolean"
},
{
"Name": "dst_ip_enrichments_geo_location_lat_d",
"Type": "Double"
},
{
"Name": "dst_ip_enrichments_geo_location_lon_d",
"Type": "Double"
},
{
"Name": "dst_ip_enrichments_geo_country_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_geo_subdivision_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_geo_city_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_asn_asn_d",
"Type": "Int"
},
{
"Name": "dst_ip_enrichments_asn_org_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_asn_isp_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_asn_asn_org_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_applications_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_environments_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_locations_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_owners_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_roles_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_tags_s",
"Type": "String"
},
{
"Name": "geo_distance_d",
"Type": "Double"
},
{
"Name": "sensor_ids_s",
"Type": "String"
},
{
"Name": "evidence_iql_s",
"Type": "String"
},
{
"Name": "description_s",
"Type": "String"
},
{
"Name": "context_s",
"Type": "String"
},
{
"Name": "class_s",
"Type": "String"
},
{
"Name": "intel_s",
"Type": "String"
},
{
"Name": "Category",
"Type": "String"
},
{
"Name": "Type",
"Type": "String"
},
{
"Name": "TimeGenerated",
"Type": "DateTime"
}
]
}

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

@ -0,0 +1,330 @@
{
"Name": "FncEventsSuricata_CL",
"Properties": [
{
"Name": "timestamp_t",
"Type": "DateTime"
},
{
"Name": "uuid_g",
"Type": "String"
},
{
"Name": "event_type_s",
"Type": "String"
},
{
"Name": "customer_id_s",
"Type": "String"
},
{
"Name": "sensor_id_s",
"Type": "String"
},
{
"Name": "source_s",
"Type": "String"
},
{
"Name": "src_ip_s",
"Type": "String"
},
{
"Name": "src_port_d",
"Type": "Double"
},
{
"Name": "dest_ip_s",
"Type": "String"
},
{
"Name": "dest_port_d",
"Type": "Double"
},
{
"Name": "proto_s",
"Type": "String"
},
{
"Name": "alert_signature_id_d",
"Type": "Int"
},
{
"Name": "alert_rev_d",
"Type": "Int"
},
{
"Name": "alert_signature_s",
"Type": "String"
},
{
"Name": "alert_category_s",
"Type": "String"
},
{
"Name": "alert_severity_d",
"Type": "Int"
},
{
"Name": "src_ip_enrichments_internal_b",
"Type": "Boolean"
},
{
"Name": "src_ip_enrichments_geo_location_lat_d",
"Type": "Double"
},
{
"Name": "src_ip_enrichments_geo_location_lon_d",
"Type": "Double"
},
{
"Name": "src_ip_enrichments_geo_country_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_geo_subdivision_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_geo_city_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_asn_asn_d",
"Type": "Int"
},
{
"Name": "src_ip_enrichments_asn_org_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_asn_isp_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_asn_asn_org_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_applications_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_environments_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_locations_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_owners_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_roles_s",
"Type": "String"
},
{
"Name": "src_ip_enrichments_annotations_tags_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_internal_b",
"Type": "Boolean"
},
{
"Name": "dst_ip_enrichments_geo_location_lat_d",
"Type": "Double"
},
{
"Name": "dst_ip_enrichments_geo_location_lon_d",
"Type": "Double"
},
{
"Name": "dst_ip_enrichments_geo_country_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_geo_subdivision_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_geo_city_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_asn_asn_d",
"Type": "Int"
},
{
"Name": "dst_ip_enrichments_asn_org_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_asn_isp_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_asn_asn_org_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_applications_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_environments_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_locations_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_owners_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_roles_s",
"Type": "String"
},
{
"Name": "dst_ip_enrichments_annotations_tags_s",
"Type": "String"
},
{
"Name": "geo_distance_d",
"Type": "Double"
},
{
"Name": "http_status_d",
"Type": "Int"
},
{
"Name": "http_protocol_s",
"Type": "String"
},
{
"Name": "http_url_s",
"Type": "String"
},
{
"Name": "http_hostname_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_internal_b",
"Type": "Boolean"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_geo_location_lat_d",
"Type": "Double"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_geo_location_lon_d",
"Type": "Double"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_geo_subdivision_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_geo_city_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_asn_asn_d",
"Type": "Int"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_asn_org_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_asn_isp_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_asn_asn_org_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_geo_country_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_annotations_applications_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_annotations_environments_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_annotations_locations_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_annotations_owners_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_annotations_roles_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_ip_enrichments_annotations_tags_s",
"Type": "String"
},
{
"Name": "http_hostname_enrichments_domain_enrichments_domain_entropy_d",
"Type": "Double"
},
{
"Name": "http_length_d",
"Type": "Int"
},
{
"Name": "http_http_method_s",
"Type": "String"
},
{
"Name": "http_http_content_type_s",
"Type": "String"
},
{
"Name": "http_http_refer_s",
"Type": "String"
},
{
"Name": "http_http_user_agent_s",
"Type": "String"
},
{
"Name": "http_redirect_s",
"Type": "String"
},
{
"Name": "http_xtf_s",
"Type": "String"
},
{
"Name": "payload_s",
"Type": "String"
},
{
"Name": "intel_s",
"Type": "String"
},
{
"Name": "Type",
"Type": "String"
},
{
"Name": "TimeGenerated",
"Type": "DateTime"
}
]
}

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

@ -0,0 +1,62 @@
[{
"vendor": "FortiNDRCloudExample",
"product": "FNC",
"signal_version": "1",
"event_type": "detection",
"subject": "none",
"timestamp": "1970-01-01T15:05:01.139Z",
"device_ip": "192.80.44.123",
"name": "Sample Rule Name",
"category": "Sample Rule Detection Category",
"severity": "low",
"confidence": "high",
"sensor_id": "bob999",
"muted": false,
"muted_rule": false,
"rule_uuid": "65ca67e0-5a28-4eb6-912e-577b93bb3b7f",
"muted_comment": "",
"first_seen": "1970-01-01T14:58:45.447Z",
"last_seen": "1970-01-01T14:59:05.536Z",
"created": "1970-01-01T14:58:45.447Z",
"updated": "1970-01-01T14:58:45.447Z",
"uuid": "2a497a81-3706-42be-8c04-da9f3b66e625",
"status": "active",
"indicators": [
{
"field": "dst.ip",
"values": [
"123.234.456.78"
]
},
{
"field": "ssl:issuer",
"values": [
"Sample usdrasdfkl;jzfg;nmadfg;jdfgSDRESRWERzdfgadf"
]
},
{
"field": "ssl:server_name_indication",
"values": [
"123-234-345-56.fortinet.sample.com"
]
},
{
"field": "ssl:subject",
"values": [
"CN=*.fortinet.sample.com"
]
}
],
"customer_id": "fortindrcloud",
"primary_dhcp_machost_pairs": [
"c1:2a:b3:df:45:46/ENEDEF5EW3"
],
"other_dhcp_machost_pairs": [
"12:3c:0a:g5:12:dc/H1789-9Rp1-12DC",
"12:3c:0a:g5:21:b8/H1789-9Rp1-21B8",
"12:3c:0a:g5:11:34/H1789-9Rp1-1134",
"12:3c:0a:67:3b:14/H1789-9M64-3B14",
"12:3c:0a:67:07:54/H1789-9M64-0754",
"a1:b2:3c:67:tt:po/FOFPL2M0KS2"
]
}]

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

@ -0,0 +1,128 @@
[{
"timestamp": "2023-12-22T20:03:51.544000Z",
"uuid": "6b7aabaf-82c0-4fbf-a930-01e6f6c0d62e",
"event_type": "observation",
"customer_id": "hws",
"sensor_id": "Yli76C",
"source": "Fortinet",
"evidence_start_timestamp": "2024-01-15T05:12:57.608000Z",
"evidence_end_timestamp": "2024-01-15T05:14:57.611000Z",
"observation_uuid": "dd4365b9-7a92-4604-b36b-4c185cacf234",
"title": "Sample Observation Title",
"category": "relationship",
"confidence": "moderate",
"src_ip": "238.74.93.79",
"src_ip_enrichments": {
"internal": true,
"geo": {
"location": {
"lat": 15.313723083291551,
"lon": -52.82257173318456
},
"country": "ZJXNonrYAhqqgftpkVtXbTJPaCVbyV",
"subdivision": "jh5c66RDSlPfWkgAwWksySOxQjJYQk",
"city": "AfyKJjpctINlQWaJkfDmmwxLSkPXTy"
},
"asn": {
"asn": 1765414505,
"org": "SSTargdmXymzkbRjupYpgjWAETwbJw",
"isp": "oqRoFXJmrnUtBUUQUaFXPYLknxTTKr",
"asn_org": "LqdiMMJGYnARWyvqRJiWrmhrqQdcEe"
},
"annotations": {
"applications": [
"XG2IdiPIN",
"RgIrnZu"
],
"environments": [
"UorQ",
"wsQt0q",
"Fx1",
"gWso047"
],
"locations": [
"ik",
"KUB7CKL",
"HvKFh4FF",
"ggV0a8"
],
"owners": [
"ijvNwJeTO",
"gwlGhZ12w"
],
"roles": [
"wRjs",
"TupofYtPH",
"SkBnO",
"TvfZL",
"bY6HOx2"
],
"tags": [
"Dz",
"qXyXh7"
]
}
},
"dst_ip": "230.109.63.180",
"dst_ip_enrichments": {
"internal": true,
"geo": {
"location": {
"lat": 38.77745079152252,
"lon": -77.15990374931947
},
"country": "aooaXFefIledlOAnIXNIiFaYmOHMtF",
"subdivision": "VbYdMDTP93M6NhuZcAzDWJ64qFukws",
"city": "jzBejuNViIzoTaKyMZPEtgcICGcQjD"
},
"asn": {
"asn": 75605248,
"org": "kcbbCpqCgxEIrFtukNqKlIfVuDqFxo",
"isp": "jtvIFfdUwjeHnCNmKiuJoHBGSzuJhT",
"asn_org": "zUVYmVHprxEAfEDgiUZMsbTxXSaEuo"
},
"annotations": {
"applications": [
"KB"
],
"environments": [
"qSZ8scjI",
"exty",
"8s8"
],
"locations": [
"IJvj9E",
"LEhIP7lT"
],
"owners": [
"B",
"4kWqAO",
"5",
"twJzpSZx",
"jhwdjR"
],
"roles": [
"jRyJ69N6F",
"Rx05P",
"s"
],
"tags": [
"aOuuId0A"
]
}
},
"geo_distance": 7.969739952125808E307,
"sensor_ids": [
"Yli76C"
],
"evidence_iql": "src.ip = \"123.234.345.456\" AND dst.ip = \"654.543.432.321\" AND src.port = 123 AND dst.port = 456",
"context": "{\"Operations\":[\"CreateServiceA\",\"StartServiceA\",\"DeleteService\"]}",
"intel": [
{"indicator": "12.34.567.890", "indicator_type": "ip_address", "timestamp": "2023-12-10T16:02:22.898252Z", "confidence": "high", "severity": "moderate", "feed": "sdfgklhjrthbfgUIHHRFahgdfgh", "is_malicious": true, "customer_ids": ["bob123"], "aggregator": null, "meta": "asdofijkadfgDFLjasdl;fS:dfSDFl;kjasdfkl;asdjadfghzvioOISDfjODFJOSDFJdf"},
{"indicator": "23.45.678.901", "indicator_type": "ip_address", "timestamp": "2023-12-11T16:02:22.898252Z", "confidence": "moderate", "severity": "low", "feed": "SDFjSDOIFfasdjfasodfjasdfadf", "is_malicious": true, "customer_ids": ["bob123"], "aggregator": null, "meta": "bjsdfgjkadfl;gjwergijIOFJSDFJr;lgkjadofigjasrgioajdfopigsjdfg"},
{"indicator": "34.56.789.012", "indicator_type": "ip_address", "timestamp": "2023-12-12T16:02:22.898252Z", "confidence": "low", "severity": "moderate", "feed": "OSDIFUERdfjsdfg;FSDDFFDDflkd", "is_malicious": false, "customer_ids": ["bob123"], "aggregator": null, "meta": "werpoituwkl;sjnbskldfgjnl;iojcv;alksdfg'asdfnkfvafga';sdfao"},
{"indicator": "56.78.901.234", "indicator_type": "ip_address", "timestamp": "2023-12-13T16:02:22.898252Z", "confidence": "moderate", "severity": "high", "feed": "zcvijadifopaiDSIDJOISJ23423", "is_malicious": true, "customer_ids": ["bob123"], "aggregator": null, "meta": "kl;cvbnmsdftigjOISDjfIOFjradoifgjaodfgjruighjadfgskdfglija;lkdfjg;"}
],
"description": "Sample Observation Description.",
"class": "specific"
}]

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

@ -0,0 +1,159 @@
[{
"timestamp": "2023-12-22T20:03:51.544000Z",
"uuid": "6b7aabaf-82c0-4fbf-a930-01e6f6c0d62e",
"event_type": "suricata",
"customer_id": "hws",
"sensor_id": "Yli76C",
"source": "Suricata",
"src_ip": "238.74.93.79",
"src_ip_enrichments": {
"internal": true,
"geo": {
"location": {
"lat": 15.313723083291551,
"lon": -52.82257173318456
},
"country": "ZJXNonrYAhqqgftpkVtXbTJPaCVbyV",
"subdivision": "jh5c66RDSlPfWkgAwWksySOxQjJYQk",
"city": "AfyKJjpctINlQWaJkfDmmwxLSkPXTy"
},
"asn": {
"asn": 1765414505,
"org": "SSTargdmXymzkbRjupYpgjWAETwbJw",
"isp": "oqRoFXJmrnUtBUUQUaFXPYLknxTTKr",
"asn_org": "LqdiMMJGYnARWyvqRJiWrmhrqQdcEe"
},
"annotations": {
"applications": [
"XG2IdiPIN",
"RgIrnZu"
],
"environments": [
"UorQ",
"wsQt0q",
"Fx1",
"gWso047"
],
"locations": [
"ik",
"KUB7CKL",
"HvKFh4FF",
"ggV0a8"
],
"owners": [
"ijvNwJeTO",
"gwlGhZ12w"
],
"roles": [
"wRjs",
"TupofYtPH",
"SkBnO",
"TvfZL",
"bY6HOx2"
],
"tags": [
"Dz",
"qXyXh7"
]
}
},
"src_port": 12569,
"dest_ip": "230.109.63.180",
"dst_ip_enrichments": {
"internal": true,
"geo": {
"location": {
"lat": 38.77745079152252,
"lon": -77.15990374931947
},
"country": "aooaXFefIledlOAnIXNIiFaYmOHMtF",
"subdivision": "VbYdMDTP93M6NhuZcAzDWJ64qFukws",
"city": "jzBejuNViIzoTaKyMZPEtgcICGcQjD"
},
"asn": {
"asn": 75605248,
"org": "kcbbCpqCgxEIrFtukNqKlIfVuDqFxo",
"isp": "jtvIFfdUwjeHnCNmKiuJoHBGSzuJhT",
"asn_org": "zUVYmVHprxEAfEDgiUZMsbTxXSaEuo"
},
"annotations": {
"applications": [
"KB"
],
"environments": [
"qSZ8scjI",
"exty",
"8s8"
],
"locations": [
"IJvj9E",
"LEhIP7lT"
],
"owners": [
"B",
"4kWqAO",
"5",
"twJzpSZx",
"jhwdjR"
],
"roles": [
"jRyJ69N6F",
"Rx05P",
"s"
],
"tags": [
"aOuuId0A"
]
}
},
"geo_distance": 7.969739952125808E307,
"dest_port": 27567,
"proto": "gr6C1a2gRVoyc6XVmr2W",
"alert": {
"gid": 2121495645,
"signature_id": 2843301883188533248,
"rev": 1204256967,
"signature": "1zxcM49pPaWQaXvRoxvF",
"category": "uxqXdYR5AtF71Qv0ss1l",
"severity": 596603172
},
"http": {
"status": 2142954575,
"protocol": "WidPnn3Wh6dgFJWtg76J",
"url": "Vm3mNRW1MVlFLR6Qcgz4",
"hostname": "vyNEAwnvr1J0zWbye5AD",
"hostname_enrichments": {
"ip_enrichments": null,
"domain_enrichments": {
"domain_entropy": 1.6027313483366948E308
}
},
"length": 2509176891212047360,
"http_method": "WWMFjeIvsVl0UgSsB2Et",
"http_content_type": "3Mik1hKDUUBDFxT1TAnJ",
"http_refer": "pirALwUM90ArBV1ozWiO",
"http_user_agent": "aB2bGN3r2xb77dkDdWCz",
"redirect": "UNEImrJLYEJ31WxFarFq",
"xff": "uGTG6tcYRvZpPa09mKhI"
},
"payload": "DKM1pVbM1SDnWnIYyyqp",
"intel": [
{
"indicator": "http://UcEQISIgTbWCsBvjcEcCuMIQhxYDhZhwzElwIOZddCfklhFJ.WJNWNtVAvbYinLIXpJe.SdkDewBDMaBcoiLlegQMVhfUrihDrKgaplPrIEhNcjbt.gRPjiDATneCR.IJNreZjOCebWrSvXZIFgAAXXvWncYAGpceUBRbRCJoHeebHUQMIeICQtzcXEvPd.BOifnwfUruejtkKJoNXP?UqGuJkebGGoGvrxVkRxCxogrjJDeaV=3SDQJZ0j8EmFhxXnlcseJqHQxMTvVm",
"indicator_type": "url",
"timestamp": "1970-01-24T00:25:03.731000Z",
"confidence": "high",
"severity": "moderate",
"feed": "94",
"is_malicious": true,
"customer_ids": [
"guokN59jSlYJ5bouFn9Fyc36tmLJv0",
"5pJvH0cw240ZGIcbToyiaJIVePg2Xr",
"aSy5MWlvhRGyUBnG2xE6FBErFQEgrW",
"vGKqpD9I6BJzqJWql3ftRrEu32Iou8"
],
"aggregator": "9bniCI45031Ye01WwhFhoi2vBZhNmY",
"meta": "GEPlZeEAIZymjKss5EYQbpBwj5Gy6H"
}
]
}]

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

@ -0,0 +1,200 @@
[{
"timestamp": "2024-01-03T15:17:32.537000Z",
"uuid": "fa42c375-a313-437a-8d30-5a498d787693",
"event_type": "suricata",
"customer_id": "kep",
"sensor_id": "618Fly",
"source": "Suricata",
"src_ip": "7.70.40.168",
"src_ip_enrichments": {
"internal": false,
"geo": {
"location": {
"lat": -56.58733456686193,
"lon": -132.7164747659492
},
"country": "uPLnDOHtEGjTLnaTweeDKBoPzgqEYb",
"subdivision": "0s9wnbsjpUH6qv4AyMWa6MHdugK87y",
"city": "fhjtlvWTETtjYLrXgWSyZAfUqfxFhO"
},
"asn": {
"asn": 1579573468,
"org": "hObohPbedoEsJFnrSjpOjhmrTJBfQT",
"isp": "LwdwmCRSdJnOWjHQLbNsnrOSeNKNQu",
"asn_org": "qvQjCeBbmNBRTcRVCAAhYkOWIQbZQz"
},
"annotations": {
"applications": [
"8N9rwf",
"L",
"SHV6SuSfm"
],
"environments": [
"EIy6Rqy",
"zU"
],
"locations": [
"h9rmc",
"whctigB",
"BelZyc"
],
"owners": [
"fXp4iRU",
"w",
"Fsc1aC",
"s",
"4UUqws6H"
],
"roles": [
"OmFp08pdZ",
"QIC",
"PbMJBcvs",
"IJiymzt"
],
"tags": [
"oLrpApMK5"
]
}
},
"src_port": 44961,
"dest_ip": "195.153.43.186",
"dst_ip_enrichments": {
"internal": true,
"geo": {
"location": {
"lat": 16.051329125427948,
"lon": 31.744029699611797
},
"country": "UsVqwowturHLEaoskCEJCGktAfqDkV",
"subdivision": "nWLowh9qXx1EIxRToJ0VozQBXYtANY",
"city": "OyGxPtJUBFcSxEIEthEYzoFJvGyvRg"
},
"asn": {
"asn": 675464323,
"org": "lkZuoSEUIDFSMCozonxWRqKukxJrtQ",
"isp": "hxBBfKFzojTVozMWhLOwoTakIQEymU",
"asn_org": "qbUGKjpRxhTEkDZlIROuDDHvjOPNbs"
},
"annotations": {
"applications": [
"guThX",
"Foh"
],
"environments": [
"HFBT",
"D08O5lBQB"
],
"locations": [
"R8Uqtk",
"E4L3X",
"g6"
],
"owners": [
"CdOM4P7r",
"5M",
"n",
"20j",
"ie9Qg"
],
"roles": [
"Reug6",
"D7I"
],
"tags": [
"7j",
"Rby",
"q"
]
}
},
"geo_distance": 3.843256997016675E306,
"dest_port": 45347,
"proto": "9JCamj2bhPDVfbWeuyaz",
"alert": {
"gid": 807114439,
"signature_id": 6980346026415599616,
"rev": 1881245527,
"signature": "VbFF6W8KFvFMgdWtHg0v",
"category": "u22N835x9Rkz1geeAfmu",
"severity": 1561098741
},
"http": {
"status": 16169864,
"protocol": "TiX7UWD17nyOEj5VZ8PE",
"url": "yAwpyhWdXflR5iXI5iLX",
"hostname": "10.1.25.26",
"hostname_enrichments": {
"ip_enrichments": {
"internal": true,
"geo": {
"location": {
"lat": 30.3985599356892,
"lon": 95.85731456777427
},
"country": "gWNKKjBwaodFYUxMiPIMebssgBMpxG",
"subdivision": "KSDTxgXXJEXihPDZBfRuqTo9TjblvF",
"city": "YfhBldthxooCdYNPkiPqjJZbxqrhFX"
},
"asn": {
"asn": 2064822871,
"org": "mZgrHibcGtDXwZZGxEoeeypyeKXNjS",
"isp": "ktSKKTyPaTBlTKGvnXBgtJThzdDZjd",
"asn_org": "QLxDmVHaiKihJEVpxEEZXwwjWLoHle"
},
"annotations": {
"applications": [
"RbnD9qIYY",
"gI51sSYLg"
],
"environments": [
"0mivVw",
"m9wPswnJS",
"brl",
"YWDFei"
],
"locations": [
"vJztDx",
"jE",
"DSLRCN",
"gT",
"1n"
],
"owners": [
"qxsY"
],
"roles": [
"DXz"
],
"tags": [
"nxBj"
]
}
},
"domain_enrichments": null
},
"length": 3787690537907247104,
"http_method": "zu7rToinmmNgd52cmEYh",
"http_content_type": "VODGhG7DHup65eNvQzhU",
"http_refer": "kjIOSp5isxUzAstHxxeH",
"http_user_agent": "Ho3kgsmsQmT0GuIkGEg2",
"redirect": "Qoor9U16hba0nI9ajbPA",
"xff": "31L9NVpqdO7CBlPQZvdv"
},
"payload": "SsmQ1i318x6N07kT7DBo",
"intel": [
{
"indicator": "191.132.127.119",
"indicator_type": "cidr",
"timestamp": "1970-01-05T05:43:26.246000Z",
"confidence": "high",
"severity": "high",
"feed": "4217508",
"is_malicious": true,
"customer_ids": [
"P9kuMHc3CTHNFdTKrNvfWekeMvJS9v"
],
"aggregator": "9vtKfV9cMtoHfZrsOO8FgdxBcu2lIl",
"meta": "AanYoutCTr2VYpK3LT8slWCyRJYZaL"
}
]
}]

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

@ -0,0 +1,167 @@
{
"id": "3a7ee0fe-ba5e-4588-a0b2-9818a67746f8",
"title": "Fortinet FortiNDR Cloud",
"publisher": "Fortinet",
"descriptionMarkdown": "The Fortinet FortiNDR Cloud data connector provides the capability to ingest [Fortinet FortiNDR Cloud](https://docs.fortinet.com/product/fortindr-cloud) events stored in Amazon S3 into Microsoft Sentinel using the Amazon S3 REST API.",
"additionalRequirementBanner": "These queries and workbooks are dependent on a parser based on Kusto to work as expected. Follow the steps to use this Kusto functions alias **Fortinet_FortiNDR_Cloud** in queries and workbooks. [Follow steps to get this Kusto functions>]() ",
"graphQueries": [
{
"metricName": "Fortinet FortiNDR Cloud Suricata Logs",
"legend": "FncEventsSuricata_CL",
"baseQuery": "FncEventsSuricata_CL"
},
{
"metricName": "Fortinet FortiNDR Cloud Observation Logs",
"legend": "FncEventsObservation_CL",
"baseQuery": "FncEventsObservation_CL"
},
{
"metricName": "Fortinet FortiNDR Cloud Detections Logs",
"legend": "FncEventsDetections_CL",
"baseQuery": "FncEventsDetections_CL"
}
],
"sampleQueries": [
{
"description" : "Fortinet FortiNDR Cloud Suricata Logs",
"query": "FncEventsSuricata_CL\n | sort by TimeGenerated desc"
},
{
"description" : "Fortinet FortiNDR Cloud Observation Logs",
"query": "FncEventsObservation_CL\n | sort by TimeGenerated desc"
},
{
"description" : "Fortinet FortiNDR Cloud Detections Logs",
"query": "FncEventsDetections_CL\n | sort by TimeGenerated desc"
}
],
"dataTypes": [
{
"name": "FncEventsSuricata_CL",
"lastDataReceivedQuery": "FncEventsSuricata_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
},
{
"name": "FncEventsObservation_CL",
"lastDataReceivedQuery": "FncEventsObservation_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
},
{
"name": "FncEventsDetections_CL",
"lastDataReceivedQuery": "FncEventsDetections_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
}
],
"connectivityCriterias": [
{
"type": "IsConnectedQuery",
"value": [
"FncEventsSuricata_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)",
"FncEventsObservation_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)",
"FncEventsDetections_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)"
]
}
],
"availability": {
"status": 1,
"isPreview": true
},
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "read and write permissions on the workspace are required.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"write": true,
"read": true,
"delete": true
}
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {
"action": true
}
}
],
"customs": [
{
"name": "Microsoft.Web/sites permissions",
"description": "Read and write permissions to Azure Functions to create a Function App is required. [See the documentation to learn more about Azure Functions](https://docs.microsoft.com/azure/azure-functions/)."
},
{
"name": "Amazon S3 REST API Credentials/permissions",
"description": "**AWS Access Key Id**, **AWS Secret Access Key**, **FortiNDR Cloud Account Code** are required for Amazon S3 REST API."
}
]
},
"instructionSteps": [
{
"title": "",
"description": ">**NOTE:** This connector uses Azure Functions to connect to the Amazon S3 REST API to pull logs into Microsoft Sentinel. This might result in additional data ingestion costs. Check the [Azure Functions pricing page](https://azure.microsoft.com/pricing/details/functions/) for details."
},
{
"title": "",
"description": ">**(Optional Step)** Securely store workspace and API authorization key(s) or token(s) in Azure Key Vault. Azure Key Vault provides a secure mechanism to store and retrieve key values. [Follow these instructions](https://docs.microsoft.com/azure/app-service/app-service-key-vault-references) to use Azure Key Vault with an Azure Function App."
},
{
"title": "",
"description": ">**NOTE:** This connector uses a parser based on a Kusto Function to normalize fields. [Follow these steps](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Fortinet FortiNDR Cloud/Parsers/Fortinet_FortiNDR_Cloud) to create the Kusto function alias **Fortinet_FortiNDR_Cloud**."
},
{
"title": "",
"description": "**STEP 1 - Configuration steps for the Fortinet FortiNDR Cloud Logs Collection**\n\nThe provider should provide or link to detailed steps to configure the 'PROVIDER NAME APPLICATION NAME' API endpoint so that the Azure Function can authenticate to it successfully, get its authorization key or token, and pull the appliance's logs into Azure Sentinel."
},
{
"title": "",
"description": "**STEP 2 - Choose ONE from the following two deployment options to deploy the connector and the associated Azure Function**\n\n>**IMPORTANT:** Before deploying the Fortinet FortiNDR Cloud connector, have the Workspace ID and Workspace Primary Key (can be copied from the following), as well as the as well as the Amazon S3 REST API Authorization credentials, readily available.",
"instructions": [
{
"parameters": {
"fillWith": [
"WorkspaceId"
],
"label": "Workspace ID"
},
"type": "CopyableLabel"
},
{
"parameters": {
"fillWith": [
"PrimaryKey"
],
"label": "Primary Key"
},
"type": "CopyableLabel"
}
]
},
{
"title": "",
"description": "**Option 1 - Azure Resource Manager (ARM) Template**\n\nUse this method for automated deployment of the Fortinet FortiNDR Cloud connector.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](<Add Link to ARM Template on https://aka.ms/threathunter GitHub repo, name template as azuredeploy_Connector_PROVIDER_NAME_APPLIANCE_NAME_AzureFunction.json>)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the **Workspace ID**, **Workspace Key**, **AwsAccessKeyId**, **AwsSecretAccessKey**, and/or Other required fields. \n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**. \n5. Click **Purchase** to deploy."
},
{
"title": "",
"description": "**Option 2 - Manual Deployment of Azure Functions**\n\n Use the following step-by-step instructions to deploy the Fortinet FortiNDR Cloud connector manually with Azure Functions(Deployment via Visual Studio Code).",
"instructions": [
{
"parameters": {
"instructionSteps": [
{
"title": "Step 1 - Deploy a Function App",
"description": "**NOTE:** You will need to [prepare VS code](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-python) for Azure Functions development.\n\n1. Download the [Azure Functions App]() file. Extract archive to your local development computer.\n2. Follow the [function app manual deployment instructions](https://github.com/Azure/Azure-Sentinel/blob/master/DataConnectors/AzureFunctionsManualDeployment.md#function-app-manual-deployment-instructions) to deploy the Azure Functions app using VSCode.\n3. After successful deployment of the function app, follow next steps for configuring it."
},
{
"title": "Step 2 - Configure the Function App",
"description": "1. In the Function App, select the Function App Name and select **Configuration**.\n2. In the **Application settings** tab, select **+ New application setting**.\n3. Add each of the following application settings individually, with their respective string values (case-sensitive): \n\t\tWorkspaceId\n\t\tWorkspaceKey\n\t\tAWSAccessKeyId\n\t\tAWSSecretAccessKey\n\t\tFncAccountCode\n\t\tFncEvents (optional default: observation,detections)\n\t\tFncTerminateApp (optional default: false)\n\t\tFncDaysToCollect(optional default: 7)\n\t\tFncIntervalMinutes (optional, default 5)\n\t\tlogAnalyticsUri (optional)\n> - Use logAnalyticsUri to override the log analytics API endpoint for dedicated cloud. For example, for public cloud, leave the value empty; for Azure GovUS cloud environment, specify the value in the following format: `https://<CustomerId>.ods.opinsights.azure.us`.\n3. Once all application settings have been entered, click **Save**."
}
]
},
"type": "InstructionStepsGroup"
}
]
}
]
}

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

@ -0,0 +1,251 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"FunctionName": {
"defaultValue": "FortiNDR Cloud",
"minLength": 1,
"maxLength": 20,
"type": "string"
},
"WorkspaceId": {
"type": "string",
"defaultValue": "<WorkspaceId>"
},
"WorkspaceKey": {
"type": "securestring",
"defaultValue": "<workspaceKey>"
},
"AwsAccessKeyId": {
"type": "string",
"defaultValue": "<AwsAccessKeyId>"
},
"AwsSecretAccessKey": {
"type": "securestring",
"defaultValue": "<AwsSecretAccessKey>"
},
"FncAccountCode": {
"type": "string",
"defaultValue": "<enter the FortiNDR Cloud account code here>"
},
"FncEvents": {
"type": "string",
"defaultValue": "observation,detections"
},
"FncTerminateApp": {
"type": "bool",
"defaultValue": false
},
"FncDaysToCollect": {
"type": "int",
"defaultValue": 7
},
"FncIntervalMinutes": {
"type": "int",
"defaultValue": 5
}
},
"variables": {
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]",
"StorageSuffix": "[environment().suffixes.storage]",
"LogAnalyticsUri": "[replace(environment().portal, 'https://portal', concat('https://', toLower(parameters('WorkspaceId')), '.ods.opinsights'))]"
},
"resources": [
{
"type": "Microsoft.Insights/components",
"apiVersion": "2015-05-01",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"kind": "web",
"properties": {
"Application_Type": "web",
"ApplicationId": "[variables('FunctionName')]"
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[tolower(variables('FunctionName'))]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [
],
"ipRules": [
],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"keyType": "Account",
"enabled": true
},
"blob": {
"keyType": "Account",
"enabled": true
}
},
"keySource": "Microsoft.Storage"
}
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2018-02-01",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Y1",
"tier": "Dynamic"
},
"kind": "functionapp",
"properties": {
"name": "[variables('FunctionName')]",
"workerSize": "0",
"workerSizeId": "0",
"numberOfWorkers": "1"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"cors": {
"corsRules": [
]
},
"deleteRetentionPolicy": {
"enabled": false
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"cors": {
"corsRules": [
]
}
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]",
"[resourceId('Microsoft.Web/serverfarms', variables('FunctionName'))]",
"[resourceId('Microsoft.Insights/components', variables('FunctionName'))]"
],
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"name": "[variables('FunctionName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('FunctionName'))]",
"httpsOnly": true,
"clientAffinityEnabled": true,
"alwaysOn": true,
"reserved": true,
"siteConfig": {
"linuxFxVersion": "python|3.9"
}
},
"resources": [
{
"apiVersion": "2018-11-01",
"type": "config",
"name": "appsettings",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('FunctionName'))]"
],
"properties": {
"FUNCTIONS_EXTENSION_VERSION": "~4",
"FUNCTIONS_WORKER_RUNTIME": "python",
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.insights/components', variables('FunctionName')), '2015-05-01').InstrumentationKey]",
"APPLICATIONINSIGHTS_CONNECTION_STRING": "[reference(resourceId('microsoft.insights/components', variables('FunctionName')), '2015-05-01').ConnectionString]",
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]",
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]",
"WEBSITE_CONTENTSHARE": "[toLower(variables('FunctionName'))]",
"WorkspaceId": "[parameters('WorkspaceID')]",
"WorkspaceKey": "[parameters('WorkspaceKey')]",
"AwsAccessKeyId": "[parameters('AwsAccessKeyId')]",
"AwsSecretAccessKey": "[parameters('AwsSecretAccessKey')]",
"FncAccountCode":"[parameters('FncAccountCode')]",
"FncEvents": "[parameters('FncEvents')]",
"FncTerminateApp": "[parameters('FncTerminateApp')]",
"FncDaysToCollect": "[parameters('FncDaysToCollect')]",
"FncIntervalMinutes": "[parameters('FncIntervalMinutes')]",
"logAnalyticsUri": "[variables('LogAnalyticsUri')]",
"WEBSITE_RUN_FROM_PACKAGE": "<add link to zip>"
}
}
]
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-hosts')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-secrets')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/', tolower(variables('FunctionName')))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"shareQuota": 5120
}
}
]
}

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

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

@ -0,0 +1,80 @@
import logging
import os
from datetime import datetime, timezone
from metastream import fetch_detections, fetch_events
from metastream.s3_client import Context
from sentinel import post_data
from globalVariables import SUPPORTED_EVENT_TYPES
AWS_ACCESS_KEY = os.environ.get('AwsAccessKeyId')
AWS_SECRET_KEY = os.environ.get('AwsSecretAccessKey') # is this encrypted
ACCOUNT_CODE = os.environ.get("FncAccountCode")
def main(args: dict) -> str:
validate_args(args)
event_type = args.get('event_type', '')
checkpoint = args.get('checkpoint', '')
if not checkpoint:
return ""
logging.info(
f'FetchAndSendActivity: event type: {event_type} checkpoint: {checkpoint}')
ctx = Context()
start_date = datetime.fromisoformat(checkpoint).replace(tzinfo=timezone.utc)
try:
if event_type == 'detections':
fetch_and_send_detections(ctx, event_type, start_date)
else:
fetch_and_send_events(ctx, event_type, start_date)
new_checkpoint = ctx.checkpoint.isoformat()
except Exception as ex:
logging.error(
f"Failure: FetchAcndSendActivity: event: {event_type} checkpoint: {checkpoint} error: {str(ex)}")
raise Exception(
f"Failure: FetchAcndSendActivity: event: {event_type} error: {str(ex)}")
return new_checkpoint
def validate_args(args: dict):
event_type = args.get('event_type', '')
if not event_type or not event_type in SUPPORTED_EVENT_TYPES:
raise AttributeError(
"Event type was not provided or it is not supported. Event type must be one of (Observation | Suricata | Detection).")
def post_events_inc(events, event_type):
limit = 5000
count = len(events)
start = 0
while start < count:
end = count if count - start <= limit else start + limit
post_data(events[start:end], event_type)
start = start + limit
def fetch_and_send_events(ctx: Context, event_type: str, start_date: datetime):
for events in fetch_events(context=ctx,
name='sentinel',
event_types=[event_type],
account_code=ACCOUNT_CODE,
start_date=start_date,
access_key=AWS_ACCESS_KEY,
secret_key=AWS_SECRET_KEY):
post_events_inc(events, event_type)
def fetch_and_send_detections(ctx: Context, event_type: str, start_date: datetime):
for events in fetch_detections(context=ctx,
name='sentinel',
account_code=ACCOUNT_CODE,
start_date=start_date,
access_key=AWS_ACCESS_KEY,
secret_key=AWS_SECRET_KEY):
post_events_inc(events, event_type)

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

@ -0,0 +1,10 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "args",
"type": "activityTrigger",
"direction": "in"
}
]
}

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

@ -0,0 +1,80 @@
import logging
import os
from datetime import date, datetime, timedelta, timezone
from metastream import fetch_detections_by_day, fetch_events_by_day
from metastream.s3_client import Context
from sentinel.sentinel import post_data
from globalVariables import SUPPORTED_EVENT_TYPES
AWS_ACCESS_KEY = os.environ.get('AwsAccessKeyId')
AWS_SECRET_KEY = os.environ.get('AwsSecretAccessKey')
ACCOUNT_CODE = os.environ.get("FncAccountCode")
def main(args: dict) -> str:
validate_args(args)
event_type = args.get('event_type', '')
day: int = args.get('day', '')
try:
ctx = Context()
start_day = datetime.now(tz=timezone.utc) - timedelta(days=day)
logging.info(
f'FetchAndSendByDayActivity: event: {event_type} day: {start_day.date()}')
if event_type == 'detections':
fetch_and_post_detections(ctx, event_type, start_day.date())
else:
fetch_and_post_events(ctx, event_type, start_day)
# it's required to return something that is json serializable
return 'success'
except Exception as ex:
logging.error(
f'Failure: FetchAndSendByDayActivity: event: {event_type} day: {start_day.date()} error: {str(ex)}')
raise Exception(
f"Failure: FetchAndSendByDayActivity failed. Event: {event_type} error: {str(ex)}")
def validate_args(args: dict):
event_type = args.get('event_type', '').lower()
day: int = args.get('day', '')
if not event_type or not event_type in SUPPORTED_EVENT_TYPES:
raise AttributeError(
"Event type was not provided or it is not supported. Event type must be one of (Observation | Suricata | Detection).")
if not day:
raise AttributeError(
"The day for which to retrieve event is required for the FetchAndSendByDayActivity.")
def post_events_inc(events, event_type):
limit = 5000
count = len(events)
start = 0
while start < count:
end = count if count - start <= limit else start + limit
post_data(events[start:end], event_type)
start = start + limit
def fetch_and_post_events(ctx: Context, event_type: str, start_day: datetime):
for events in fetch_events_by_day(context=ctx,
name='sentinel',
event_type=event_type,
account_code=ACCOUNT_CODE,
day=start_day,
access_key=AWS_ACCESS_KEY,
secret_key=AWS_SECRET_KEY):
post_events_inc(events, event_type)
def fetch_and_post_detections(ctx: Context, event_type: str, start_day: date):
for events in fetch_detections_by_day(context=ctx,
name='sentinel',
account_code=ACCOUNT_CODE,
day=start_day,
access_key=AWS_ACCESS_KEY,
secret_key=AWS_SECRET_KEY):
post_events_inc(events, event_type)

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

@ -0,0 +1,10 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "args",
"type": "activityTrigger",
"direction": "in"
}
]
}

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

@ -0,0 +1,95 @@
import logging
import os
from datetime import datetime, timedelta, timezone
from azure.durable_functions.models import DurableOrchestrationStatus
import azure.durable_functions as df
import azure.functions as func
from metastream.errors import InputError
from globalVariables import ORCHESTRATION_NAME, SUPPORTED_EVENT_TYPES
NOT_RUNNING_FUNCTION_STATES = [
df.OrchestrationRuntimeStatus.Completed,
df.OrchestrationRuntimeStatus.Failed,
df.OrchestrationRuntimeStatus.Terminated,
None
]
EVENT_TYPES = (os.environ.get("FncEvents") or "observation").split(",")
EVENT_TYPES = [event.strip() for event in EVENT_TYPES if event]
TERMINATE_APP = os.environ.get("FncTerminateApp").strip().lower() == 'true'
try:
DAYS_TO_COLLECT = int(os.environ.get("FncDaysToCollect") or 7)
except ValueError:
DAYS_TO_COLLECT = None
try:
INTERVAL = int(os.environ.get("FncIntervalMinutes") or "5")
except ValueError:
INTERVAL = None
def validate_configuration():
if EVENT_TYPES and not SUPPORTED_EVENT_TYPES.issuperset(EVENT_TYPES):
raise InputError(
f"FncEvents must be one or more of {SUPPORTED_EVENT_TYPES}")
sentinel_shared_key = (os.environ.get('WorkspaceKey') or '').strip()
if not sentinel_shared_key:
raise InputError(f'WorkspaceKey is required.')
if INTERVAL is None or INTERVAL < 1 or INTERVAL > 60:
raise InputError(f'FncIntervalMinutes must be a number 1-60')
if DAYS_TO_COLLECT and (DAYS_TO_COLLECT < 0 or DAYS_TO_COLLECT > 7):
raise InputError(f'FncDaysToCollect must be a number 0-7')
async def main(mytimer: func.TimerRequest, starter: str) -> None:
client = df.DurableOrchestrationClient(starter)
instance_id = "FncIntegrationSentinelStaticInstanceId"
existing_instance = await client.get_status(instance_id)
logging.info(
f'OrchestratorWatchdog: {ORCHESTRATION_NAME} status: {existing_instance.runtime_status}')
if TERMINATE_APP:
reason = f'FncTerminateApp set to {TERMINATE_APP}'
await terminate_app(client, existing_instance.runtime_status, instance_id, reason)
return
# Only start the orchestrator if it's not already running.
if existing_instance.runtime_status in NOT_RUNNING_FUNCTION_STATES:
validate_configuration()
await client.start_new(ORCHESTRATION_NAME, instance_id, create_args())
logging.info(f"OrchestratorWatchdog: Started {ORCHESTRATION_NAME}")
async def terminate_app(client, status, instance_id, reason: str):
if status not in NOT_RUNNING_FUNCTION_STATES:
await client.terminate(instance_id=instance_id, reason=reason)
logging.info(
f'OrchestrationWatchdog: Termination request sent to {ORCHESTRATION_NAME}.')
def create_args():
timestamp = datetime.now(tz=timezone.utc)
days_to_collect = DAYS_TO_COLLECT if DAYS_TO_COLLECT else 0
if DAYS_TO_COLLECT:
start_date = timestamp.replace(hour=0, minute=0, second=0).isoformat()
else:
start_date = (timestamp - timedelta(minutes=INTERVAL)).isoformat()
args = {}
args['event_types'] = {
event_type.strip(): {
"checkpoint": start_date,
"days_to_collect": days_to_collect
}
for event_type in EVENT_TYPES
}
args['interval'] = INTERVAL
return args

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

@ -0,0 +1,17 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "mytimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 0 */6 * * *",
"runOnStartup": true
},
{
"type": "orchestrationClient",
"direction": "in",
"name": "starter"
}
]
}

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

@ -0,0 +1,89 @@
import logging
from datetime import timedelta
import azure.durable_functions as df
def orchestrator_function(context: df.DurableOrchestrationContext):
args: dict = context.get_input()
event_types: dict = args.get('event_types')
interval: int = args.get('interval')
logging.info(
f'SingletonEternalOrchestrator: event_types: {list(event_types)} instance_id: {context.instance_id}')
if not event_types:
return
# Retrieving full days for each event_type one by one
failing = args.get('failing', [])
for event_type, event_type_args in event_types.items():
if event_type in failing:
continue
attempt = event_type_args.get('attempt', 0)
remaining_days = event_type_args['days_to_collect']
if remaining_days > 0 and attempt <= 3:
try:
yield context.call_activity('FetchAndSendByDayActivity', {'day': remaining_days, 'event_type': event_type})
event_types[event_type]['days_to_collect'] = remaining_days-1
event_type_args['attempt'] = 0
except Exception as ex:
logging.error(f'Error when fetching events by day with event_type => {event_type} error => {ex}')
attempt += 1
event_types[event_type]['attempt'] = attempt
if attempt <= 3:
logging.info(f"Retrying attempt {attempt}.")
else:
failing.append(event_type)
args['failing'] = failing
# Run the orchastrator new for each day to help avoid timeouts.
args['event_types'] = event_types
context.continue_as_new(args)
return
# Retrieving piece of a day for each event_type one by one
retrieved = args.get('retrieved', [])
for event_type, event_type_args in event_types.items():
attempt = event_type_args.get('attempt', 0)
if event_type in failing or event_type in retrieved or attempt > 3:
continue
try:
checkpoint = event_type_args['checkpoint']
next_checkpoint = yield context.call_activity('FetchAndSendActivity', {'checkpoint': checkpoint, 'event_type': event_type})
event_types[event_type]['checkpoint'] = next_checkpoint
retrieved.append(event_type)
args['retrieved'] = retrieved
event_type_args['attempt'] = 0
except Exception as ex:
logging.error(f'Error when fetching events by checkpoints with event_type => {event_type} error => {ex}')
attempt += 1
event_types[event_type]['attempt'] = attempt
if attempt <= 3:
logging.info(f"Retrying attempt {attempt}.")
else:
failing.append(event_type)
args['failing'] = failing
args['event_types'] = event_types
context.continue_as_new(args)
return
retrieved_events = args.get('retrieved', 'none')
failed_events = args.get('failing', 'none')
logging.info(f'Fech events finished. Retrieved Events: {retrieved_events}, Failed Events: {failed_events}')
args.pop('retrieved', None)
args.pop('failing', None)
for event_type_args in event_types.values():
event_type_args['attempt'] = 0
args['event_types'] = event_types
# sleep
logging.info(
f'SingletonEternalOrchestrator: Sleeping for {interval} minutes')
yield context.create_timer(context.current_utc_datetime + timedelta(minutes=interval))
logging.info(
f'SingletonEternalOrchestrator: Woke up and will continue as new.')
context.continue_as_new(args)
main = df.Orchestrator.create(orchestrator_function)

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

@ -0,0 +1,10 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "context",
"type": "orchestrationTrigger",
"direction": "in"
}
]
}

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

@ -0,0 +1,13 @@
SUPPORTED_EVENT_TYPES = set(['observation', 'suricata', 'detections'])
ORCHESTRATION_NAME = 'SingletonEternalOrchestrator'
AUTH_URLS = {
"production": "auth.icebrg.io",
"uat": "auth-uat.icebrg.io"
}
BUCKETS = {
"production": "fortindr-cloud-metastream",
"uat": "fortindr-cloud-metastream-uat"
}

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

@ -0,0 +1 @@
from .metastream import fetch_events_by_day, fetch_events, fetch_event_types, fetch_detections, fetch_detections_by_day

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

@ -0,0 +1,56 @@
import http.client
import json
from globalVariables import AUTH_URLS
from .errors import InputError
def _get_auth_url(env):
auth_url = AUTH_URLS.get(env)
if not auth_url:
raise InputError(f"no auth url defined for environment '{env}'")
return auth_url
class Auth:
def __init__(self, token, env):
self.token = token
self.env = env
def __enter__(self):
self.connection = _Auth(self.token).connect(self.env)
return self.connection
def __exit__(self, exc_type, exc_val, exc_tb):
self.connection.conn.close()
class _Auth:
def __init__(self, token):
self.conn = None
self._headers = {"Authorization": f"IBToken {token}"}
def connect(self, env: str):
auth_url = _get_auth_url(env)
self.conn = http.client.HTTPSConnection(auth_url)
return self
def user(self) -> dict:
url = "/v1/authenticate/self"
user = self._get(url).get("user")
if not user:
raise InputError("unable to get user from auth")
return user
def account(self, account_uuid: str) -> dict:
url = f"/v1/account/{account_uuid}"
account = self._get(url).get("account")
if not account:
raise InputError("unable to get account from auth")
return account
def _get(self, url: str) -> dict:
self.conn.request("GET", url, headers=self._headers)
r = self.conn.getresponse()
if 200 > r.status > 300:
raise InputError(f"unable to contact auth: {r.status} {r.reason}")
return json.loads(r.read())

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

@ -0,0 +1,18 @@
class BaseError(Exception):
"""Base class for metastream client errors"""
def __init__(self, code, message):
self.code = code
self.message = message
super().__init__(message)
class InputError(BaseError):
"""Exception raised for user input errors"""
def __init__(self, message):
super().__init__(code=0, message=message)
class ServerError(BaseError):
"""Exception raised for server side errors"""
pass

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

@ -0,0 +1,255 @@
import os.path
from datetime import datetime, timedelta, timezone, date
from typing import List
from globalVariables import SUPPORTED_EVENT_TYPES, BUCKETS
from .s3_client import S3Client, Context
from .auth_client import Auth
from .errors import InputError, ServerError
def _validate_start_date(start_date: datetime, checkpoint: datetime):
if start_date > checkpoint:
raise InputError(message="start_date must be at least 1 second in the past")
delta = checkpoint - start_date
if delta > timedelta(days=1):
raise InputError(message="start_date must be within the last 24 hours")
def _validate_day(day: date):
if (datetime.now(timezone.utc).date() - day).days > 7:
raise InputError(message="day must be within 7 days")
def _validate_event_types(event_types):
if not all(e in SUPPORTED_EVENT_TYPES for e in event_types):
raise InputError(f'event_types must be of the following: {", ".join(SUPPORTED_EVENT_TYPES)}')
def _validate_limit(limit: int):
if limit < 1 or limit > 10_000:
raise InputError('limit must be between 1 and 10,000')
def _basename(prefix):
return os.path.basename(prefix.rstrip('/'))
def _prefix_to_datetime(date_prefix: str) -> datetime:
"""
Converts a S3 bucket key prefix to a datetime.
:param date_prefix: assumes the last element is a date in YYYYMMDD format
:return: UTC datetime
"""
date = _basename(date_prefix)
if date.startswith("date_partition="):
date = date[15:]
try:
return datetime.strptime(date + '+0000', "%Y%m%d%z")
except ValueError:
raise ServerError(message=f'unknown format for date_prefix: {date_prefix}', code=0) from None
def _ts_to_datetime(timestamp: str) -> datetime:
"""Converts an ISO 8601 formatted timestamp to a datetime"""
if not timestamp:
return datetime.min
return datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f%z')
def _get_customer_prefix(account_code: str, env: str) -> str:
"""returns the bucket key prefix up to the account_code"""
if env.lower() == "uat":
account_code = f'uat-{account_code}'
return f'v1/customer/cust-{account_code}'
def _get_bucket(env: str):
if env.lower() == "production":
return BUCKETS["production"]
else:
return BUCKETS["uat"]
def _fetch_account_code(env: str, account_code: str = None, api_token: str = None) -> str:
"""returns account_code if given or else attempts to fetch the account code from the auth API"""
if not any([account_code, api_token]):
raise InputError(f"one of 'account_code' or 'api_token' is required")
if account_code:
return account_code
with Auth(api_token, env) as auth:
user = auth.user()
account_uuid = user.get("account_uuid")
account = auth.account(account_uuid)
account_code = account.get("code")
if account_code is None:
raise InputError("unable to get account code from auth")
return account_code
def _create_user_agent_extra(name, account_code):
user_agent_extra = f'integrations-{name}-{account_code}'
return user_agent_extra
def fetch_events(name: str, event_types: List[str], account_code: str = None, api_token: str = None,
start_date: datetime = datetime.now(timezone.utc) - timedelta(minutes=5),
access_key: str = None, secret_key: str = None, limit: int = 0, env: str = "production",
context: Context = None):
"""fetches events from metastream. See README.md for full details"""
checkpoint = datetime.now(tz=timezone.utc).replace(microsecond=0)
if context:
context.checkpoint = checkpoint
account_code = _fetch_account_code(env, account_code, api_token)
_validate_event_types(event_types)
_validate_start_date(start_date, checkpoint)
start_day = start_date.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
if not event_types:
event_types = SUPPORTED_EVENT_TYPES
num_events = 0
cut_off = checkpoint - timedelta(seconds=1)
user_agent_extra = _create_user_agent_extra(name, account_code)
with S3Client(_get_bucket(env), access_key, secret_key, user_agent_extra, context=context) as s3:
for sensor_prefix in s3.fetch_common_prefixes(_get_customer_prefix(account_code, env)):
if _basename(sensor_prefix) in ['devices', 'signals']:
continue
for date_prefix in s3.fetch_common_prefixes(sensor_prefix):
if start_day > _prefix_to_datetime(date_prefix):
continue
for event_type_prefix in s3.fetch_common_prefixes(date_prefix):
if _basename(event_type_prefix) not in event_types:
continue
for obj in s3.fetch_file_objects(f'{event_type_prefix}v1/'):
if start_date > obj.get('LastModified'):
continue
if obj.get('LastModified') > cut_off:
continue
events = s3.fetch_gzipped_json_lines_file(obj.get('Key'))
if limit:
yield events[:limit - num_events]
num_events += len(events)
if num_events >= limit:
return
else:
yield events
def fetch_events_by_day(name: str, day: datetime, event_type: str, account_code: str, api_token: str = None,
access_key: str = None, secret_key: str = None, limit: int = 0, env: str = "production",
context: Context = None) -> List[dict]:
"""fetches events from metastream for an entire day. See README.md for full details"""
account_code = _fetch_account_code(env, account_code, api_token)
_validate_day(day.date())
start_day = day.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
user_agent_extra = _create_user_agent_extra(name, account_code)
num_events = 0
with S3Client(_get_bucket(env), access_key, secret_key, user_agent_extra, context=context) as s3:
for sensor_prefix in s3.fetch_common_prefixes(_get_customer_prefix(account_code, env)):
if _basename(sensor_prefix) in ['devices', 'signals']:
continue
for date_prefix in s3.fetch_common_prefixes(sensor_prefix):
if start_day != _prefix_to_datetime(date_prefix):
continue
for event_type_prefix in s3.fetch_common_prefixes(date_prefix):
if _basename(event_type_prefix) != event_type:
continue
for obj in s3.fetch_file_objects(f'{event_type_prefix}v1/'):
events = s3.fetch_gzipped_json_lines_file(obj.get('Key'))
if limit:
yield events[:limit - num_events]
num_events += len(events)
if num_events >= limit:
return
else:
yield events
def fetch_detections_by_day(name: str, day: date, account_code: str, access_key: str = None, secret_key: str = None,
limit: int = 0, env: str = "production", context: Context = None) -> List[dict]:
"""fetches events from metastream for an entire day. See README.md for full details"""
_validate_day(day)
user_agent_extra = _create_user_agent_extra(name, account_code)
num_events = 0
with S3Client(_get_bucket(env), access_key, secret_key, user_agent_extra, context=context) as s3:
for sensor_prefix in s3.fetch_common_prefixes(_get_customer_prefix(account_code, env)):
if _basename(sensor_prefix) != 'signals':
continue
for date_prefix in s3.fetch_common_prefixes(sensor_prefix):
if day != _prefix_to_datetime(date_prefix).date():
continue
for obj in s3.fetch_file_objects(date_prefix):
if not _basename(obj.get('Key', '')).startswith('detection_none'):
continue
events = s3.fetch_gzipped_json_lines_file(obj.get('Key'))
if limit:
yield events[:limit - num_events]
num_events += len(events)
if num_events >= limit:
return
else:
yield events
def fetch_detections(name: str, account_code: str, start_date: datetime, access_key: str = None, secret_key: str = None,
limit: int = 0, env: str = "production", context: Context = None):
"""fetches events from metastream. See README.md for full details"""
checkpoint = datetime.now(tz=timezone.utc).replace(microsecond=0)
if context:
context.checkpoint = checkpoint
_validate_start_date(start_date, checkpoint)
start_day = start_date.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
num_events = 0
cut_off = checkpoint - timedelta(seconds=1)
user_agent_extra = _create_user_agent_extra(name, account_code)
with S3Client(_get_bucket(env), access_key, secret_key, user_agent_extra, context=context) as s3:
for sensor_prefix in s3.fetch_common_prefixes(_get_customer_prefix(account_code, env)):
if _basename(sensor_prefix) != 'signals':
continue
for date_prefix in s3.fetch_common_prefixes(sensor_prefix):
if start_day > _prefix_to_datetime(date_prefix):
continue
for obj in s3.fetch_file_objects(date_prefix):
if not _basename(obj.get('Key', '')).startswith('detection_none'):
continue
if start_date > obj.get('LastModified'):
continue
if obj.get('LastModified') > cut_off:
continue
events = s3.fetch_gzipped_json_lines_file(obj.get('Key'))
if limit:
yield events[:limit - num_events]
num_events += len(events)
if num_events >= limit:
return
else:
yield events
def fetch_event_types():
return SUPPORTED_EVENT_TYPES

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

@ -0,0 +1,137 @@
import gzip
import io
import json
from typing import List
import boto3
import botocore.client
import botocore.config
class Context:
def __init__(self):
self.file_downloads = 0
self.api_calls = 0
self.checkpoint = None
def file_downloads_incr(self):
self.file_downloads += 1
def api_calls_incr(self):
self.api_calls += 1
class S3Client:
def __init__(self, bucket: str, access_key: str, secret_key: str, user_agent_extra: str, client: botocore.client.BaseClient = None,
context: Context = None):
"""
S3Client provides a context manager for _S3Client. Provides higher level methods for S3.
:param bucket: S3 bucket
:param access_key: aws access key
:param secret_key: aws secret access key
:param user_agent_extra: appends to user-agent
:param client: optional boto3 client
:param context: optional context for exporting metrics
"""
self.bucket = bucket
self.access_key = access_key
self.secret_key = secret_key
self.user_agent_extra = user_agent_extra
self.client = client
self.context = context
def __enter__(self):
self.client = _S3Client(self.bucket, self.access_key, self.secret_key, self.user_agent_extra, self.client, self.context)
return self.client
def __exit__(self, exc_type, exc_val, exc_tb):
pass
# older version of boto3 in splunk cloud doesn't have close() method.
# self.client.client.close()
class _S3Client:
S3_MAX_KEYS = 1000
def __init__(self, bucket: str, access_key: str, secret_key: str, user_agent_extra: str, client, context: Context):
self.bucket = bucket
self.context = context or Context()
if client is not None:
self.client = client
else:
config = botocore.config.Config(user_agent_extra=user_agent_extra)
self.client = boto3.client('s3', aws_access_key_id=access_key, aws_secret_access_key=secret_key, config=config)
def fetch_common_prefixes(self, prefix: str) -> List[str]:
"""
A generator function that yields common prefix found after the given prefix.
:param prefix: s3 bucket key prefix
"""
if not prefix.endswith('/'):
prefix += '/'
self.context.api_calls_incr()
obj = self.client.list_objects_v2(
Bucket=self.bucket,
Delimiter="/",
Prefix=prefix,
MaxKeys=self.S3_MAX_KEYS
)
common_prefixes = obj.get('CommonPrefixes') or []
for prefix in common_prefixes:
yield prefix.get('Prefix')
while obj.get('IsTruncated'):
self.context.api_calls_incr()
obj = self.client.list_objects_v2(
Bucket=self.bucket,
Delimiter="/",
Prefix=prefix,
ContinuationToken=obj.get('NextContinuationToken'),
MaxKeys=self.S3_MAX_KEYS
)
common_prefixes = obj.get('CommonPrefixes') or []
for prefix in common_prefixes:
yield prefix.get('Prefix')
def fetch_file_objects(self, prefix: str) -> List:
"""
A generator method that yields file objects found after the given key prefix.
:param prefix: s3 bucket key prefix
"""
self.context.api_calls_incr()
obj = self.client.list_objects_v2(
Bucket=self.bucket,
Prefix=prefix,
MaxKeys=self.S3_MAX_KEYS
)
contents = obj.get('Contents') or []
for item in contents:
yield item
while obj.get('IsTruncated'):
self.context.api_calls_incr()
obj = self.client.list_objects_v2(
Bucket=self.bucket,
Prefix=prefix,
ContinuationToken=obj.get('NextContinuationToken'),
MaxKeys=self.S3_MAX_KEYS
)
contents = obj.get('Contents') or []
for item in contents:
yield item
def fetch_gzipped_json_lines_file(self, key: str) -> List[dict]:
"""
Downloads a gzipped file of `JSON Lines` format and converts it to Python.
:param key: s3 key to a gzipped JSON Lines file
:returns Contents of the file converted to Python
"""
self.context.file_downloads_incr()
datagz = io.BytesIO()
self.client.download_fileobj(Bucket=self.bucket, Key=key, Fileobj=datagz)
data = gzip.decompress(datagz.getvalue())
return [json.loads(line) for line in data.splitlines(False)]

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

@ -0,0 +1 @@
from .sentinel import post_data

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

@ -0,0 +1,50 @@
import base64
import hashlib
import hmac
import json
import logging
import os
from datetime import datetime
import requests
LOG_ANALYTICS_URI = (os.environ.get('LogAnalyticsUri') or "").strip()
SENTINEL_CUSTOMER_ID = (os.environ.get('WorkspaceId') or '').strip()
SENTINEL_RESOURCE = '/api/logs'
if not LOG_ANALYTICS_URI:
LOG_ANALYTICS_URI = f'https://{SENTINEL_CUSTOMER_ID}.ods.opinsights.azure.com{SENTINEL_RESOURCE}?api-version=2016-04-01'
SENTINEL_SHARED_KEY = (os.environ.get('WorkspaceKey') or '').strip()
def post_data(events: list[dict], log_type_suffix: str):
"""Build and send a request to the POST API"""
body = json.dumps(events)
method = 'POST'
content_type = 'application/json'
resource = '/api/logs'
rfc1123date = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
content_length = len(body)
signature = _build_signature(rfc1123date, content_length, method, content_type, resource)
log_type = f'FncEvents{log_type_suffix.title()}'
headers = {
'content-type': content_type,
'Authorization': signature,
'Log-Type': log_type,
'x-ms-date': rfc1123date
}
response = requests.post(LOG_ANALYTICS_URI, data=body, headers=headers)
if (response.status_code >= 200 and response.status_code <= 299):
logging.info(f'SentinelClient: posted {len(events)} events to {log_type}')
else:
logging.error(f"SentinelClient: failed to post events to Sentinel. Response code: {response.status_code}")
raise requests.exceptions.HTTPError(f"SentinelClient: failed to post events to Sentinel. Response code: {response.status_code}")
def _build_signature(date, content_length, method, content_type, resource):
'''Build the API signature'''
x_headers = 'x-ms-date:' + date
string_to_hash = f'{method}\n{str(content_length)}\n{content_type}\n{x_headers}\n{resource}'
bytes_to_hash = bytes(string_to_hash, encoding="utf-8")
decoded_key = base64.b64decode(SENTINEL_SHARED_KEY)
encoded_hash = base64.b64encode(hmac.new(
decoded_key, bytes_to_hash, digestmod=hashlib.sha256).digest()).decode()
return f"SharedKey {SENTINEL_CUSTOMER_ID}:{encoded_hash}"

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

@ -0,0 +1,15 @@
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[3.*, 4.0.0)"
}
}

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

@ -0,0 +1,168 @@
# DO NOT include azure-functions-worker in this file
# The Python Worker is managed by Azure Functions platform
# Manually managing azure-functions-worker may cause unexpected issues
aiohttp==3.8.6
aiosignal==1.3.1
astor==0.8.1
astroid==2.9.3
async-timeout==4.0.3
attrs==23.1.0
autopep8==1.7.0
azure-functions==1.17.0
azure-functions-durable==1.2.6
bandit==1.7.5
bcrypt==4.0.1
beautifulsoup4==4.12.2
boto3==1.28.67
botocore==1.31.67
bracex==2.4
cachetools==5.3.1
certifi==2023.7.22
cffi==1.16.0
chardet==5.2.0
charset-normalizer==3.3.0
click==8.1.7
colorama==0.4.6
coloredlogs==15.0.1
commonmark==0.9.1
ConfigArgParse==1.7
configparser==5.3.0
coverage==7.3.2
cryptography==36.0.2
dateparser==1.1.8
decorator==5.1.1
demisto-py==3.2.13
demisto-sdk==1.20.7
dictdiffer==0.9.0
dictor==0.1.12
docker==5.0.3
docopt==0.6.2
exceptiongroup==1.1.3
flatten-dict==0.4.2
freezegun==1.2.2
frozenlist==1.4.0
furl==2.1.3
future==0.18.3
gitdb==4.0.10
GitPython==3.1.37
giturlparse==0.10.0
google-api-core==2.12.0
google-auth==2.23.3
google-cloud-core==2.3.3
google-cloud-storage==2.11.0
google-crc32c==1.5.0
google-resumable-media==2.6.0
googleapis-common-protos==1.60.0
grpcio==1.59.0
humanfriendly==10.0
idna==3.4
imagesize==1.4.1
importlib-resources==5.13.0
inflection==0.5.1
iniconfig==2.0.0
isort==5.12.0
jmespath==1.0.1
joblib==1.3.2
jsonschema==4.19.1
jsonschema-specifications==2023.7.1
junitparser==3.1.0
klara==0.6.3
lazy-object-proxy==1.9.0
mccabe==0.6.1
mergedeep==1.3.4
more-itertools==9.1.0
multidict==6.0.4
mypy==0.982
mypy-extensions==1.0.0
neo4j==5.13.0
networkx==2.8.8
nltk==3.8.1
ordered-set==4.1.0
orderedmultidict==1.0.1
orjson==3.9.8
packaging==23.2
paramiko==2.12.0
pbr==5.11.1
Pebble==5.0.3
platformdirs==3.11.0
pluggy==1.3.0
prettytable==3.9.0
protobuf==4.24.4
pyasn1==0.5.0
pyasn1-modules==0.3.0
pycodestyle==2.11.0
pycparser==2.21
pydantic==1.10.13
Pygments==2.16.1
pykwalify==1.8.0
pylint==2.12.2
PyNaCl==1.5.0
PyPDF2==1.28.6
pyspellchecker==0.6.3
pytest==7.4.2
pytest-freezegun==0.4.2
python-dateutil==2.8.2
python-dotenv==0.20.0
pytz==2023.3.post1
pytz-deprecation-shim==0.1.0.post0
PyYAML==6.0.1
referencing==0.30.2
regex==2023.10.3
requests==2.31.0
rich==12.6.0
rpds-py==0.10.6
rsa==4.9
ruamel.yaml==0.17.35
ruamel.yaml.clib==0.2.8
s3transfer==0.7.0
shellingham==1.5.3
six==1.16.0
slack-sdk==3.23.0
smmap==5.0.1
soupsieve==2.5
stevedore==5.1.0
tabulate==0.9.0
tenacity==8.2.3
toml==0.10.2
tomli==2.0.1
tqdm==4.66.1
typed-ast==1.5.5
typer==0.7.0
types-chardet==5.0.4.6
types-cryptography==3.3.23.2
types-dateparser==1.1.4.10
types-decorator==5.1.8.4
types-emoji==2.1.0.3
types-filelock==3.2.7
types-futures==3.3.8
types-ipaddress==1.0.8
types-Markdown==3.5.0.0
types-mock==4.0.15.2
types-paramiko==2.12.0.1
types-pkg-resources==0.1.3
types-protobuf==3.20.4.6
types-PyMySQL==1.1.0.1
types-python-dateutil==2.8.19.14
types-pytz==2022.7.1.2
types-pyvmomi==8.0.0.6
types-PyYAML==6.0.12.12
types-requests==2.28.11
types-setuptools==67.8.0.0
types-six==1.16.21.9
types-tabulate==0.9.0.3
types-ujson==5.8.0.1
types-urllib3==1.26.25.14
typing_extensions==4.8.0
tzdata==2023.3
tzlocal==4.3.1
ujson==5.8.0
urllib3==1.26.17
vulture==2.10
wcmatch==8.5
wcwidth==0.2.8
websocket-client==1.6.4
wrapt==1.13.3
yamlordereddictloader==0.4.2
yarl==1.9.2
z3-solver==4.12.2.0

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

@ -0,0 +1,20 @@
{
"Name": "Fortinet FortiNDR Cloud",
"Author": "Microsoft - support@microsoft.com",
"Logo": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/Azure_Sentinel.svg\" width=\"75px\" height=\"75px\">",
"Description": "The [Fortinet FortiNDR Cloud](https://docs.fortinet.com/product/fortindr-cloud) solution for Microsoft Sentinel provides the capability to ingest Fortinet FortiNDR Cloud events stored in Amazon S3 into Microsoft Sentinel using the Amazon S3 REST API. For questions about Fortinet FortiNDR Cloud, please contact Fortinet at [azuresales@fortinet.com](mailto:azuresales@fortinet.com).",
"Data Connectors": [
"Data Connectors/FortinetFortiNdrCloud_API_AzureFunctionApp.json"
],
"Parsers": [
"Parsers/Fortinet_FortiNDR_Cloud.yaml"
],
"Workbooks": [
"Workbooks/FortinetFortiNdrCloudWorkbook.json"
],
"BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Fortinet FortiNDR Cloud",
"Version": "1.0.0",
"Metadata": "SolutionMetadata.json",
"TemplateSpec": true,
"Is1PConnector": false
}

Двоичные данные
Solutions/Fortinet FortiNDR Cloud/Package/3.0.0.zip Normal file

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

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

@ -0,0 +1,134 @@
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"config": {
"isWizard": false,
"basics": {
"description": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/Azure_Sentinel.svg\" width=\"75px\" height=\"75px\">\n\n**Note:** Please refer to the following before installing the solution: \r \n • Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/Fortinet%20FortiNDR%20Cloud/ReleaseNotes.md)\r \n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe [Fortinet FortiNDR Cloud](https://docs.fortinet.com/product/fortindr-cloud) solution for Microsoft Sentinel provides the capability to ingest Fortinet FortiNDR Cloud events stored in Amazon S3 into Microsoft Sentinel using the Amazon S3 REST API. For questions about Fortinet FortiNDR Cloud, please contact Fortinet at [azuresales@fortinet.com](mailto:azuresales@fortinet.com).\n\n**Data Connectors:** 1, **Parsers:** 1, **Workbooks:** 1\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
"subscription": {
"resourceProviders": [
"Microsoft.OperationsManagement/solutions",
"Microsoft.OperationalInsights/workspaces/providers/alertRules",
"Microsoft.Insights/workbooks",
"Microsoft.Logic/workflows"
]
},
"location": {
"metadata": {
"hidden": "Hiding location, we get it from the log analytics workspace"
},
"visible": false
},
"resourceGroup": {
"allowExisting": true
}
}
},
"basics": [
{
"name": "getLAWorkspace",
"type": "Microsoft.Solutions.ArmApiControl",
"toolTip": "This filters by workspaces that exist in the Resource Group selected",
"condition": "[greater(length(resourceGroup().name),0)]",
"request": {
"method": "GET",
"path": "[concat(subscription().id,'/providers/Microsoft.OperationalInsights/workspaces?api-version=2020-08-01')]"
}
},
{
"name": "workspace",
"type": "Microsoft.Common.DropDown",
"label": "Workspace",
"placeholder": "Select a workspace",
"toolTip": "This dropdown will list only workspace that exists in the Resource Group selected",
"constraints": {
"allowedValues": "[map(filter(basics('getLAWorkspace').value, (filter) => contains(toLower(filter.id), toLower(resourceGroup().name))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]",
"required": true
},
"visible": true
}
],
"steps": [
{
"name": "dataconnectors",
"label": "Data Connectors",
"bladeTitle": "Data Connectors",
"elements": [
{
"name": "dataconnectors1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This Solution installs the data connector for Fortinet FortiNDR Cloud. You can get Fortinet FortiNDR Cloud 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-parser-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "The Solution installs a parser that transforms the ingested data into Microsoft Sentinel normalized format. The normalized format enables better correlation of different types of data from different data sources to drive end-to-end outcomes seamlessly in security monitoring, hunting, incident investigation and response scenarios in Microsoft Sentinel."
}
},
{
"name": "dataconnectors-link2",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more about connecting data sources",
"uri": "https://docs.microsoft.com/azure/sentinel/connect-data-sources"
}
}
}
]
},
{
"name": "workbooks",
"label": "Workbooks",
"subLabel": {
"preValidation": "Configure the workbooks",
"postValidation": "Done"
},
"bladeTitle": "Workbooks",
"elements": [
{
"name": "workbooks-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This solution installs workbook(s) to help you gain insights into the telemetry collected in Microsoft Sentinel. After installing the solution, start using the workbook in Manage solution view."
}
},
{
"name": "workbooks-link",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more",
"uri": "https://docs.microsoft.com/azure/sentinel/tutorial-monitor-your-data"
}
}
},
{
"name": "workbook1",
"type": "Microsoft.Common.Section",
"label": "FortiNDR Cloud",
"elements": [
{
"name": "workbook1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Gain insights into Fortinet FortiNDR CLoud events, including the Suricata, Observatino and Detections data."
}
}
]
}
]
}
],
"outputs": {
"workspace-location": "[first(map(filter(basics('getLAWorkspace').value, (filter) => and(contains(toLower(filter.id), toLower(resourceGroup().name)),equals(filter.name,basics('workspace')))), (item) => item.location))]",
"location": "[location()]",
"workspace": "[basics('workspace')]"
}
}
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -0,0 +1,32 @@
{
"location": {
"type": "string",
"minLength": 1,
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace"
}
},
"workspace-location": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]"
}
},
"workspace": {
"defaultValue": "",
"type": "string",
"metadata": {
"description": "Workspace name for Log Analytics where Microsoft Sentinel is setup"
}
},
"workbook1-name": {
"type": "string",
"defaultValue": "FortiNDR Cloud",
"minLength": 1,
"metadata": {
"description": "Name for the workbook"
}
}
}

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

@ -0,0 +1,349 @@
// Usage Instruction :
// Paste below query in log analytics, click on Save button and select as Function from drop down by specifying function name and alias as Fortinet_FortiNDR_Cloud.
// Function usually takes 10-15 minutes to activate. You can then use function alias from any other queries (e.g. Fortinet_FortiNDR_Cloud | take 10).
// Reference : Using functions in Azure monitor log queries : https://docs.microsoft.com/azure/azure-monitor/log-query/functions
let FortiNDR_Cloud_suricata_view = view () {
FncEventsSuricata_CL
| extend
su_timestamp=column_ifexists('timestamp_t',''),
su_uuid=column_ifexists('uuid_g',''),
su_event_type=column_ifexists('event_type_s',''),
su_customer_id=column_ifexists('customer_id_s',''),
su_sensor_id=column_ifexists('sensor_id_s',''),
su_source=column_ifexists('source_s',''),
su_src_ip=column_ifexists('src_ip_s',''),
su_src_port=column_ifexists('src_port_d',''),
su_dst_ip=column_ifexists('dest_ip_s',''),
su_dst_port=column_ifexists('dest_port_d',''),
su_proto=column_ifexists('proto_s',''),
su_sig_id=column_ifexists('alert_signature_id_d',''),
su_sig_rev=column_ifexists('alert_rev_d',''),
su_sig_name=column_ifexists('alert_signature_s',''),
su_sig_category=column_ifexists('alert_category_s',''),
su_sig_severity=column_ifexists('alert_severity_d',''),
su_src_internal=column_ifexists('src_ip_enrichments_internal_b',''),
su_src_geo_lat=column_ifexists('src_ip_enrichments_geo_location_lat_d',''),
su_src_geo_lon=column_ifexists('src_ip_enrichments_geo_location_lon_d',''),
su_src_geo_country=column_ifexists('src_ip_enrichments_geo_country_s',''),
su_src_geo_subdivision=column_ifexists('src_ip_enrichments_geo_subdivision_s',''),
su_src_geo_city=column_ifexists('src_ip_enrichments_geo_city_s',''),
su_src_asn_asn=column_ifexists('src_ip_enrichments_asn_asn_d',''),
su_src_asn_org=column_ifexists('src_ip_enrichments_asn_org_s',''),
su_src_asn_isp=column_ifexists('src_ip_enrichments_asn_isp_s',''),
su_src_asn_asn_org=column_ifexists('src_ip_enrichments_asn_asn_org_s',''),
su_src_annotations_applications=column_ifexists('src_ip_enrichments_annotations_applications_s',''),
su_src_annotations_environments=column_ifexists('src_ip_enrichments_annotations_environments_s',''),
su_src_annotations_locations=column_ifexists('src_ip_enrichments_annotations_locations_s',''),
su_src_annotations_owners=column_ifexists('src_ip_enrichments_annotations_owners_s',''),
su_src_annotations_roles=column_ifexists('src_ip_enrichments_annotations_roles_s',''),
su_src_annotations_tags=column_ifexists('src_ip_enrichments_annotations_tags_s',''),
su_dst_internal=column_ifexists('dst_ip_enrichments_internal_b',''),
su_dst_geo_lat=column_ifexists('dst_ip_enrichments_geo_location_lat_d',''),
su_dst_geo_lon=column_ifexists('dst_ip_enrichments_geo_location_lon_d',''),
su_dst_geo_country=column_ifexists('dst_ip_enrichments_geo_country_s',''),
su_dst_geo_subdivision=column_ifexists('dst_ip_enrichments_geo_subdivision_s',''),
su_dst_geo_city=column_ifexists('dst_ip_enrichments_geo_city_s',''),
su_dst_asn_asn=column_ifexists('dst_ip_enrichments_asn_asn_d',''),
su_dst_asn_org=column_ifexists('dst_ip_enrichments_asn_org_s',''),
su_dst_asn_isp=column_ifexists('dst_ip_enrichments_asn_isp_s',''),
su_dst_asn_asn_org=column_ifexists('dst_ip_enrichments_asn_asn_org_s',''),
su_dst_annotations_applications=column_ifexists('dst_ip_enrichments_annotations_applications_s',''),
su_dst_annotations_environments=column_ifexists('dst_ip_enrichments_annotations_environments_s',''),
su_dst_annotations_locations=column_ifexists('dst_ip_enrichments_annotations_locations_s',''),
su_dst_annotations_owners=column_ifexists('dst_ip_enrichments_annotations_owners_s',''),
su_dst_annotations_roles=column_ifexists('dst_ip_enrichments_annotations_roles_s',''),
su_dst_annotations_tags=column_ifexists('dst_ip_enrichments_annotations_tags_s',''),
su_geo_distance=column_ifexists('geo_distance_d',''),
su_http_status=column_ifexists('http_status_d',''),
su_http_protocol=column_ifexists('http_protocol_s',''),
su_http_url=column_ifexists('http_url_s',''),
su_http_hostname=column_ifexists('http_hostname_s',''),
su_http_host_internal=column_ifexists('http_hostname_enrichments_ip_enrichments_internal_b',''),
su_http_host_geo_lat=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_location_lat_d',''),
su_http_host_geo_lon=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_location_lon_d',''),
su_http_host_geo_subdivision=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_subdivision_s',''),
su_http_host_geo_city=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_city_s',''),
su_http_host_asn_asn=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_asn_d',''),
su_http_host_asn_org=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_org_s',''),
su_http_host_asn_isp=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_isp_s',''),
su_http_host_asn_asn_org=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_asn_org_s',''),
su_http_host_geo_country=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_country_s',''),
su_http_host_annotations_applications=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_applications_s',''),
su_http_host_annotations_environments=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_environments_s',''),
su_http_host_annotations_locations=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_locations_s',''),
su_http_host_annotations_owners=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_owners_s',''),
su_http_host_annotations_roles=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_roles_s',''),
su_http_host_annotations_tags=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_tags_s',''),
su_http_host_domain_entropy=column_ifexists('http_hostname_enrichments_domain_enrichments_domain_entropy_d',''),
su_http_length=column_ifexists('http_length_d',''),
su_http_method=column_ifexists('http_http_method_s',''),
su_http_content_type=column_ifexists('http_http_content_type_s',''),
su_http_refer=column_ifexists('http_http_refer_s',''),
su_http_user_agent=column_ifexists('http_http_user_agent_s',''),
su_http_redirect=column_ifexists('http_redirect_s',''),
su_http_xtf=column_ifexists('http_xtf_s',''),
su_payload=column_ifexists('payload_s',''),
su_intel=column_ifexists('intel_s','')
| project
su_timestamp,
su_event_type,
su_src_ip,
su_src_port,
su_dst_ip,
su_dst_port,
su_intel,
su_sig_name,
su_sig_id,
su_sig_rev,
su_sig_category,
su_sig_severity,
su_payload,
su_source,
su_proto,
su_sensor_id,
su_src_internal,
su_src_geo_lat,
su_src_geo_lon,
su_src_geo_country,
su_src_geo_subdivision,
su_src_geo_city,
su_src_asn_asn,
su_src_asn_org,
su_src_asn_isp,
su_src_asn_asn_org,
su_src_annotations_applications,
su_src_annotations_environments,
su_src_annotations_locations,
su_src_annotations_owners,
su_src_annotations_roles,
su_src_annotations_tags,
su_dst_internal,
su_dst_geo_lat,
su_dst_geo_lon,
su_dst_geo_country,
su_dst_geo_subdivision,
su_dst_geo_city,
su_dst_asn_asn,
su_dst_asn_org,
su_dst_asn_isp,
su_dst_asn_asn_org,
su_dst_annotations_applications,
su_dst_annotations_environments,
su_dst_annotations_locations,
su_dst_annotations_owners,
su_dst_annotations_roles,
su_dst_annotations_tags,
su_geo_distance,
su_http_status,
su_http_protocol,
su_http_url,
su_http_hostname,
su_http_host_internal,
su_http_host_geo_lat,
su_http_host_geo_lon,
su_http_host_geo_country,
su_http_host_geo_subdivision,
su_http_host_geo_city,
su_http_host_asn_asn,
su_http_host_asn_org,
su_http_host_asn_isp,
su_http_host_asn_asn_org,
su_http_host_annotations_applications,
su_http_host_annotations_environments,
su_http_host_annotations_locations,
su_http_host_annotations_owners,
su_http_host_annotations_roles,
su_http_host_annotations_tags,
su_http_host_domain_entropy,
su_http_length,
su_http_method,
su_http_content_type,
su_http_refer,
su_http_user_agent,
su_http_redirect,
su_http_xtf,
su_uuid,
su_customer_id,
Type
};
let FortiNDR_Cloud_observation_view = view () {
FncEventsObservation_CL
| extend
ob_timestamp=column_ifexists('timestamp_t',''),
ob_uuid=column_ifexists('uuid_g',''),
ob_event_type=column_ifexists('event_type_s',''),
ob_customer_id=column_ifexists('customer_id_s',''),
ob_sensor_id=column_ifexists('sensor_id_s',''),
ob_source=column_ifexists('source_s',''),
ob_evidence_start_timestamp=column_ifexists('evidence_start_timestamp_t',''),
ob_evidence_end_timestamp=column_ifexists('evidence_end_timestamp_t',''),
ob_observation_uuid=column_ifexists('observation_uuid_g',''),
ob_observation_title=column_ifexists('title_s',''),
ob_confidence=column_ifexists('confidence_s',''),
ob_src_ip=column_ifexists('src_ip_s',''),
ob_dst_ip=column_ifexists('dst_ip_s',''),
ob_src_internal=column_ifexists('src_ip_enrichments_internal_b',''),
ob_src_geo_lat=column_ifexists('src_ip_enrichments_geo_location_lat_d',''),
ob_src_geo_lon=column_ifexists('src_ip_enrichments_geo_location_lon_d',''),
ob_src_geo_country=column_ifexists('src_ip_enrichments_geo_country_s',''),
ob_src_geo_subdivision=column_ifexists('src_ip_enrichments_geo_subdivision_s',''),
ob_src_geo_city=column_ifexists('src_ip_enrichments_geo_city_s',''),
ob_src_asn_asn=column_ifexists('src_ip_enrichments_asn_asn_d',''),
ob_src_asn_org=column_ifexists('src_ip_enrichments_asn_org_s',''),
ob_src_asn_isp=column_ifexists('src_ip_enrichments_asn_isp_s',''),
ob_src_asn_asn_org=column_ifexists('src_ip_enrichments_asn_asn_org_s',''),
ob_src_annotations_applications=column_ifexists('src_ip_enrichments_annotations_applications_s',''),
ob_src_annotations_environments=column_ifexists('src_ip_enrichments_annotations_environments_s',''),
ob_src_annotations_locations=column_ifexists('src_ip_enrichments_annotations_locations_s',''),
ob_src_annotations_owners=column_ifexists('src_ip_enrichments_annotations_owners_s',''),
ob_src_annotations_roles=column_ifexists('src_ip_enrichments_annotations_roles_s',''),
ob_src_annotations_tags=column_ifexists('src_ip_enrichments_annotations_tags_s',''),
ob_dst_internal=column_ifexists('dst_ip_enrichments_internal_b',''),
ob_dst_geo_lat=column_ifexists('dst_ip_enrichments_geo_location_lat_d',''),
ob_dst_geo_lon=column_ifexists('dst_ip_enrichments_geo_location_lon_d',''),
ob_dst_geo_country=column_ifexists('dst_ip_enrichments_geo_country_s',''),
ob_dst_geo_subdivision=column_ifexists('dst_ip_enrichments_geo_subdivision_s',''),
ob_dst_geo_city=column_ifexists('dst_ip_enrichments_geo_city_s',''),
ob_dst_asn_asn=column_ifexists('dst_ip_enrichments_asn_asn_d',''),
ob_dst_asn_org=column_ifexists('dst_ip_enrichments_asn_org_s',''),
ob_dst_asn_isp=column_ifexists('dst_ip_enrichments_asn_isp_s',''),
ob_dst_asn_asn_org=column_ifexists('dst_ip_enrichments_asn_asn_org_s',''),
ob_dst_annotations_applications=column_ifexists('dst_ip_enrichments_annotations_applications_s',''),
ob_dst_annotations_environments=column_ifexists('dst_ip_enrichments_annotations_environments_s',''),
ob_dst_annotations_locations=column_ifexists('dst_ip_enrichments_annotations_locations_s',''),
ob_dst_annotations_owners=column_ifexists('dst_ip_enrichments_annotations_owners_s',''),
ob_dst_annotations_roles=column_ifexists('dst_ip_enrichments_annotations_roles_s',''),
ob_dst_annotations_tags=column_ifexists('dst_ip_enrichments_annotations_tags_s',''),
ob_geo_distance=column_ifexists('geo_distance_d',''),
ob_sensor_ids=column_ifexists('sensor_ids_s',''),
ob_evidence_iql=column_ifexists('evidence_iql_s',''),
ob_description=column_ifexists('description_s',''),
ob_context=column_ifexists('context_s',''),
ob_class=column_ifexists('class_s',''),
ob_intel=column_ifexists('intel_s', ''),
ob_category=column_ifexists('Category', '')
| project
ob_timestamp,
ob_observation_title,
ob_confidence,
ob_category,
ob_class,
ob_context,
ob_evidence_iql,
ob_evidence_end_timestamp,
ob_evidence_start_timestamp,
ob_description,
ob_observation_uuid,
ob_sensor_ids,
ob_event_type,
ob_src_ip,
ob_dst_ip,
ob_intel,
ob_source,
ob_sensor_id,
ob_src_internal,
ob_src_geo_lat,
ob_src_geo_lon,
ob_src_geo_country,
ob_src_geo_subdivision,
ob_src_geo_city,
ob_src_asn_asn,
ob_src_asn_org,
ob_src_asn_isp,
ob_src_asn_asn_org,
ob_src_annotations_applications,
ob_src_annotations_environments,
ob_src_annotations_locations,
ob_src_annotations_owners,
ob_src_annotations_roles,
ob_src_annotations_tags,
ob_dst_internal,
ob_dst_geo_lat,
ob_dst_geo_lon,
ob_dst_geo_country,
ob_dst_geo_subdivision,
ob_dst_geo_city,
ob_dst_asn_asn,
ob_dst_asn_org,
ob_dst_asn_isp,
ob_dst_asn_asn_org,
ob_dst_annotations_applications,
ob_dst_annotations_environments,
ob_dst_annotations_locations,
ob_dst_annotations_owners,
ob_dst_annotations_roles,
ob_dst_annotations_tags,
ob_geo_distance,
ob_uuid,
ob_customer_id,
Type
};
let FortiNDR_Cloud_detections_view = view () {
FncEventsDetections_CL
| extend
de_vendor=column_ifexists('vendor_s',''),
de_product=column_ifexists('product_s',''),
de_signal_version=column_ifexists('signal_version_s',''),
de_event_type=column_ifexists('event_type_s',''),
de_subject=column_ifexists('subject_s',''),
de_timestamp=column_ifexists('timestamp_t',''),
de_device_ip=column_ifexists('device_ip_s',''),
de_rule_name=column_ifexists('name_s',''),
de_severity=column_ifexists('severity_s',''),
de_confidence=column_ifexists('confidence_s',''),
de_sensor_ids=column_ifexists('sensor_id_s',''),
de_muted=column_ifexists('muted_b',''),
de_rule_muted=column_ifexists('muted_rule_b',''),
de_rule_uuid=column_ifexists('rule_uuid_g',''),
de_mute_comment=column_ifexists('muted_comment_s',''),
de_first_seen=column_ifexists('first_seen_t',''),
de_last_seen=column_ifexists('last_seen_t',''),
de_created=column_ifexists('created_t',''),
de_updated=column_ifexists('updated_t',''),
de_uuid=column_ifexists('uuid_g',''),
de_status=column_ifexists('status_s',''),
de_indicators=column_ifexists('indicators_s',''),
de_customer_id=column_ifexists('customer_id_s',''),
de_primary_pdns_hostnames=column_ifexists('primary_pdns_hostnames_s',''),
de_other_pdns_hostnames=column_ifexists('other_pdns_hostnames_s',''),
de_primary_dhcp_machost_pairs=column_ifexists('primary_dhcp_machost_pairs_s',''),
de_other_dhcp_machost_pairs=column_ifexists('other_dhcp_machost_pairs_s',''),
de_category=column_ifexists('Category', '')
| project
de_timestamp,
de_device_ip,
de_status,
de_indicators,
de_last_seen,
de_rule_name,
de_rule_uuid,
de_category,
de_created,
de_updated,
de_severity,
de_confidence,
de_muted,
de_rule_muted,
de_mute_comment,
de_sensor_ids,
de_primary_pdns_hostnames,
de_other_pdns_hostnames,
de_primary_dhcp_machost_pairs,
de_other_dhcp_machost_pairs,
de_vendor,
de_product,
de_signal_version,
de_event_type,
de_subject,
de_uuid,
de_customer_id,
Type
};
union isfuzzy=true
FortiNDR_Cloud_suricata_view,
FortiNDR_Cloud_observation_view,
FortiNDR_Cloud_detections_view

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

@ -0,0 +1,353 @@
id: 4c846775-c295-421f-9275-ded657b190d6
Function:
Title: Parser for Fortinet_FortiNDR_Cloud
Version: '1.0.0'
LastUpdated: '2024-01-09'
Category: Microsoft Sentinel Parser
FunctionName: Fortinet_FortiNDR_Cloud
FunctionAlias: Fortinet_FortiNDR_Cloud
FunctionQuery: |
let FortiNDR_Cloud_suricata_view = view () {
FncEventsSuricata_CL
| extend
su_timestamp=column_ifexists('timestamp_t',''),
su_uuid=column_ifexists('uuid_g',''),
su_event_type=column_ifexists('event_type_s',''),
su_customer_id=column_ifexists('customer_id_s',''),
su_sensor_id=column_ifexists('sensor_id_s',''),
su_source=column_ifexists('source_s',''),
su_src_ip=column_ifexists('src_ip_s',''),
su_src_port=column_ifexists('src_port_d',''),
su_dst_ip=column_ifexists('dest_ip_s',''),
su_dst_port=column_ifexists('dest_port_d',''),
su_proto=column_ifexists('proto_s',''),
su_sig_id=column_ifexists('alert_signature_id_d',''),
su_sig_rev=column_ifexists('alert_rev_d',''),
su_sig_name=column_ifexists('alert_signature_s',''),
su_sig_category=column_ifexists('alert_category_s',''),
su_sig_severity=column_ifexists('alert_severity_d',''),
su_src_internal=column_ifexists('src_ip_enrichments_internal_b',''),
su_src_geo_lat=column_ifexists('src_ip_enrichments_geo_location_lat_d',''),
su_src_geo_lon=column_ifexists('src_ip_enrichments_geo_location_lon_d',''),
su_src_geo_country=column_ifexists('src_ip_enrichments_geo_country_s',''),
su_src_geo_subdivision=column_ifexists('src_ip_enrichments_geo_subdivision_s',''),
su_src_geo_city=column_ifexists('src_ip_enrichments_geo_city_s',''),
su_src_asn_asn=column_ifexists('src_ip_enrichments_asn_asn_d',''),
su_src_asn_org=column_ifexists('src_ip_enrichments_asn_org_s',''),
su_src_asn_isp=column_ifexists('src_ip_enrichments_asn_isp_s',''),
su_src_asn_asn_org=column_ifexists('src_ip_enrichments_asn_asn_org_s',''),
su_src_annotations_applications=column_ifexists('src_ip_enrichments_annotations_applications_s',''),
su_src_annotations_environments=column_ifexists('src_ip_enrichments_annotations_environments_s',''),
su_src_annotations_locations=column_ifexists('src_ip_enrichments_annotations_locations_s',''),
su_src_annotations_owners=column_ifexists('src_ip_enrichments_annotations_owners_s',''),
su_src_annotations_roles=column_ifexists('src_ip_enrichments_annotations_roles_s',''),
su_src_annotations_tags=column_ifexists('src_ip_enrichments_annotations_tags_s',''),
su_dst_internal=column_ifexists('dst_ip_enrichments_internal_b',''),
su_dst_geo_lat=column_ifexists('dst_ip_enrichments_geo_location_lat_d',''),
su_dst_geo_lon=column_ifexists('dst_ip_enrichments_geo_location_lon_d',''),
su_dst_geo_country=column_ifexists('dst_ip_enrichments_geo_country_s',''),
su_dst_geo_subdivision=column_ifexists('dst_ip_enrichments_geo_subdivision_s',''),
su_dst_geo_city=column_ifexists('dst_ip_enrichments_geo_city_s',''),
su_dst_asn_asn=column_ifexists('dst_ip_enrichments_asn_asn_d',''),
su_dst_asn_org=column_ifexists('dst_ip_enrichments_asn_org_s',''),
su_dst_asn_isp=column_ifexists('dst_ip_enrichments_asn_isp_s',''),
su_dst_asn_asn_org=column_ifexists('dst_ip_enrichments_asn_asn_org_s',''),
su_dst_annotations_applications=column_ifexists('dst_ip_enrichments_annotations_applications_s',''),
su_dst_annotations_environments=column_ifexists('dst_ip_enrichments_annotations_environments_s',''),
su_dst_annotations_locations=column_ifexists('dst_ip_enrichments_annotations_locations_s',''),
su_dst_annotations_owners=column_ifexists('dst_ip_enrichments_annotations_owners_s',''),
su_dst_annotations_roles=column_ifexists('dst_ip_enrichments_annotations_roles_s',''),
su_dst_annotations_tags=column_ifexists('dst_ip_enrichments_annotations_tags_s',''),
su_geo_distance=column_ifexists('geo_distance_d',''),
su_http_status=column_ifexists('http_status_d',''),
su_http_protocol=column_ifexists('http_protocol_s',''),
su_http_url=column_ifexists('http_url_s',''),
su_http_hostname=column_ifexists('http_hostname_s',''),
su_http_host_internal=column_ifexists('http_hostname_enrichments_ip_enrichments_internal_b',''),
su_http_host_geo_lat=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_location_lat_d',''),
su_http_host_geo_lon=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_location_lon_d',''),
su_http_host_geo_subdivision=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_subdivision_s',''),
su_http_host_geo_city=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_city_s',''),
su_http_host_asn_asn=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_asn_d',''),
su_http_host_asn_org=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_org_s',''),
su_http_host_asn_isp=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_isp_s',''),
su_http_host_asn_asn_org=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_asn_org_s',''),
su_http_host_geo_country=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_country_s',''),
su_http_host_annotations_applications=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_applications_s',''),
su_http_host_annotations_environments=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_environments_s',''),
su_http_host_annotations_locations=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_locations_s',''),
su_http_host_annotations_owners=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_owners_s',''),
su_http_host_annotations_roles=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_roles_s',''),
su_http_host_annotations_tags=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_tags_s',''),
su_http_host_domain_entropy=column_ifexists('http_hostname_enrichments_domain_enrichments_domain_entropy_d',''),
su_http_length=column_ifexists('http_length_d',''),
su_http_method=column_ifexists('http_http_method_s',''),
su_http_content_type=column_ifexists('http_http_content_type_s',''),
su_http_refer=column_ifexists('http_http_refer_s',''),
su_http_user_agent=column_ifexists('http_http_user_agent_s',''),
su_http_redirect=column_ifexists('http_redirect_s',''),
su_http_xtf=column_ifexists('http_xtf_s',''),
su_payload=column_ifexists('payload_s',''),
su_intel=column_ifexists('intel_s','')
| project
su_timestamp,
su_event_type,
su_src_ip,
su_src_port,
su_dst_ip,
su_dst_port,
su_intel,
su_sig_name,
su_sig_id,
su_sig_rev,
su_sig_category,
su_sig_severity,
su_payload,
su_source,
su_proto,
su_sensor_id,
su_src_internal,
su_src_geo_lat,
su_src_geo_lon,
su_src_geo_country,
su_src_geo_subdivision,
su_src_geo_city,
su_src_asn_asn,
su_src_asn_org,
su_src_asn_isp,
su_src_asn_asn_org,
su_src_annotations_applications,
su_src_annotations_environments,
su_src_annotations_locations,
su_src_annotations_owners,
su_src_annotations_roles,
su_src_annotations_tags,
su_dst_internal,
su_dst_geo_lat,
su_dst_geo_lon,
su_dst_geo_country,
su_dst_geo_subdivision,
su_dst_geo_city,
su_dst_asn_asn,
su_dst_asn_org,
su_dst_asn_isp,
su_dst_asn_asn_org,
su_dst_annotations_applications,
su_dst_annotations_environments,
su_dst_annotations_locations,
su_dst_annotations_owners,
su_dst_annotations_roles,
su_dst_annotations_tags,
su_geo_distance,
su_http_status,
su_http_protocol,
su_http_url,
su_http_hostname,
su_http_host_internal,
su_http_host_geo_lat,
su_http_host_geo_lon,
su_http_host_geo_country,
su_http_host_geo_subdivision,
su_http_host_geo_city,
su_http_host_asn_asn,
su_http_host_asn_org,
su_http_host_asn_isp,
su_http_host_asn_asn_org,
su_http_host_annotations_applications,
su_http_host_annotations_environments,
su_http_host_annotations_locations,
su_http_host_annotations_owners,
su_http_host_annotations_roles,
su_http_host_annotations_tags,
su_http_host_domain_entropy,
su_http_length,
su_http_method,
su_http_content_type,
su_http_refer,
su_http_user_agent,
su_http_redirect,
su_http_xtf,
su_uuid,
su_customer_id,
Type
};
let FortiNDR_Cloud_observation_view = view () {
FncEventsObservation_CL
| extend
ob_timestamp=column_ifexists('timestamp_t',''),
ob_uuid=column_ifexists('uuid_g',''),
ob_event_type=column_ifexists('event_type_s',''),
ob_customer_id=column_ifexists('customer_id_s',''),
ob_sensor_id=column_ifexists('sensor_id_s',''),
ob_source=column_ifexists('source_s',''),
ob_evidence_start_timestamp=column_ifexists('evidence_start_timestamp_t',''),
ob_evidence_end_timestamp=column_ifexists('evidence_end_timestamp_t',''),
ob_observation_uuid=column_ifexists('observation_uuid_g',''),
ob_observation_title=column_ifexists('title_s',''),
ob_confidence=column_ifexists('confidence_s',''),
ob_src_ip=column_ifexists('src_ip_s',''),
ob_dst_ip=column_ifexists('dst_ip_s',''),
ob_src_internal=column_ifexists('src_ip_enrichments_internal_b',''),
ob_src_geo_lat=column_ifexists('src_ip_enrichments_geo_location_lat_d',''),
ob_src_geo_lon=column_ifexists('src_ip_enrichments_geo_location_lon_d',''),
ob_src_geo_country=column_ifexists('src_ip_enrichments_geo_country_s',''),
ob_src_geo_subdivision=column_ifexists('src_ip_enrichments_geo_subdivision_s',''),
ob_src_geo_city=column_ifexists('src_ip_enrichments_geo_city_s',''),
ob_src_asn_asn=column_ifexists('src_ip_enrichments_asn_asn_d',''),
ob_src_asn_org=column_ifexists('src_ip_enrichments_asn_org_s',''),
ob_src_asn_isp=column_ifexists('src_ip_enrichments_asn_isp_s',''),
ob_src_asn_asn_org=column_ifexists('src_ip_enrichments_asn_asn_org_s',''),
ob_src_annotations_applications=column_ifexists('src_ip_enrichments_annotations_applications_s',''),
ob_src_annotations_environments=column_ifexists('src_ip_enrichments_annotations_environments_s',''),
ob_src_annotations_locations=column_ifexists('src_ip_enrichments_annotations_locations_s',''),
ob_src_annotations_owners=column_ifexists('src_ip_enrichments_annotations_owners_s',''),
ob_src_annotations_roles=column_ifexists('src_ip_enrichments_annotations_roles_s',''),
ob_src_annotations_tags=column_ifexists('src_ip_enrichments_annotations_tags_s',''),
ob_dst_internal=column_ifexists('dst_ip_enrichments_internal_b',''),
ob_dst_geo_lat=column_ifexists('dst_ip_enrichments_geo_location_lat_d',''),
ob_dst_geo_lon=column_ifexists('dst_ip_enrichments_geo_location_lon_d',''),
ob_dst_geo_country=column_ifexists('dst_ip_enrichments_geo_country_s',''),
ob_dst_geo_subdivision=column_ifexists('dst_ip_enrichments_geo_subdivision_s',''),
ob_dst_geo_city=column_ifexists('dst_ip_enrichments_geo_city_s',''),
ob_dst_asn_asn=column_ifexists('dst_ip_enrichments_asn_asn_d',''),
ob_dst_asn_org=column_ifexists('dst_ip_enrichments_asn_org_s',''),
ob_dst_asn_isp=column_ifexists('dst_ip_enrichments_asn_isp_s',''),
ob_dst_asn_asn_org=column_ifexists('dst_ip_enrichments_asn_asn_org_s',''),
ob_dst_annotations_applications=column_ifexists('dst_ip_enrichments_annotations_applications_s',''),
ob_dst_annotations_environments=column_ifexists('dst_ip_enrichments_annotations_environments_s',''),
ob_dst_annotations_locations=column_ifexists('dst_ip_enrichments_annotations_locations_s',''),
ob_dst_annotations_owners=column_ifexists('dst_ip_enrichments_annotations_owners_s',''),
ob_dst_annotations_roles=column_ifexists('dst_ip_enrichments_annotations_roles_s',''),
ob_dst_annotations_tags=column_ifexists('dst_ip_enrichments_annotations_tags_s',''),
ob_geo_distance=column_ifexists('geo_distance_d',''),
ob_sensor_ids=column_ifexists('sensor_ids_s',''),
ob_evidence_iql=column_ifexists('evidence_iql_s',''),
ob_description=column_ifexists('description_s',''),
ob_context=column_ifexists('context_s',''),
ob_class=column_ifexists('class_s',''),
ob_intel=column_ifexists('intel_s', ''),
ob_category=column_ifexists('Category', '')
| project
ob_timestamp,
ob_observation_title,
ob_confidence,
ob_category,
ob_class,
ob_context,
ob_evidence_iql,
ob_evidence_end_timestamp,
ob_evidence_start_timestamp,
ob_description,
ob_observation_uuid,
ob_sensor_ids,
ob_event_type,
ob_src_ip,
ob_dst_ip,
ob_intel,
ob_source,
ob_sensor_id,
ob_src_internal,
ob_src_geo_lat,
ob_src_geo_lon,
ob_src_geo_country,
ob_src_geo_subdivision,
ob_src_geo_city,
ob_src_asn_asn,
ob_src_asn_org,
ob_src_asn_isp,
ob_src_asn_asn_org,
ob_src_annotations_applications,
ob_src_annotations_environments,
ob_src_annotations_locations,
ob_src_annotations_owners,
ob_src_annotations_roles,
ob_src_annotations_tags,
ob_dst_internal,
ob_dst_geo_lat,
ob_dst_geo_lon,
ob_dst_geo_country,
ob_dst_geo_subdivision,
ob_dst_geo_city,
ob_dst_asn_asn,
ob_dst_asn_org,
ob_dst_asn_isp,
ob_dst_asn_asn_org,
ob_dst_annotations_applications,
ob_dst_annotations_environments,
ob_dst_annotations_locations,
ob_dst_annotations_owners,
ob_dst_annotations_roles,
ob_dst_annotations_tags,
ob_geo_distance,
ob_uuid,
ob_customer_id,
Type
};
let FortiNDR_Cloud_detections_view = view () {
FncEventsDetections_CL
| extend
de_vendor=column_ifexists('vendor_s',''),
de_product=column_ifexists('product_s',''),
de_signal_version=column_ifexists('signal_version_s',''),
de_event_type=column_ifexists('event_type_s',''),
de_subject=column_ifexists('subject_s',''),
de_timestamp=column_ifexists('timestamp_t',''),
de_device_ip=column_ifexists('device_ip_s',''),
de_rule_name=column_ifexists('name_s',''),
de_severity=column_ifexists('severity_s',''),
de_confidence=column_ifexists('confidence_s',''),
de_sensor_ids=column_ifexists('sensor_id_s',''),
de_muted=column_ifexists('muted_b',''),
de_rule_muted=column_ifexists('muted_rule_b',''),
de_rule_uuid=column_ifexists('rule_uuid_g',''),
de_mute_comment=column_ifexists('muted_comment_s',''),
de_first_seen=column_ifexists('first_seen_t',''),
de_last_seen=column_ifexists('last_seen_t',''),
de_created=column_ifexists('created_t',''),
de_updated=column_ifexists('updated_t',''),
de_uuid=column_ifexists('uuid_g',''),
de_status=column_ifexists('status_s',''),
de_indicators=column_ifexists('indicators_s',''),
de_customer_id=column_ifexists('customer_id_s',''),
de_primary_pdns_hostnames=column_ifexists('primary_pdns_hostnames_s',''),
de_other_pdns_hostnames=column_ifexists('other_pdns_hostnames_s',''),
de_primary_dhcp_machost_pairs=column_ifexists('primary_dhcp_machost_pairs_s',''),
de_other_dhcp_machost_pairs=column_ifexists('other_dhcp_machost_pairs_s',''),
de_category=column_ifexists('Category', '')
| project
de_timestamp,
de_device_ip,
de_status,
de_indicators,
de_last_seen,
de_rule_name,
de_rule_uuid,
de_category,
de_created,
de_updated,
de_severity,
de_confidence,
de_muted,
de_rule_muted,
de_mute_comment,
de_sensor_ids,
de_primary_pdns_hostnames,
de_other_pdns_hostnames,
de_primary_dhcp_machost_pairs,
de_other_dhcp_machost_pairs,
de_vendor,
de_product,
de_signal_version,
de_event_type,
de_subject,
de_uuid,
de_customer_id,
Type
};
union isfuzzy=true
FortiNDR_Cloud_suricata_view,
FortiNDR_Cloud_observation_view,
FortiNDR_Cloud_detections_view

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

@ -0,0 +1,3 @@
| **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** |
|-------------|--------------------------------|---------------------------------------------|
| 3.0.0 | 30-01-2024 | Initial Solution Release |

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

@ -0,0 +1,16 @@
{
"publisherId": "azuresentinel",
"offerId": "azure-sentinel-solution-fortindrcloud",
"firstPublishDate": "2024-01-15",
"providers": ["Fortinet"],
"categories": {
"domains" : ["Security - Automation (SOAR)"],
"verticals": []
},
"support": {
"name": "Microsoft Corporation",
"email": "support@microsoft.com",
"tier": "Microsoft",
"link": "https://support.microsoft.com"
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,23 +1,23 @@
{
"Name": "Armorblox",
"Author": "Armorblox - support@armorblox.com",
"Logo": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Armorblox/Data%20Connectors/Logo/armorblox.svg\" width=\"75px\" height=\"75px\">",
"Description": "The [Armorblox](https://www.armorblox.com/) solution provides the capability to ingest incidents from your Armorblox instance into Microsoft Sentinel through the REST API.\r\n \r\n **Underlying Microsoft Technologies used:** \r\n\r\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs:\r\n\n a. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api)\r\n\n \r\n\n b. [Azure Functions](https://azure.microsoft.com/services/functions/#overview)\r\n\n",
"Data Connectors": [
"Data Connectors/Armorblox_API_FunctionApp.json"
],
"Workbooks": [
"Workbooks/ArmorbloxOverview.json"
],
"Analytic Rules": [
"Analytic Rules/ArmorbloxNeedsReviewAlert.yaml"
],
"Playbooks": [
"Playbooks/Needs-Review-Incident-Email-Notification/azuredeploy.json"
],
"Metadata": "SolutionMetadata.json",
"BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Armorblox",
"Version": "2.0.2",
"TemplateSpec": true,
"Is1PConnector": false
}
"Name": "Armorblox",
"Author": "Armorblox - support@armorblox.com",
"Logo": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Armorblox/Data%20Connectors/Logo/armorblox.svg\" width=\"75px\" height=\"75px\">",
"Description": "The [Armorblox](https://www.armorblox.com/) solution provides the capability to ingest incidents from your Armorblox instance into Microsoft Sentinel through the REST API.\r\n \r\n **Underlying Microsoft Technologies used:** \r\n\r\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs:\r\n\n a. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api)\r\n\n \r\n\n b. [Azure Functions](https://azure.microsoft.com/services/functions/#overview)\r\n\n",
"Data Connectors": [
"Data Connectors/Armorblox_API_FunctionApp.json"
],
"Workbooks": [
"Workbooks/ArmorbloxOverview.json"
],
"Analytic Rules": [
"Analytic Rules/ArmorbloxNeedsReviewAlert.yaml"
],
"Playbooks": [
"Playbooks/Needs-Review-Incident-Email-Notification/azuredeploy.json"
],
"Metadata": "SolutionMetadata.json",
"BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Armorblox",
"Version": "2.0.2",
"TemplateSpec": true,
"Is1PConnector": false
}

Двоичные данные
Workbooks/Images/Preview/FncDetectionDashboardBlack.png Normal file

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

После

Ширина:  |  Высота:  |  Размер: 171 KiB

Двоичные данные
Workbooks/Images/Preview/FncDetectionDashboardWhite.png Normal file

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

После

Ширина:  |  Высота:  |  Размер: 167 KiB

Двоичные данные
Workbooks/Images/Preview/FncMainDashboardBlack.png Normal file

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

После

Ширина:  |  Высота:  |  Размер: 111 KiB

Двоичные данные
Workbooks/Images/Preview/FncMainDashboardWhite.png Normal file

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

После

Ширина:  |  Высота:  |  Размер: 110 KiB

Двоичные данные
Workbooks/Images/Preview/FncObservationDashboardBlack.png Normal file

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

После

Ширина:  |  Высота:  |  Размер: 172 KiB

Двоичные данные
Workbooks/Images/Preview/FncObservationDashboardWhite.png Normal file

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

После

Ширина:  |  Высота:  |  Размер: 172 KiB

Двоичные данные
Workbooks/Images/Preview/FncSuricataDashboardBlack.png Normal file

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

После

Ширина:  |  Высота:  |  Размер: 181 KiB

Двоичные данные
Workbooks/Images/Preview/FncSuricataDashboardWhite.png Normal file

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

После

Ширина:  |  Высота:  |  Размер: 180 KiB

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

@ -6910,5 +6910,33 @@
"templateRelativePath": "MalwareProtectionEssentialsWorkbook.json",
"subtitle": "",
"provider": "Microsoft Sentinel community"
},
{
"workbookKey": "FortinetFortiNdrCloudWorkbook",
"logoFileName": "fortinet_logo.svg",
"description": "Gain insights into Fortinet FortiNDR CLoud events, including the Suricata, Observatino and Detections data.",
"dataTypesDependencies": [
"FncEventsSuricata_CL",
"FncEventsObservation_CL",
"FncEventsDetections_CL"
],
"dataConnectorsDependencies": [
"FortinetFortiNdrCloudDataConnector"
],
"previewImagesFileNames": [
"FncDetectionDashboardBlack.png",
"FncDetectionDashboardWhite.png",
"FncObservationDashboardBlack.png",
"FncObservationDashboardWhite.png",
"FncSuricataDashboardBlack.png",
"FncSuricataDashboardWhite.png",
"FncMainDashboardBlack.png",
"FncMainDashboardWhite.png"
],
"version": "1.0.0",
"title": "FortiNDR Cloud",
"templateRelativePath": "FortinetFortiNdrCloudWorkbook.json",
"subtitle": "",
"provider": "Fortinet"
}
]