This reverts commit ff69f85224.
This commit is contained in:
Ofer Shezaf 2022-01-03 16:21:46 +02:00
Родитель ff69f85224
Коммит ee97399b42
425 изменённых файлов: 59529 добавлений и 3746 удалений

39
.github/pull_request_template.md поставляемый
Просмотреть файл

@ -1,7 +1,36 @@
Fixes #
## Before submitting this PR please ensure that you have read the following sections and then completed the template below:
## Proposed Changes
Thank you for your contribution to the Microsoft Sentinel Github repo.
-
-
-
> The code should have been tested in a Microsoft Sentinel environment that does not have any custom parsers, functions or tables, so that you validate no incorrect syntax and execution functions properly.
> Details of the code changes in your submitted PR. Providing descriptions for pull requests ensures, there is context to changes being made and greatly enhances the code review process. Providing associated Issues that this resolves also easily connects the reason.
Change(s):
- Updated syntax for XYZ.yaml
Reason for Change(s):
- New schema used for XYZ.yaml
- Resolves ISSUE #1234
## After the submission has been made, please look at the Validation Checks:
> Check that the validations are passing and address any issues that are present. Let us know if you have tried fixing and need help.
> References:
> - [Guidance for Detection checks](https://github.com/Azure/Azure-Sentinel#pull-request-detection-template-structure-validation-check)
> - [General contribution guidance](https://github.com/Azure/Azure-Sentinel/wiki#what-can-you-contribute-and-how-can-you-create-contributions)
> - [PR validation troubleshooting](https://github.com/Azure/Azure-Sentinel#pull-request)
## PR Template
-----------------------------------------------------------------------------------------------------------
**Description for the PR:**
(Enter the description below)
**Testing Completed:**
Yes/ No :
-----------------------------------------------------------------------------------------------------------

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

@ -64,6 +64,10 @@ function getConnectorCategory(dataTypes : any, instructionSteps:[])
{
return ConnectorCategory.Event;
}
else if (dataTypes[0].name.includes("AzureDiagnostics"))
{
return ConnectorCategory.AzureDiagnostics;
}
else if(dataTypes[0].name.endsWith("_CL"))
{
let isAzureFunction:boolean = false;

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

@ -9,10 +9,6 @@
"Name": "PurviewTenantId",
"Type": "String"
},
{
"Name": "PurviewSubscriptionId",
"Type": "String"
},
{
"Name": "PurviewAccountName",
"Type": "String"
@ -46,7 +42,7 @@
"Type": "String"
},
{
"Name": "SourceOwner",
"Name": "SourceScanId",
"Type": "String"
},
{
@ -69,10 +65,6 @@
"Name": "AssetModifiedTime",
"Type": "DateTime"
},
{
"Name": "AssetOwner",
"Type": "String"
},
{
"Name": "AssetLastScanTime",
"Type": "DateTime"
@ -90,7 +82,7 @@
"Type": "String"
},
{
"Name": "ActivityTrigger",
"Name": "ClassificationTrigger",
"Type": "String"
},
{
@ -98,20 +90,20 @@
"Type": "Dynamic"
},
{
"Name": "ClassificationCount",
"Type": "Long"
"Name": "ClassificationDetails",
"Type": "Dynamic"
},
{
"Name": "SensitivityLabelGuid",
"Name": "SensitivityLabelTrigger",
"Type": "String"
},
{
"Name": "SensitivityLabelName",
"Name": "SensitivityLabel",
"Type": "String"
},
{
"Name": "UserId",
"Type": "String"
"Name": "SensitivityLabelDetails",
"Type": "Dynamic"
}
]
}

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

@ -0,0 +1,333 @@
{
"Name": "CiscoDuo",
"Properties": [
{
"Name": "AccessDvcBrowser",
"Type": "String"
},
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "AccessDvcBrowserVersion",
"Type": "String"
},
{
"Name": "AccessDvcEncryptionEnabled",
"Type": "Boolean"
},
{
"Name": "AccessDvcFirewallEnabled",
"Type": "Boolean"
},
{
"Name": "AccessDvcFlashVersion",
"Type": "String"
},
{
"Name": "AccessDvcIpAddr",
"Type": "String"
},
{
"Name": "AccessDvcJavaVersion",
"Type": "String"
},
{
"Name": "AccessDvcFlashVersion",
"Type": "String"
},
{
"Name": "AccessDvcLocationState",
"Type": "String"
},
{
"Name": "AccessDvcOsVersion",
"Type": "String"
},
{
"Name": "AccessDvcPasswordSet",
"Type": "Boolean"
},
{
"Name": "AccessDvcSecurityAgents",
"Type": "String"
},
{
"Name": "Alias",
"Type": "String"
},
{
"Name": "AuthDeviceCity",
"Type": "String"
},
{
"Name": "AuthDeviceCountry",
"Type": "String"
},
{
"Name": "AuthDeviceState",
"Type": "String"
},
{
"Name": "AuthFactor",
"Type": "String"
},
{
"Name": "Context",
"Type": "String"
},
{
"Name": "Credits",
"Type": "Double"
},
{
"Name": "description_s",
"Type": "String"
},
{
"Name": "DstGeoRegion",
"Type": "String"
},
{
"Name": "DstUserName",
"Type": "String"
},
{
"Name": "DvcAction",
"Type": "String"
},
{
"Name": "DvcHostname",
"Type": "String"
},
{
"Name": "EventEndTime",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "EventResult",
"Type": "String"
},
{
"Name": "EventResultDetails",
"Type": "String"
},
{
"Name": "EventType",
"Type": "String"
},
{
"Name": "EventUid",
"Type": "String"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "Explanations",
"Type": "String"
},
{
"Name": "FromCommonNetblock",
"Type": "String"
},
{
"Name": "FromNewUser",
"Type": "Boolean"
},
{
"Name": "HttpUserAgentOriginal",
"Type": "Boolean"
},
{
"Name": "IsoTimestamp",
"Type": "DateTime"
},
{
"Name": "Phone",
"Type": "Boolean"
},
{
"Name": "PriorityEvent",
"Type": "Boolean"
},
{
"Name": "PriorityReasons",
"Type": "String"
},
{
"Name": "Sekey",
"Type": "String"
},
{
"Name": "SrcAppId",
"Type": "String"
},
{
"Name": "SrcAppName",
"Type": "String"
},
{
"Name": "SrcDomainType",
"Type": "String"
},
{
"Name": "SrcDvcOs",
"Type": "String"
},
{
"Name": "SrcDvcType",
"Type": "String"
},
{
"Name": "SrcGeoCity",
"Type": "String"
},
{
"Name": "SrcGeoCountry",
"Type": "String"
},
{
"Name": "SrcHostname",
"Type": "String"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "SrcRiskLevel",
"Type": "Boolean"
},
{
"Name": "SrcUserId",
"Type": "String"
},
{
"Name": "SrcUserName",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceBrowser",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceBrowserVersion",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceEncryptionEnabled",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceFirewallEnabled",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceIp",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceLocationCity",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceLocationCountry",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceLocationState",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceOs",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceOsVersion",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDevicePasswordSet",
"Type": "String"
},
{
"Name": "SurfacedAuthAccessDeviceSecurityAgents",
"Type": "String"
},
{
"Name": "SurfacedAuthAlias",
"Type": "String"
},
{
"Name": "SurfacedAuthApplicationKey",
"Type": "String"
},
{
"Name": "SurfacedAuthApplicationName",
"Type": "Double"
},
{
"Name": "SurfacedAuthEmail",
"Type": "String"
},
{
"Name": "SurfacedAuthFactor",
"Type": "Boolean"
},
{
"Name": "SurfacedAuthIsotimestamp",
"Type": "DateTime"
},
{
"Name": "SurfacedAuthOodSoftware",
"Type": "String"
},
{
"Name": "SurfacedAuthReason",
"Type": "String"
},
{
"Name": "SurfacedAuthResult",
"Type": "String"
},
{
"Name": "SurfacedAuthTimestamp",
"Type": "Double"
},
{
"Name": "SurfacedAuthTransactionId",
"Type": "String"
},
{
"Name": "SurfacedAuthUserGroups",
"Type": "String"
},
{
"Name": "SurfacedAuthUserKey",
"Type": "String"
},
{
"Name": "SurfacedAuthUserName",
"Type": "Double"
},
{
"Name": "SurfacedTimestamp",
"Type": "Double"
},
{
"Name": "TransactionId",
"Type": "String"
},
{
"Name": "TriagedAsInteresting",
"Type": "Boolean"
}
]
}

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

@ -0,0 +1,385 @@
{
"Name": "CiscoWSAEvent",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "AmpFileHashSha256",
"Type": "String"
},
{
"Name": "AmpFileName",
"Type": "String"
},
{
"Name": "AmpReputationScore",
"Type": "String"
},
{
"Name": "AmpScanningVerdict",
"Type": "String"
},
{
"Name": "AmpThreatName",
"Type": "String"
},
{
"Name": "AmpUploadIndicator",
"Type": "String"
},
{
"Name": "ArchiveScannerFileVerdict",
"Type": "String"
},
{
"Name": "ArchiveScanningVerdict",
"Type": "String"
},
{
"Name": "ArchiveScanningVerdictDetail",
"Type": "String"
},
{
"Name": "AvcApplicationBehavior",
"Type": "String"
},
{
"Name": "AvcApplicationName",
"Type": "String"
},
{
"Name": "AvcApplicationType",
"Type": "String"
},
{
"Name": "AvgBandwidth(Kb/sec)",
"Type": "Double"
},
{
"Name": "BlockedFileTypeDetail",
"Type": "String"
},
{
"Name": "CiscoDataSecurityScanningVerdict",
"Type": "String"
},
{
"Name": "ClientRequestThreatName",
"Type": "String"
},
{
"Name": "ContactedServerCode",
"Type": "String"
},
{
"Name": "DataSecurityPolicyGroupName",
"Type": "String"
},
{
"Name": "DcaUrlCategoryVerdict",
"Type": "String"
},
{
"Name": "DstBytes",
"Type": "String"
},
{
"Name": "DstHostname",
"Type": "Int"
},
{
"Name": "DstIpAddr",
"Type": "String"
},
{
"Name": "DstPortNumber",
"Type": "String"
},
{
"Name": "DvcAction",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "EventResultDetails",
"Type": "String"
},
{
"Name": "EventStartTime",
"Type": "DateTime"
},
{
"Name": "EventTime",
"Type": "DateTime"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "ExternalDlpScannningVerdict",
"Type": "String"
},
{
"Name": "ExternalDplPolicyGroupName",
"Type": "String"
},
{
"Name": "GteEncapsulatedUrl",
"Type": "String"
},
{
"Name": "HostIP",
"Type": "String"
},
{
"Name": "HostName",
"Type": "String"
},
{
"Name": "HttpReferrerOriginal",
"Type": "String"
},
{
"Name": "HttpRequestMethod",
"Type": "String"
},
{
"Name": "HttpRequestXff",
"Type": "String"
},
{
"Name": "HttpStatusCode",
"Type": "String"
},
{
"Name": "IdentityPolicyGroupName",
"Type": "String"
},
{
"Name": "Latency",
"Type": "Integer"
},
{
"Name": "MalwareScanningVerdict",
"Type": "String"
},
{
"Name": "McAfeeDetectionType",
"Type": "String"
},
{
"Name": "McAfeeMalwareScanningVerdict",
"Type": "String"
},
{
"Name": "McAfeeScanError",
"Type": "String"
},
{
"Name": "McAfeeScannedFileName",
"Type": "String"
},
{
"Name": "McAfeeThreatCategory",
"Type": "String"
},
{
"Name": "McAfeeThreatName",
"Type": "String"
},
{
"Name": "NetworkApplicationProtocol",
"Type": "String"
},
{
"Name": "NetworkBytes",
"Type": "String"
},
{
"Name": "OutboundMalwareScanningPolicyGroupName",
"Type": "String"
},
{
"Name": "PolicyGroupName",
"Type": "String"
},
{
"Name": "RequestSideAntiMalwareScanningVerdict",
"Type": "String"
},
{
"Name": "RequestSideDvsScanningVerdict",
"Type": "String"
},
{
"Name": "RequestSideDvsThreatName",
"Type": "String"
},
{
"Name": "RequestSideDvsVerdictName",
"Type": "String"
},
{
"Name": "RequestSideScanningUrlCategoryVerdict",
"Type": "String"
},
{
"Name": "RequestUri",
"Type": "String"
},
{
"Name": "ResponseBodyMimeType",
"Type": "String"
},
{
"Name": "ResponseSideScanningUrlCategoryVerdict",
"Type": "String"
},
{
"Name": "ResponseSideThreatCategory",
"Type": "String"
},
{
"Name": "ResponseSideThreatCategoryCode",
"Type": "String"
},
{
"Name": "ResponseSideThreatName",
"Type": "String"
},
{
"Name": "ResponseThreatCategory",
"Type": "String"
},
{
"Name": "RoutingPolicy",
"Type": "String"
},
{
"Name": "SafeBrowsingScanningVerdict",
"Type": "String"
},
{
"Name": "SeverityLevel",
"Type": "String"
},
{
"Name": "SophosScannedFileName",
"Type": "String"
},
{
"Name": "SophosScanningVerdict",
"Type": "String"
},
{
"Name": "SophosScanReturnCode",
"Type": "String"
},
{
"Name": "SophosThreatName",
"Type": "String"
},
{
"Name": "SrcBytes",
"Type": "String"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "SrcPortNumber",
"Type": "String"
},
{
"Name": "SrcUserName",
"Type": "String"
},
{
"Name": "SuspectedUserAgent",
"Type": "String"
},
{
"Name": "ThreatIdentifier",
"Type": "String"
},
{
"Name": "ThreatName",
"Type": "String"
},
{
"Name": "ThreatRiskRatioValue",
"Type": "String"
},
{
"Name": "Throttled",
"Type": "String"
},
{
"Name": "TraceIdentifier",
"Type": "String"
},
{
"Name": "UrlCategory",
"Type": "String"
},
{
"Name": "UrlOriginal",
"Type": "String"
},
{
"Name": "UserType",
"Type": "String"
},
{
"Name": "WbrsScore",
"Type": "String"
},
{
"Name": "WebReputationScore",
"Type": "String"
},
{
"Name": "WebReputationThreatCategory",
"Type": "String"
},
{
"Name": "WebReputationThreatType",
"Type": "String"
},
{
"Name": "WebrootScanningVerdict",
"Type": "String"
},
{
"Name": "WebrootSpyId",
"Type": "String"
},
{
"Name": "WebrootThreatName",
"Type": "String"
},
{
"Name": "WebrootThreatRiskRatio",
"Type": "String"
},
{
"Name": "WebrootTraceId",
"Type": "String"
},
{
"Name": "WebTapBehavior",
"Type": "String"
},
{
"Name": "YouTubeUrlCategory",
"Type": "String"
}
]
}

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

@ -0,0 +1,65 @@
{
"Name": "Syslog (Digital Guardian)",
"Properties": [
{
"Name": "TenantId",
"Type": "String"
},
{
"Name": "SourceSystem",
"Type": "String"
},
{
"Name": "TimeGenerated [UTC]",
"Type": "DateTime"
},
{
"Name": "Computer",
"Type": "String"
},
{
"Name": "EventTime [UTC]",
"Type": "DateTime"
},
{
"Name": "Facility",
"Type": "String"
},
{
"Name": "HostName",
"Type": "String"
},
{
"Name": "SeverityLevel",
"Type": "String"
},
{
"Name": "SyslogMessage",
"Type": "String"
},
{
"Name": "ProcessID",
"Type": "String"
},
{
"Name": "HostIP",
"Type": "Int"
},
{
"Name": "ProcessName",
"Type": "String"
},
{
"Name": "MG",
"Type": "String"
},
{
"Name": "Type",
"Type": "String"
},
{
"Name": "_ResourceId",
"Type": "String"
}
]
}

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

@ -0,0 +1,149 @@
{
"name": "DigitalGuardianDLPEvent",
"Properties": [
{
"Name": "TenantId",
"Type": "String"
},
{
"Name": "SourceSystem",
"Type": "String"
},
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "Computer",
"Type": "String"
},
{
"Name": "EventTime",
"Type": "DateTime"
},
{
"Name": "Facility",
"Type": "String"
},
{
"Name": "HostName",
"Type": "String"
},
{
"Name": "SeverityLevel",
"Type": "String"
},
{
"Name": "SyslogMessage",
"Type": "String"
},
{
"Name": "ProcessID",
"Type": "Int32"
},
{
"Name": "HostIP",
"Type": "String"
},
{
"Name": "ProcessName",
"Type": "String"
},
{
"Name": "MG",
"Type": "String"
},
{
"Name": "Type",
"Type": "String"
},
{
"Name": "_ResourceId",
"Type": "String"
},
{
"Name": "DvcAvtion",
"Type": "String"
},
{
"Name": "DstUserName",
"Type": "String"
},
{
"Name": "DstIpAddr",
"Type": "String"
},
{
"Name": "DstPortNumber",
"Type": "String"
},
{
"Name": "email_recipients",
"Type": "String"
},
{
"Name": "email_sender",
"Type": "String"
},
{
"Name": "email_subject",
"Type": "String"
},
{
"Name": "http_url",
"Type": "String"
},
{
"Name": "IncidentId",
"Type": "String"
},
{
"Name": "IncidentStatus",
"Type": "String"
},
{
"Name": "IncidentsUrl",
"Type": "String"
},
{
"Name": "inspected_document",
"Type": "String"
},
{
"Name": "managed_device_id",
"Type": "String"
},
{
"Name": "MatchedPolicies",
"Type": "String"
},
{
"Name": "matches",
"Type": "String"
},
{
"Name": "EventCount",
"Type": "String"
},
{
"Name": "NetworkApplicationProtocol",
"Type": "String"
},
{
"Name": "SrcUserName",
"Type": "String"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "SrcPortNumber",
"Type": "String"
},
{
"Name": "EventEndTime",
"Type": "DateTime"
}
]
}

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

@ -0,0 +1,157 @@
{
"name": "ImpervaWAFCloud",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "EventType",
"Type": "String"
},
{
"Name": "EventSeverity",
"Type": "String"
},
{
"Name": "DvcAction",
"Type": "String"
},
{
"Name": "NetworkApplicationProtocol",
"Type": "String"
},
{
"Name": "Country",
"Type": "String"
},
{
"Name": "City",
"Type": "String"
},
{
"Name": "HttpStatusCode",
"Type": "String"
},
{
"Name": "SrcPortNumber",
"Type": "String"
},
{
"Name": "AccountName",
"Type": "String"
},
{
"Name": "RequestId",
"Type": "String"
},
{
"Name": "PoPName",
"Type": "String"
},
{
"Name": "BrowserType",
"Type": "String"
},
{
"Name": "EventEndTime",
"Type": "String"
},
{
"Name": "NetworkSessionId",
"Type": "String"
},
{
"Name": "PostBody",
"Type": "String"
},
{
"Name": "QueryString",
"Type": "String"
},
{
"Name": "UrlOriginal",
"Type": "String"
},
{
"Name": "HttpUserAgentOriginal",
"Type": "String"
},
{
"Name": "HttpRequestMethod",
"Type": "String"
},
{
"Name": "DstIpAddr",
"Type": "String"
},
{
"Name": "SiteID",
"Type": "String"
},
{
"Name": "DstDomainHostname",
"Type": "String"
},
{
"Name": "DstPortNumber",
"Type": "String"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "EventStartTime",
"Type": "String"
},
{
"Name": "AccountID",
"Type": "String"
},
{
"Name": "NetworkApplicationProtocoVersion",
"Type": "String"
},
{
"Name": "HttpRequestXff",
"Type": "String"
},
{
"Name": "CaptchaSupport",
"Type": "String"
},
{
"Name": "ClientApp",
"Type": "String"
},
{
"Name": "ClientAppSig",
"Type": "String"
},
{
"Name": "CookiesSupport",
"Type": "String"
},
{
"Name": "SrcGeoLatitude",
"Type": "String"
},
{
"Name": "SrcGeoLongitude",
"Type": "String"
},
{
"Name": "VisitorID",
"Type": "String"
}
]
}

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

@ -0,0 +1,533 @@
{
"name": "SentinelOne",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "AccountName",
"Type": "String"
},
{
"Name": "ActivityType",
"Type": "Double"
},
{
"Name": "EventCreationTime",
"Type": "DateTime"
},
{
"Name": "DataAccountName",
"Type": "String"
},
{
"Name": "DataFullScopeDetails",
"Type": "String"
},
{
"Name": "DataScopeLevel",
"Type": "String"
},
{
"Name": "DataScopeName",
"Type": "String"
},
{
"Name": "DataSiteId",
"Type": "Double"
},
{
"Name": "DataSiteName",
"Type": "String"
},
{
"Name": "SrcUserName",
"Type": "String"
},
{
"Name": "EventId",
"Type": "String"
},
{
"Name": "EventOriginalMessage",
"Type": "String"
},
{
"Name": "SiteId",
"Type": "String"
},
{
"Name": "SiteName",
"Type": "String"
},
{
"Name": "UpdatedAt",
"Type": "DateTime"
},
{
"Name": "UserIdentity",
"Type": "String"
},
{
"Name": "EventType",
"Type": "String"
},
{
"Name": "DataByUser",
"Type": "String"
},
{
"Name": "DataRole",
"Type": "String"
},
{
"Name": "DataUserScope",
"Type": "String"
},
{
"Name": "EventTypeDetailed",
"Type": "String"
},
{
"Name": "DataSource",
"Type": "String"
},
{
"Name": "DataExpiryDateStr",
"Type": "String"
},
{
"Name": "DataExpiryTime",
"Type": "Double"
},
{
"Name": "DataNetworkquarantine",
"Type": "Boolean"
},
{
"Name": "DataRuleCreationTime",
"Type": "Double"
},
{
"Name": "DataRuleDescription",
"Type": "String"
},
{
"Name": "DataRuleExpirationMode",
"Type": "String"
},
{
"Name": "DataRuleId",
"Type": "Double"
},
{
"Name": "DataRuleName",
"Type": "String"
},
{
"Name": "DataRuleQueryDetails",
"Type": "String"
},
{
"Name": "DataRuleQueryType",
"Type": "String"
},
{
"Name": "DataRuleSeverity",
"Type": "String"
},
{
"Name": "DataScopeId",
"Type": "Double"
},
{
"Name": "DataStatus",
"Type": "String"
},
{
"Name": "DataSystemUser",
"Type": "Double"
},
{
"Name": "DataTreatasthreat",
"Type": "String"
},
{
"Name": "DataUserId",
"Type": "Double"
},
{
"Name": "DataUserName",
"Type": "String"
},
{
"Name": "EventSubStatus",
"Type": "String"
},
{
"Name": "AgentId",
"Type": "String"
},
{
"Name": "DataComputerName",
"Type": "String"
},
{
"Name": "DataExternalIp",
"Type": "String"
},
{
"Name": "DataGroupName",
"Type": "String"
},
{
"Name": "DataSystem",
"Type": "Boolean"
},
{
"Name": "DataUuid",
"Type": "String"
},
{
"Name": "GroupId",
"Type": "String"
},
{
"Name": "GroupName",
"Type": "String"
},
{
"Name": "DataGroup",
"Type": "String"
},
{
"Name": "DataOptionalGroups",
"Type": "String"
},
{
"Name": "DataCreatedAt",
"Type": "DateTime"
},
{
"Name": "DataDownloadUrl",
"Type": "String"
},
{
"Name": "DataFilePath",
"Type": "String"
},
{
"Name": "DataFilename",
"Type": "String"
},
{
"Name": "DataUploadedFilename",
"Type": "String"
},
{
"Name": "Comments",
"Type": "String"
},
{
"Name": "DataNewValue",
"Type": "String"
},
{
"Name": "DataPolicyId",
"Type": "String"
},
{
"Name": "DataPolicyName",
"Type": "String"
},
{
"Name": "DataNewValueb",
"Type": "Boolean"
},
{
"Name": "DataShouldReboot",
"Type": "Boolean"
},
{
"Name": "DataRoleName",
"Type": "String"
},
{
"Name": "DataScopeLevelName",
"Type": "String"
},
{
"Name": "ActiveDirectoryComputerDistinguishedName",
"Type": "String"
},
{
"Name": "ActiveDirectoryComputerMemberOf",
"Type": "String"
},
{
"Name": "ActiveDirectoryLastUserDistinguishedName",
"Type": "String"
},
{
"Name": "ActiveDirectoryLastUserMemberOf",
"Type": "String"
},
{
"Name": "ActiveThreats",
"Type": "Double"
},
{
"Name": "AgentVersion",
"Type": "String"
},
{
"Name": "AllowRemoteShell",
"Type": "Boolean"
},
{
"Name": "AppsVulnerabilityStatus",
"Type": "String"
},
{
"Name": "ComputerName",
"Type": "String"
},
{
"Name": "ConsoleMigrationStatus",
"Type": "String"
},
{
"Name": "CoreCount",
"Type": "Double"
},
{
"Name": "CpuCount",
"Type": "Double"
},
{
"Name": "CpuId",
"Type": "String"
},
{
"Name": "SrcDvcDomain",
"Type": "String"
},
{
"Name": "EncryptedApplications",
"Type": "Boolean"
},
{
"Name": "ExternalId",
"Type": "String"
},
{
"Name": "ExternalIp",
"Type": "String"
},
{
"Name": "FirewallEnabled",
"Type": "Boolean"
},
{
"Name": "GroupIp",
"Type": "String"
},
{
"Name": "InRemoteShellSession",
"Type": "Boolean"
},
{
"Name": "Infected",
"Type": "Boolean"
},
{
"Name": "InstallerType",
"Type": "String"
},
{
"Name": "IsActive",
"Type": "Boolean"
},
{
"Name": "IsDecommissioned",
"Type": "Boolean"
},
{
"Name": "IsPendingUninstall",
"Type": "Boolean"
},
{
"Name": "IsUninstalled",
"Type": "Boolean"
},
{
"Name": "IsUpToDate",
"Type": "Boolean"
},
{
"Name": "LastActiveDate",
"Type": "DateTime"
},
{
"Name": "LastIpToMgmt",
"Type": "String"
},
{
"Name": "LastLoggedInUserName",
"Type": "String"
},
{
"Name": "LicenseKey",
"Type": "String"
},
{
"Name": "LocationEnabled",
"Type": "Boolean"
},
{
"Name": "LocationType",
"Type": "String"
},
{
"Name": "Locations",
"Type": "String"
},
{
"Name": "MachineType",
"Type": "String"
},
{
"Name": "MitigationMode",
"Type": "String"
},
{
"Name": "MitigationModeSuspicious",
"Type": "String"
},
{
"Name": "SrcDvcModelName",
"Type": "String"
},
{
"Name": "NetworkInterfaces",
"Type": "String"
},
{
"Name": "NetworkQuarantineEnabled",
"Type": "Boolean"
},
{
"Name": "NetworkStatus",
"Type": "String"
},
{
"Name": "OperationalState",
"Type": "String"
},
{
"Name": "OsArch",
"Type": "String"
},
{
"Name": "SrcDvcOs",
"Type": "String"
},
{
"Name": "OsRevision",
"Type": "String"
},
{
"Name": "OsStartTime",
"Type": "DateTime"
},
{
"Name": "OsType",
"Type": "String"
},
{
"Name": "RangerStatus",
"Type": "String"
},
{
"Name": "RangerVersion",
"Type": "String"
},
{
"Name": "RegisteredAt",
"Type": "DateTime"
},
{
"Name": "RemoteProfilingState",
"Type": "String"
},
{
"Name": "ScanFinishedAt",
"Type": "DateTime"
},
{
"Name": "ScanStartedAt",
"Type": "DateTime"
},
{
"Name": "ScanStatus",
"Type": "String"
},
{
"Name": "ThreatRebootRequired",
"Type": "Boolean"
},
{
"Name": "TotalMemory",
"Type": "Double"
},
{
"Name": "UserActionsNeeded",
"Type": "String"
},
{
"Name": "Uuid",
"Type": "String"
},
{
"Name": "Creator",
"Type": "String"
},
{
"Name": "CreatorId",
"Type": "String"
},
{
"Name": "Inherits",
"Type": "Boolean"
},
{
"Name": "IsDefault",
"Type": "Boolean"
},
{
"Name": "Name",
"Type": "String"
},
{
"Name": "RegistrationToken",
"Type": "String"
},
{
"Name": "TotalAgents",
"Type": "Double"
},
{
"Name": "Type",
"Type": "String"
}
]
}

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

@ -0,0 +1,133 @@
{
"name": "TrendMicroCAS",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "EventOriginalUid",
"Type": "String"
},
{
"Name": "EventCategoryType",
"Type": "String"
},
{
"Name": "EventType",
"Type": "String"
},
{
"Name": "ScanType",
"Type": "String"
},
{
"Name": "DstUserName",
"Type": "String"
},
{
"Name": "SrcFilePath",
"Type": "String"
},
{
"Name": "DetectionTime",
"Type": "DateTime"
},
{
"Name": "TriggeredPolicyName",
"Type": "String"
},
{
"Name": "TriggeredSecurityFilter",
"Type": "String"
},
{
"Name": "EventOriginalResultDetails",
"Type": "String"
},
{
"Name": "EventResult",
"Type": "String"
},
{
"Name": "MailMessageId",
"Type": "String"
},
{
"Name": "MailMessageSender",
"Type": "String"
},
{
"Name": "MailMessageRecipient",
"Type": "String"
},
{
"Name": "MailMessageSubmitTime",
"Type": "DateTime"
},
{
"Name": "MailMessageDeliveryTime",
"Type": "DateTime"
},
{
"Name": "MailMessageSubject",
"Type": "String"
},
{
"Name": "MailMessageFileName",
"Type": "String"
},
{
"Name": "SrcFileName",
"Type": "String"
},
{
"Name": "FileUploadTime",
"Type": "DateTime"
},
{
"Name": "SecurityRiskName",
"Type": "String"
},
{
"Name": "DetectedBy",
"Type": "String"
},
{
"Name": "RiskLevel",
"Type": "String"
},
{
"Name": "SrcFileSHA1",
"Type": "String"
},
{
"Name": "SrcFileSHA256",
"Type": "String"
},
{
"Name": "VirusName",
"Type": "String"
},
{
"Name": "DetectionType",
"Type": "String"
},
{
"Name": "RansomwareName",
"Type": "String"
},
{
"Name": "TriggeredDlpTemplate",
"Type": "String"
}
]
}

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

@ -0,0 +1,81 @@
{
"name": "VMwareESXi",
"Properties": [
{
"Name": "TenantId",
"Type": "String"
},
{
"Name": "SourceSystem",
"Type": "String"
},
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "Computer",
"Type": "String"
},
{
"Name": "EventTime",
"Type": "DateTime"
},
{
"Name": "Facility",
"Type": "String"
},
{
"Name": "HostName",
"Type": "String"
},
{
"Name": "SeverityLevel",
"Type": "String"
},
{
"Name": "SyslogMessage",
"Type": "String"
},
{
"Name": "ProcessID",
"Type": "Int"
},
{
"Name": "HostIP",
"Type": "String"
},
{
"Name": "ProcessName",
"Type": "String"
},
{
"Name": "MG",
"Type": "String"
},
{
"Name": "Type",
"Type": "String"
},
{
"Name": "_ResourceId",
"Type": "String"
},
{
"Name": "Sub",
"Type": "String"
},
{
"Name": "OpId",
"Type": "String"
},
{
"Name": "UserName",
"Type": "String"
},
{
"Name": "Message",
"Type": "String"
}
]
}

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

@ -1,386 +1,513 @@
{
"Name": "imNetworkSession",
"Properties": [{
"Properties": [
{
"Name": "TimeGenerated",
"Type": "datetime"
}, {
},
{
"Name": "_ResourceId",
"Type": "string"
}, {
},
{
"Name": "Type",
"Type": "string"
}, {
},
{
"Name": "EventMessage",
"Type": "string"
}, {
},
{
"Name": "EventCount",
"Type": "int"
}, {
},
{
"Name": "EventStartTime",
"Type": "datetime"
}, {
},
{
"Name": "EventEndTime",
"Type": "datetime"
}, {
},
{
"Name": "EventType",
"Type": "string"
}, {
},
{
"Name": "EventSubType",
"Type": "string"
}, {
},
{
"Name": "EventResult",
"Type": "string"
}, {
},
{
"Name": "EventResultDetails",
"Type": "string"
}, {
},
{
"Name": "EventOriginalResultDetails",
"Type": "string"
}, {
},
{
"Name": "EventSeverity",
"Type": "string"
}, {
},
{
"Name": "EventOriginalSeverity",
"Type": "string"
}, {
},
{
"Name": "EventOriginalUid",
"Type": "string"
}, {
},
{
"Name": "EventOriginalType",
"Type": "string"
}, {
},
{
"Name": "EventProduct",
"Type": "string"
}, {
},
{
"Name": "EventProductVersion",
"Type": "string"
}, {
},
{
"Name": "EventVendor",
"Type": "string"
}, {
},
{
"Name": "EventSchema",
"Type": "string"
}, {
},
{
"Name": "EventSchemaVersion",
"Type": "string"
}, {
},
{
"Name": "EventReportUrl",
"Type": "string"
}, {
},
{
"Name": "Dvc",
"Type": "string"
}, {
},
{
"Name": "DvcIpAddr",
"Type": "string"
}, {
},
{
"Name": "DvcHostname",
"Type": "string"
}, {
},
{
"Name": "DvcDomain",
"Type": "string"
}, {
},
{
"Name": "DvcDomainType",
"Type": "string"
}, {
},
{
"Name": "DvcFQDN",
"Type": "string"
}, {
},
{
"Name": "DvcId",
"Type": "string"
}, {
},
{
"Name": "DvcIdType",
"Type": "string"
}, {
},
{
"Name": "DvcMacAddr",
"Type": "string"
}, {
},
{
"Name": "DvcZone",
"Type": "string"
}, {
},
{
"Name": "Dst",
"Type": "string"
}, {
},
{
"Name": "DstIpAddr",
"Type": "string"
}, {
},
{
"Name": "DstPortNumber",
"Type": "int"
}, {
},
{
"Name": "DstHostname",
"Type": "string"
}, {
},
{
"Name": "Hostname",
"Type": "string"
}, {
},
{
"Name": "DstDomain",
"Type": "string"
}, {
},
{
"Name": "DstDomainType",
"Type": "string"
}, {
},
{
"Name": "DstFQDN",
"Type": "string"
}, {
},
{
"Name": "DstDvcId",
"Type": "string"
}, {
},
{
"Name": "DstDvcIdType",
"Type": "string"
}, {
},
{
"Name": "DstDeviceType",
"Type": "string"
}, {
},
{
"Name": "DstUserId",
"Type": "string"
}, {
},
{
"Name": "DstUserIdType",
"Type": "string"
}, {
},
{
"Name": "DstUsername",
"Type": "string"
}, {
},
{
"Name": "User",
"Type": "string"
}, {
},
{
"Name": "DstUsernameType",
"Type": "string"
}, {
},
{
"Name": "DstUserType",
"Type": "string"
}, {
},
{
"Name": "DstOriginalUserType",
"Type": "string"
}, {
},
{
"Name": "DstUserDomain",
"Type": "string"
}, {
},
{
"Name": "DstAppName",
"Type": "string"
}, {
},
{
"Name": "DstAppId",
"Type": "string"
}, {
},
{
"Name": "DstAppType",
"Type": "string"
}, {
},
{
"Name": "DstZone",
"Type": "string"
}, {
},
{
"Name": "DstInterfaceName",
"Type": "string"
}, {
},
{
"Name": "DstInterfaceGuid",
"Type": "string"
}, {
},
{
"Name": "DstMacAddr",
"Type": "string"
}, {
},
{
"Name": "DstGeoCountry",
"Type": "string"
}, {
},
{
"Name": "DstGeoCity",
"Type": "string"
}, {
},
{
"Name": "DstGeoLatitude",
"Type": "string"
}, {
},
{
"Name": "DstGeoLongitude",
"Type": "string"
}, {
},
{
"Name": "Src",
"Type": "string"
}, {
},
{
"Name": "SrcIpAddr",
"Type": "string"
}, {
},
{
"Name": "SrcPortNumber",
"Type": "int"
}, {
},
{
"Name": "SrcHostname",
"Type": "string"
}, {
},
{
"Name": "SrcDomain",
"Type": "string"
}, {
},
{
"Name": "SrcDomainType",
"Type": "string"
}, {
},
{
"Name": "SrcFQDN",
"Type": "string"
}, {
},
{
"Name": "SrcDvcId",
"Type": "string"
}, {
},
{
"Name": "SrcDvcIdType",
"Type": "string"
}, {
},
{
"Name": "SrcDeviceType",
"Type": "string"
}, {
},
{
"Name": "SrcUserId",
"Type": "string"
}, {
},
{
"Name": "SrcUserIdType",
"Type": "string"
}, {
},
{
"Name": "SrcUsername",
"Type": "string"
}, {
},
{
"Name": "SrcUsernameType",
"Type": "string"
}, {
},
{
"Name": "SrcUserType",
"Type": "string"
}, {
},
{
"Name": "SrcOriginalUserType",
"Type": "string"
}, {
},
{
"Name": "SrcUserDomain",
"Type": "string"
}, {
},
{
"Name": "SrcAppName",
"Type": "string"
}, {
},
{
"Name": "SrcAppId",
"Type": "string"
}, {
},
{
"Name": "IpAddr",
"Type": "string"
}, {
},
{
"Name": "SrcAppType",
"Type": "string"
}, {
},
{
"Name": "SrcZone",
"Type": "string"
}, {
},
{
"Name": "SrcInterfaceName",
"Type": "string"
}, {
},
{
"Name": "SrcInterfaceGuid",
"Type": "string"
}, {
},
{
"Name": "SrcMacAddr",
"Type": "string"
}, {
},
{
"Name": "SrcGeoCountry",
"Type": "string"
}, {
},
{
"Name": "SrcGeoCity",
"Type": "string"
}, {
},
{
"Name": "SrcGeoLatitude",
"Type": "string"
}, {
},
{
"Name": "SrcGeoLongitude",
"Type": "string"
}, {
},
{
"Name": "NetworkApplicationProtocol",
"Type": "string"
}, {
},
{
"Name": "NetworkProtocol",
"Type": "string"
}, {
},
{
"Name": "NetworkDirection",
"Type": "string"
}, {
},
{
"Name": "NetworkDuration",
"Type": "int"
}, {
},
{
"Name": "Duration",
"Type": "int"
}, {
},
{
"Name": "NetworkIcmpCode",
"Type": "int"
}, {
},
{
"Name": "NetworkIcmpType",
"Type": "string"
}, {
},
{
"Name": "DstBytes",
"Type": "int"
}, {
},
{
"Name": "SrcBytes",
"Type": "int"
}, {
},
{
"Name": "NetworkBytes",
"Type": "int"
}, {
},
{
"Name": "DstPackets",
"Type": "int"
}, {
},
{
"Name": "SrcPackets",
"Type": "int"
}, {
},
{
"Name": "NetworkPackets",
"Type": "int"
}, {
},
{
"Name": "NetworkSessionId",
"Type": "string"
}, {
},
{
"Name": "SessionId",
"Type": "string"
}, {
},
{
"Name": "NetworkConnectionHistory",
"Type": "string"
}, {
},
{
"Name": "SrcVlanId",
"Type": "string"
}, {
},
{
"Name": "DstVlanId",
"Type": "string"
}, {
},
{
"Name": "InnerVlanId",
"Type": "string"
}, {
},
{
"Name": "OuterVlanId",
"Type": " string"
}, {
},
{
"Name": "DstNatIpAddr",
"Type": "string"
}, {
},
{
"Name": "DstNatPortNumber",
"Type": "int"
}, {
},
{
"Name": "SrcNatIpAddr",
"Type": "string"
}, {
},
{
"Name": "SrcNatPortNumber",
"Type": "int"
}, {
},
{
"Name": "DvcInboundInterface",
"Type": "string"
}, {
},
{
"Name": "DvcOutboundInterface",
"Type": "string"
}, {
},
{
"Name": "NetworkRuleName",
"Type": "string"
}, {
},
{
"Name": "NetworkRuleNumber",
"Type": "int"
}, {
},
{
"Name": "Rule",
"Type": "string"
}, {
},
{
"Name": "DvcAction",
"Type": "string"
}, {
},
{
"Name": "DvcOriginalAction",
"Type": "string"
}, {
},
{
"Name": "ThreatId",
"Type": "string"
}, {
},
{
"Name": "ThreatName",
"Type": "string"
}, {
},
{
"Name": "ThreatCategory",
"Type": "string"
}, {
},
{
"Name": "ThreatRiskLevel",
"Type": "int"
}, {
},
{
"Name": "ThreatRiskLevelOriginal",
"Type": "string"
}
]
}
}

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

@ -1,5 +1,5 @@
{
"Name": "imNetworkSession",
"Name": "imWebSession",
"Properties": [{
"Name": "TimeGenerated",
"Type": "datetime"

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

@ -1,19 +1,22 @@
using Microsoft.Azure.Sentinel.KustoServices.Contract;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Kqlvalidations.Tests
{
public class CustomTablesSchemasLoader : ITableSchemasLoader
{
private readonly List<TableSchema> _tableSchemas;
private const int TestFolderDepth = 3;
public CustomTablesSchemasLoader()
{
_tableSchemas = new List<TableSchema>();
var jsonFiles = Directory.GetFiles(DetectionsYamlFilesTestData.GetCustomTablesPath(), "*.json");
var jsonFilePath = Path.Combine(Utils.GetTestDirectory(TestFolderDepth), "CustomTables");
var jsonFiles = Directory.GetFiles(jsonFilePath, "*.json");
foreach (var jsonFile in jsonFiles)
{
var tableSchema = ReadTableSchema(jsonFile);

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

@ -1,76 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Kqlvalidations.Tests
{
public class DetectionsYamlFilesTestData : TheoryData<string>
{
public DetectionsYamlFilesTestData()
{
List<string> detectionPaths = GetDetectionPaths();
var files = GetDetectionFiles(detectionPaths);
files.ForEach(f => AddData(Path.GetFileName(f)));
}
public static List<string> GetDetectionPaths()
{
List<string> dirPaths = new List<string>() { "Detections", "Solutions"};
var rootDir = Directory.CreateDirectory(GetAssemblyDirectory());
var testFolderDepth = 6;
List<string> detectionPaths = new List<string>();
for (int i = 0; i < testFolderDepth; i++)
{
rootDir = rootDir.Parent;
}
foreach (var dirName in dirPaths)
{
detectionPaths.Add(Path.Combine(rootDir.FullName, dirName));
}
return detectionPaths;
}
public static string GetCustomTablesPath()
{
var rootDir = Directory.CreateDirectory(GetAssemblyDirectory());
var testFolderDepth = 3;
for (int i = 0; i < testFolderDepth; i++)
{
rootDir = rootDir.Parent;
}
var detectionPath = Path.Combine(rootDir.FullName, "CustomTables");
return detectionPath;
}
public static string GetSkipTemplatesPath()
{
var rootDir = Directory.CreateDirectory(GetAssemblyDirectory());
var testFolderDepth = 3;
for (int i = 0; i < testFolderDepth; i++)
{
rootDir = rootDir.Parent;
}
return rootDir.FullName;
}
private static string GetAssemblyDirectory()
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
private static List<string> GetDetectionFiles(List<string> detectionPaths)
{
var files = Directory.GetFiles(detectionPaths[0], "*.yaml", SearchOption.AllDirectories).ToList();
files.AddRange(Directory.GetFiles(detectionPaths[1], "*.yaml", SearchOption.AllDirectories).ToList().Where(s => s.Contains("Analytic Rules")));
return files;
}
}
}

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

@ -1,7 +1,5 @@
using Microsoft.Azure.Sentinel.KustoServices.Contract;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using Microsoft.Azure.Sentinel.KustoServices.Contract;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -13,7 +11,6 @@ namespace Kqlvalidations.Tests
public class KqlValidationTests
{
private readonly IKqlQueryAnalyzer _queryValidator;
private static readonly List<string> DetectionPaths = DetectionsYamlFilesTestData.GetDetectionPaths();
public KqlValidationTests()
{
_queryValidator = new KqlQueryAnalyzerBuilder()
@ -22,16 +19,14 @@ namespace Kqlvalidations.Tests
.Build();
}
// We pass File name to test because in the result file we want to show an informative name for the test
[Theory]
[ClassData(typeof(DetectionsYamlFilesTestData))]
public void Validate_DetectionQueries_HaveValidKql(string detectionsYamlFileName)
public void Validate_DetectionQueries_HaveValidKql(string fileName, string encodedFilePath)
{
var detectionsYamlFile = getDetectionsYamlFile(detectionsYamlFileName);
var yaml = File.ReadAllText(detectionsYamlFile);
var deserializer = new DeserializerBuilder().Build();
var res = deserializer.Deserialize<dynamic>(yaml);
string queryStr = res["query"];
string id = res["id"];
var res = ReadAndDeserializeYaml(encodedFilePath);
var queryStr = (string) res["query"];
var id = (string) res["id"];
//we ignore known issues
if (ShouldSkipTemplateValidation(id))
@ -39,41 +34,61 @@ namespace Kqlvalidations.Tests
return;
}
var validationRes = _queryValidator.ValidateSyntax(queryStr);
var firstErrorLocation = (Line: 0, Col: 0);
if (!validationRes.IsValid)
{
firstErrorLocation = GetLocationInQuery(queryStr, validationRes.Diagnostics.First(d => d.Severity == "Error").Start);
}
Assert.True(validationRes.IsValid, validationRes.IsValid ? string.Empty : $"Template Id:{id} is not valid in Line:{firstErrorLocation.Line} col:{firstErrorLocation.Col} Errors:{validationRes.Diagnostics.Select(d => d.ToString()).ToList().Aggregate((s1, s2) => s1 + "," + s2)}");
ValidateKql(id, queryStr);
}
// We pass File name to test because in the result file we want to show an informative name for the test
[Theory]
[ClassData(typeof(DetectionsYamlFilesTestData))]
public void Validate_DetectionQueries_SkippedTemplatesDoNotHaveValidKql(string detectionsYamlFileName)
public void Validate_DetectionQueries_SkippedTemplatesDoNotHaveValidKql(string fileName, string encodedFilePath)
{
var detectionsYamlFile = getDetectionsYamlFile(detectionsYamlFileName);
var res = ReadAndDeserializeYaml(encodedFilePath);
var queryStr = (string) res["query"];
var id = (string) res["id"];
var yaml = File.ReadAllText(detectionsYamlFile);
var deserializer = new DeserializerBuilder().Build();
var res = deserializer.Deserialize<dynamic>(yaml);
string queryStr = res["query"];
string id = res["id"];
//Templates that are in the skipped templates should not pass the validateion (if they pass, why skip?)
//Templates that are in the skipped templates should not pass the validation (if they pass, why skip?)
if (ShouldSkipTemplateValidation(id))
{
var validationRes = _queryValidator.ValidateSyntax(queryStr);
Assert.False(validationRes.IsValid, $"Template Id:{id} is valid but it is in the skipped validation templates. Please remove it from the templates that are skipped since it is valid.");
}
else
}
// // We pass File name to test because in the result file we want to show an informative name for the test
// [Theory]
// [ClassData(typeof(InsightsYamlFilesTestData))]
// public void Validate_InsightsQueries_HaveValidKqlBaseQuery(string fileName, string encodedFilePath)
// {
// var res = ReadAndDeserializeYaml(encodedFilePath);
// var queryStr = (string) res["BaseQuery"];
//
// ValidateKql(fileProp.FileName, queryStr);
// }
private void ValidateKql(string id, string queryStr)
{
return;
var validationRes = _queryValidator.ValidateSyntax(queryStr);
var firstErrorLocation = (Line: 0, Col: 0);
if (!validationRes.IsValid)
{
firstErrorLocation = GetLocationInQuery(queryStr, validationRes.Diagnostics.First(d => d.Severity == "Error").Start);
}
Assert.True(validationRes.IsValid,
validationRes.IsValid
? string.Empty
: @$"Template Id: {id} is not valid in Line: {firstErrorLocation.Line} col: {firstErrorLocation.Col}
Errors: {validationRes.Diagnostics.Select(d => d.ToString()).ToList().Aggregate((s1, s2) => s1 + "," + s2)}");
}
private Dictionary<object, object> ReadAndDeserializeYaml(string encodedFilePath)
{
var yaml = File.ReadAllText(Utils.DecodeBase64(encodedFilePath));
var deserializer = new DeserializerBuilder().Build();
return deserializer.Deserialize<dynamic>(yaml);
}
private bool ShouldSkipTemplateValidation(string templateId)
{
return TemplatesToSkipValidationReader.WhiteListTemplates
@ -97,23 +112,6 @@ namespace Kqlvalidations.Tests
var col = (pos - curPos + 1);
return (curlineIndex + 1, col);
}
/// <summary>
///Get detection yaml file from Detection or solution analytics rule folder
/// </summary>
/// <param name="detectionsYamlFileName">Detections Yaml File Name</param>
/// <returns>detections yaml file path</returns>
private string getDetectionsYamlFile(string detectionsYamlFileName)
{
try
{
return Directory.GetFiles(DetectionPaths[0], detectionsYamlFileName, SearchOption.AllDirectories).Single();
}
catch
{
return Directory.GetFiles(DetectionPaths[1], detectionsYamlFileName, SearchOption.AllDirectories).Where(s => s.Contains("Analytic Rules")).Single();
}
}
}
}

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

@ -112,7 +112,7 @@
{
"id": "4902eddb-34f7-44a8-ac94-8486366e9494",
"templateName": "ExcessiveDenyFromSource.yaml",
"validationFailReason": "The name 'imWebSession' does not refer to any known function"
"validationFailReason": "The name 'imNetworkSession' does not refer to any known function"
},
{
"id": "3f0c20d5-6228-48ef-92f3-9ff7822c1954",
@ -120,10 +120,17 @@
"validationFailReason": "The name 'imWebSession' does not refer to any known function"
},
{
"id": "6e575295-a7e6-464c-8192-3e1d8fd6a990",
"templateName": "Log4J_IPIOC_Dec112021.yaml",
"validationFailReason": "The name 'imDns' does not refer to any known function."
"id": "fcb9d75c-c3c1-4910-8697-f136bfef2363",
"templateName": "PossibleBeaconingActivity.yaml",
"validationFailReason": "The name 'imNetworkSession' does not refer to any known function."
},
// Commenting out for now as the imDNS has been commented out in the referenced query since it was causing customer query failures.
// Once ASIM is fully deployed to all customer environments, this will likely solve the overall issues.
//{
// "id": "6e575295-a7e6-464c-8192-3e1d8fd6a990",
// "templateName": "Log4J_IPIOC_Dec112021.yaml",
// "validationFailReason": "The name 'imDns' does not refer to any known function."
//},
{
"id": "b39e6482-ab7e-4817-813d-ec910b64b26e",
"templateName": "HighlySensitivePasswordAccessed.yaml",

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

@ -15,10 +15,11 @@ namespace Kqlvalidations.Tests
public static class TemplatesToSkipValidationReader
{
private const string SKipJsonFileName = "SkipValidationsTemplates.json";
private const int TestFolderDepth = 3;
static TemplatesToSkipValidationReader()
{
var jsonFilePath = Path.Combine(DetectionsYamlFilesTestData.GetSkipTemplatesPath(), SKipJsonFileName);
var jsonFilePath = Path.Combine(Utils.GetTestDirectory(TestFolderDepth), SKipJsonFileName);
using (StreamReader r = new StreamReader(jsonFilePath))
{
string json = r.ReadToEnd();

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

@ -0,0 +1,37 @@
using System;
using System.IO;
using System.Reflection;
namespace Kqlvalidations.Tests
{
public static class Utils
{
public static string GetTestDirectory(int testFolderDepth)
{
var rootDir = Directory.CreateDirectory(GetAssemblyDirectory());
for (int i = 0; i < testFolderDepth; i++)
{
rootDir = rootDir.Parent;
}
return rootDir.FullName;
}
public static string EncodeToBase64(string plainText) {
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(plainTextBytes);
}
public static string DecodeBase64(string base64EncodedData) {
var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
private static string GetAssemblyDirectory()
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
}

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

@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Kqlvalidations.Tests
{
public class DetectionsYamlFilesLoader : YamlFilesLoader
{
protected override List<string> GetDirectoryPaths()
{
var basePath = Utils.GetTestDirectory(TestFolderDepth);
var detectionsDir = new List<string> { Path.Combine(basePath, "Detections")};
var solutionDirectories = Path.Combine(basePath, "Solutions");
var analyticsRulesDir = Directory.GetDirectories(solutionDirectories, "Analytic Rules", SearchOption.AllDirectories);
return analyticsRulesDir.Concat(detectionsDir).ToList();
}
}
}

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

@ -0,0 +1,9 @@
namespace Kqlvalidations.Tests
{
public class DetectionsYamlFilesTestData : YamlFilesTestData
{
public DetectionsYamlFilesTestData() : base(new DetectionsYamlFilesLoader())
{
}
}
}

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

@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.IO;
namespace Kqlvalidations.Tests
{
public class InsightsYamlFilesLoader : YamlFilesLoader
{
protected override List<string> GetDirectoryPaths()
{
return new List<string> { Path.Combine(Utils.GetTestDirectory(TestFolderDepth), "Insights")};
}
}
}

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

@ -0,0 +1,11 @@
using System.IO;
namespace Kqlvalidations.Tests
{
public class InsightsYamlFilesTestData : YamlFilesTestData
{
public InsightsYamlFilesTestData() : base(new InsightsYamlFilesLoader())
{
}
}
}

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

@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Kqlvalidations.Tests
{
public abstract class YamlFilesLoader
{
protected const int TestFolderDepth = 6;
protected abstract List<string> GetDirectoryPaths();
public List<string> GetFilesNames()
{
var directoryPaths = GetDirectoryPaths();
return directoryPaths.Aggregate(new List<string>(), (accumulator, directoryPath) =>
{
var files = Directory.GetFiles(directoryPath, "*.yaml", SearchOption.AllDirectories).ToList();
return accumulator.Concat(files).ToList();
});
}
}
}

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

@ -0,0 +1,17 @@
using System.IO;
namespace Kqlvalidations.Tests
{
public class YamlFilesTestData : TheoryData<string, string>
{
public YamlFilesTestData(YamlFilesLoader yamlFilesLoader)
{
var files = yamlFilesLoader.GetFilesNames();
files.ForEach(filePath =>
{
var fileName = Path.GetFileName(filePath);
Add(fileName, Utils.EncodeToBase64(filePath));
});
}
}
}

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

@ -76,6 +76,14 @@ describe("dataConnectorValidator", () => {
await checkInvalid(".script/tests/dataConnectorValidatorTest/testFiles/Agari/invalidAzureFunctionConnectorPermissions.json","DataConnectorValidationError");
});
it("should pass when validSyslogDataConnector.json is valid", async () => {
await checkValid(".script/tests/dataConnectorValidatorTest/testFiles/validAzureDiagnosticsDataConnector.json");
});
it("should throw an exception when Syslog data connector have Invalid set of permissions", async () => {
await checkInvalid(".script/tests/dataConnectorValidatorTest/testFiles/invalidAzureDiagnosticsDataConnector.json","DataConnectorValidationError");
});
async function checkValid(filePath: string): Promise<Chai.PromisedAssertion> {
let result = await IsValidDataConnectorSchema(filePath);
expect(result).to.equal(ExitCode.SUCCESS);

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

@ -0,0 +1,58 @@
{
"id": "MicrosoftAzurePurview",
"title": "Azure Purview",
"publisher": "Microsoft",
"descriptionMarkdown": "Connect to Azure Purview to enable data sensitivity enrichment of Microsoft Sentinel. Data classification and sensitivity label logs from Azure Purview scans can be ingested and visualized through workbooks, analytical rules, and more.",
"graphQueries": [
{
"metricName": "Total data received",
"legend": "PurviewDataSensitivityLogs",
"baseQuery": "PurviewDataSensitivityLogs"
}
],
"sampleQueries": [
{
"description": "View files that contain a specific classification (example shows Social Security Number)",
"query": "PurviewDataSensitivityLogs\n | where Classification has \"Social Security Number\""
}
],
"dataTypes": [
{
"name": "AzureDiagnostics (PurviewDataSensitivityLogs)",
"lastDataReceivedQuery": "PurviewDataSensitivityLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
}
],
"connectivityCriterias": [
{
"type": "IsConnectedQuery",
"value": [
"PurviewDataSensitivityLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)"
]
}
],
"availability": {
"status": 1,
"isPreview": true
},
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "Azure Purview account Owner or Contributor role to set up Diagnostic Settings. Microsoft Contributor role with write permissions to enable data connector, view workbook, and create analytic rules.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"write": true,
"read": true
}
}
]
},
"instructionSteps": [
{
"title": "Connect Azure Purview to Azure Sentinel",
"description": "Within the Azure Portal, navigate to your Purview resource:\n 1. In the search bar, search for **Purview accounts.**\n 2. Select the specific account that you would like to be set up with Sentinel.\n\nInside your Azure Purview resource:\n 3. Select **Diagnostic Settings.**\n 4. Select **+ Add diagnostic setting.**\n 5. In the **Diagnostic setting** blade:\n - Select the Log Category as **DataSensitivityLogEvent**.\n - Select **Send to Log Analytics**.\n - Chose the log destination workspace. This should be the same workspace that is used by **Azure Sentinel.**\n - Click **Save**.",
"instructions": []
}
]
}

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

@ -0,0 +1,59 @@
{
"id": "MicrosoftAzurePurview",
"title": "Azure Purview",
"publisher": "Microsoft",
"descriptionMarkdown": "Connect to Azure Purview to enable data sensitivity enrichment of Microsoft Sentinel. Data classification and sensitivity label logs from Azure Purview scans can be ingested and visualized through workbooks, analytical rules, and more.",
"graphQueries": [
{
"metricName": "Total data received",
"legend": "PurviewDataSensitivityLogs",
"baseQuery": "PurviewDataSensitivityLogs"
}
],
"sampleQueries": [
{
"description": "View files that contain a specific classification (example shows Social Security Number)",
"query": "PurviewDataSensitivityLogs\n | where Classification has \"Social Security Number\""
}
],
"dataTypes": [
{
"name": "AzureDiagnostics (PurviewDataSensitivityLogs)",
"lastDataReceivedQuery": "PurviewDataSensitivityLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
}
],
"connectivityCriterias": [
{
"type": "IsConnectedQuery",
"value": [
"PurviewDataSensitivityLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)"
]
}
],
"availability": {
"status": 1,
"isPreview": true
},
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "Azure Purview account Owner or Contributor role to set up Diagnostic Settings. Microsoft Contributor role with write permissions to enable data connector, view workbook, and create analytic rules.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"write": true,
"read": true,
"delete": true
}
}
]
},
"instructionSteps": [
{
"title": "Connect Azure Purview to Azure Sentinel",
"description": "Within the Azure Portal, navigate to your Purview resource:\n 1. In the search bar, search for **Purview accounts.**\n 2. Select the specific account that you would like to be set up with Sentinel.\n\nInside your Azure Purview resource:\n 3. Select **Diagnostic Settings.**\n 4. Select **+ Add diagnostic setting.**\n 5. In the **Diagnostic setting** blade:\n - Select the Log Category as **DataSensitivityLogEvent**.\n - Select **Send to Log Analytics**.\n - Chose the log destination workspace. This should be the same workspace that is used by **Azure Sentinel.**\n - Click **Save**.",
"instructions": []
}
]
}

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

@ -14,6 +14,10 @@
Exfiltration,
CommandAndControl,
Impact,
Reconnaissance,
ResourceDevelopment,
ImpairProcessControl,
InhibitResponseFunction,
PreAttack
}
}

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

@ -33,12 +33,14 @@
"CEF",
"CheckPoint",
"CiscoASA",
"CiscoDuoSecurity",
"CiscoFirepowerEStreamer",
"CiscoISE",
"CiscoMeraki",
"CiscoSecureEndpoint",
"CiscoUCS",
"CiscoUmbrellaDataConnector",
"CiscoWSA",
"Citrix",
"CitrixWAF",
"CloudflareDataConnector",
@ -51,6 +53,7 @@
"DDOS",
"DNS",
"Darktrace",
"DigitalGuardianDLP",
"Dynamics365",
"ESETEnterpriseInspector",
"ESETPROTECT",
@ -64,6 +67,7 @@
"ForgeRock",
"Fortinet",
"GWorkspaceRAPI",
"ImpervaWAFCloudAPI",
"ImpervaWAFGateway",
"ImportedConnector",
"InfobloxCloudDataConnector",
@ -102,6 +106,7 @@
"SecurityEvents",
"SemperisDSP",
"SenservaPro",
"SentinelOne",
"SlackAuditAPI",
"SonicWallFirewall",
"SonraiDataConnector",
@ -118,6 +123,7 @@
"ThreatIntelligenceTaxii",
"ThycoticSecretServer_CEF",
"TrendMicro",
"TrendMicroCAS",
"TrendMicroTippingPoint",
"TrendMicroXDR",
"UbiquitiUnifi",

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

@ -194,4 +194,5 @@ export enum ConnectorCategory {
Event="Event",
RestAPI="REST_API",
AzureFunction="Azure_Function",
AzureDiagnostics="AzureDiagnostics"
}

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

@ -6,7 +6,7 @@ export function isValidDataType(dataTypes: Array<DataType>): boolean {
let name = dataType.name;
if(name.indexOf(' ') >= 0)
{
if ((name.includes("CommonSecurityLog") || name.includes("Syslog") || name.includes("Event")))
if ((name.includes("CommonSecurityLog") || name.includes("Syslog") || name.includes("Event") || name.includes("AzureDiagnostics")))
{
return true;
}

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

@ -0,0 +1,201 @@
{
"type": "object",
"required": [
"id",
"title",
"publisher",
"graphQueries",
"sampleQueries",
"dataTypes",
"connectivityCriterias",
"availability",
"permissions",
"instructionSteps"
],
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
},
"publisher": {
"type": "string"
},
"descriptionMarkdown": {
"type": "string"
},
"graphQueries": {
"type": "array",
"items": {
"type": "object",
"required": [
"metricName",
"legend",
"baseQuery"
],
"properties": {
"metricName": {
"type": "string"
},
"legend": {
"type": "string"
},
"baseQuery": {
"type": "string"
}
}
}
},
"sampleQueries": {
"type": "array",
"items": {
"type": "object",
"required": [
"description",
"query"
],
"properties": {
"description": {
"type": "string"
},
"query": {
"type": "string"
}
}
}
},
"dataTypes": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"lastDataReceivedQuery"
],
"properties": {
"name": {
"type": "string"
},
"lastDataReceivedQuery": {
"type": "string"
}
}
}
},
"connectivityCriterias": {
"type": "array",
"items": {
"type": "object",
"required": [
"type",
"value"
],
"properties": {
"type": {
"type": "string"
},
"value": {
"type": "array",
"default": [
],
"items": {
"type": "string"
}
}
}
}
},
"availability": {
"type": "object",
"required": [
"status",
"isPreview"
],
"properties": {
"status": {
"type": "integer"
},
"isPreview": {
"type": "boolean"
}
}
},
"permissions": {
"type": "object",
"required": [
"resourceProvider"
],
"properties": {
"resourceProvider": {
"type": "array",
"items": {
"type": "object",
"required": [
"provider",
"permissionsDisplayText",
"providerDisplayName",
"scope",
"requiredPermissions"
],
"properties": {
"provider": {
"type": "string"
},
"permissionsDisplayText": {
"type": "string"
},
"providerDisplayName": {
"type": "string"
},
"scope": {
"type": "string"
},
"requiredPermissions": {
"type": "object",
"required": [
"write",
"read",
"delete"
],
"properties": {
"write": {
"type": "boolean"
},
"read": {
"type": "boolean"
},
"delete": {
"type": "boolean"
}
}
}
}
}
}
}
},
"instructionSteps": {
"type": "array",
"items": {
"type": "object",
"required": [
"title",
"description",
"instructions"
],
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"instructions": {
"type": "array"
}
}
}
}
}
}

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

@ -7,7 +7,7 @@
# This is copied from here: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
/Playbooks/ @dicolanl @Yaniv-Shasha @sarah-yo @sreedharande
/Playbooks/ @dicolanl @Yaniv-Shasha @sarah-yo @sreedharande @lior-tamir
/Workbooks/ @Liatlishams
/Solutions/HoneyTokens @haneuvir
/Solutions/SAP @udidekel @tamirkopitz

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

@ -1,4 +0,0 @@
.git*
.vscode
local.settings.json
test

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

@ -1,6 +0,0 @@
# Azure Functions artifacts
bin
obj
appsettings.json
local.settings.json

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

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

@ -4,7 +4,7 @@
"name": "Timer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */5 * * * *"
"schedule": "%Schedule%"
}
]
}

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

@ -1,11 +0,0 @@
# TimerTrigger - PowerShell
The `TimerTrigger` makes it incredibly easy to have your functions executed on a schedule. This sample demonstrates a simple use case of calling your function every 5 minutes.
## How it works
For a `TimerTrigger` to work, you provide a schedule in the form of a [cron expression](https://en.wikipedia.org/wiki/Cron#CRON_expression)(See the link for full details). A cron expression is a string with 6 separate expressions which represent a given schedule via patterns. The pattern we use to represent every 5 minutes is `0 */5 * * * *`. This, in plain text, means: "When seconds is equal to 0, minutes is divisible by 5, for any hour, day of the month, month, day of the week, or year".
## Learn more
<TODO> Documentation

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

@ -3,13 +3,15 @@
Language: PowerShell
Version: 1.0
Author: Nicholas DiCola
Last Modified: 05/12/2021
Modified By: Sreedhar Ande
Last Modified: 12/16/2021
DESCRIPTION
This Function App calls the MCAS Activity REST API (https://docs.microsoft.com/cloud-app-security/api-activities) to pull the MCAS
Activity logs. The response from the MCAS API is recieved in JSON format. This function will build the signature and authorization header
needed to post the data to the Log Analytics workspace via the HTTP Data Connector API. The Function App will post the data to MCASActivity_CL.
#>
# Input bindings are passed in via param block.
param($Timer)
@ -29,8 +31,6 @@ if ($env:MSI_SECRET -and (Get-Module -ListAvailable Az.Accounts)){
Connect-AzAccount -Identity
}
#Wait-Debugger
$AzureWebJobsStorage = $env:AzureWebJobsStorage
$MCASAPIToken = $env:MCASAPIToken
$workspaceId = $env:WorkspaceId
@ -38,8 +38,8 @@ $workspaceKey = $env:WorkspaceKey
$Lookback = $env:Lookback
$MCASURL = $env:MCASURL
$LAURI = $env:LAURI
$storageAccountContainer = "mcasactivity-logs"
$fileName = "lastrun-MCAS.json"
$TblLastRunExecutions = "MCASLastRunLogs"
$StartTime = (get-date).ToUniversalTime()
$currentStartTime = $StartTime | get-date -Format yyyy-MM-ddTHH:mm:ss:ffffffZ
@ -202,33 +202,28 @@ $headers = @{
}
$EndEpoch = ([int64]((Get-Date -Date $StartTime) - (get-date "1/1/1970")).TotalMilliseconds)
#check for last run file
# Retrieve Timestamp from last executions
# Check if Table has already been created and if not create it to maintain state between executions of Function
$storageAccountContext = New-AzStorageContext -ConnectionString $AzureWebJobsStorage
$checkBlob = Get-AzStorageBlob -Blob $fileName -Container $storageAccountContainer -Context $storageAccountContext
if($checkBlob -ne $null){
#Blob found get data
Get-AzStorageBlobContent -Blob $fileName -Container $storageAccountContainer -Context $storageAccountContext -Destination "$env:temp\$fileName" -Force
$lastRunContext = Get-Content "$env:temp\$fileName" | ConvertFrom-Json
$StartEpoch = $lastRunContext.lastRunEpoch
$lastRunContext.lastRunEpoch = $EndEpoch
$lastRunContext | ConvertTo-Json | out-file "$env:temp\$fileName"
$LastExecutionsTable = Get-AzStorageTable -Name $TblLastRunExecutions -Context $storageAccountContext -ErrorAction Ignore
if($null -eq $LastExecutionsTable.Name) {
New-AzStorageTable -Name $TblLastRunExecutions -Context $storageAccountContext
$LastRunExecutionsTable = (Get-AzStorageTable -Name $TblLastRunExecutions -Context $storageAccountContext.Context).cloudTable
Add-AzTableRow -table $LastRunExecutionsTable -PartitionKey "MCASExecutions" -RowKey $workspaceId -property @{"lastRun"="$CurrentStartTime";"lastRunEpoch"="$EndEpoch"} -UpdateExisting
}
Else {
$LastRunExecutionsTable = (Get-AzStorageTable -Name $TblLastRunExecutions -Context $storageAccountContext.Context).cloudTable
}
# retrieve the row
$LastRunExecutionsTableRow = Get-AzTableRow -table $LastRunExecutionsTable -partitionKey "MCASExecutions" -RowKey $workspaceId -ErrorAction Ignore
if($null -ne $LastRunExecutionsTableRow.lastRunEpoch){
$StartEpoch = $LastRunExecutionsTableRow.lastRunEpoch
}
else {
#no blob create the context
#$StartEpoch = ([int64]((Get-Date -Date $StartTime).AddMinutes(-$Lookback) - (get-date "1/1/1970")).TotalMilliseconds)
$StartEpoch = ([int64]((Get-Date -Date $StartTime).AddDays(-$Lookback) - (get-date "1/1/1970")).TotalMilliseconds)
$lastRunContent = @"
{
"lastRun": "$CurrentStartTime",
"lastRunEpoch": $EndEpoch
}
"@
$lastRunContent | Out-File "$env:temp\$fileName"
$lastRunContext = $lastRunContent | ConvertFrom-Json
}
#Build query
$body = @"
@ -246,7 +241,6 @@ $body = @"
"@
#Get the Activities
Write-Host "Starting to process Tenant: $MCASURL"
$uri = $MCASURL+"/api/v1/activities/"
@ -275,7 +269,7 @@ do {
Write-Host "Got some results: "($results.data.Count)
$totalRecords += ($results.data.Count)
Write-Host $totalRecords
#SendToLogA -Data ($results.data) -customLogName "MCASActivity"
SendToLogA -Data ($results.data) -customLogName "MCASActivity"
}
else{
Write-Host "No new logs"
@ -285,7 +279,7 @@ do {
if($loopAgain -ne $false){
# if there is more data update the query
$newBody = $body | ConvertFrom-Json
If($newBody.filters.date.lte -eq $null){
If($null -eq $newBody.filters.date.lte){
$newBody.filters.date | Add-Member -Name lte -Value ($results.nextQueryFilters.date.lte) -MemberType NoteProperty
}
else {
@ -295,10 +289,6 @@ do {
Write-Host $body
}
else {
# no more data write last run to az storage
Set-AzStorageBlobContent -Blob $fileName -Container $storageAccountContainer -Context $storageAccountContext -File "$env:temp\$fileName" -Force
Add-AzTableRow -table $LastRunExecutionsTable -PartitionKey "MCASExecutions" -RowKey $workspaceId -property @{"lastRun"="$CurrentStartTime";"lastRunEpoch"="$EndEpoch"} -UpdateExisting
}
} until ($loopAgain -eq $false)
#clear the temp folder
Remove-Item $env:temp\* -Recurse -Force -ErrorAction SilentlyContinue

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

@ -1,5 +1,6 @@
{
"version": "2.0",
"functionTimeout": "00:10:00",
"logging": {
"applicationInsights": {
"samplingSettings": {

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

@ -1,4 +0,0 @@
{
"$schema": "http://json.schemastore.org/proxies",
"proxies": {}
}

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

@ -1,3 +1,10 @@
## 1.0
- Converted MCAS Acitivyt Data connector from Logic Apps to Azure Function
- Splitting the data if it is more than 25MB
## 2.0
- Function Schedule (CRON Expression) as parameter
- Updated StorageAccountName and KeyVaultName
- Updated Path for Function Package
- Deleted the usage of Storage Account to write last run executions
- Writing Last Run executions to Azure Storage Table

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

@ -1,4 +0,0 @@
{
"lastRun": "",
"lastRunEpoch": 0
}

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

@ -50,8 +50,8 @@
},
"variables": {
"FunctionName": "[concat(toLower(parameters('FunctionName')),'-fn', uniqueString(resourceGroup().id, subscription().id))]",
"StorageAccountName": "[concat(substring(variables('FunctionName'), 0, 7), '-sa-', uniqueString(resourceGroup().id, subscription().id))]",
"KeyVaultName": "[concat(substring(variables('FunctionName'), 0, 7), '-kv-', uniqueString(resourceGroup().id, subscription().id))]",
"StorageAccountName": "[substring(concat(substring(variables('FunctionName'), 0, 7), 'sa', uniqueString(resourceGroup().id, subscription().id)), 0, 20)]",
"KeyVaultName": "[substring(concat(substring(variables('FunctionName'), 0, 7), 'kv', uniqueString(resourceGroup().id, subscription().id)), 0, 20)]",
"MCASAPIToken": "MCASAPIToken",
"LogAnalyticsWorkspaceKey": "LogAnalyticsWorkspaceKey",
"StorageContainerName": "mcasactivity-logs",
@ -207,7 +207,7 @@
"Lookback": "[parameters('Lookback')]",
"MCASURL": "[parameters('MCASURL')]",
"LAURI": "[variables('LogAnaltyicsUri')]",
"WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/mcasactivityazurefunctionzip"
"WEBSITE_RUN_FROM_PACKAGE": "https://github.com/Azure/Azure-Sentinel/blob/master/DataConnectors/MCASActivityFunction/AzureFunctionMCASActivity/MCASActivityTimerTrigger.zip?raw=true"
}
}
]

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

@ -32,9 +32,7 @@ A MCAS API Token is required. See the documentation to learn more about the [API
```
## Post Deployment Steps
1. There is a json file (lastrun-MCAS.json) in Function Dependencies folder
2. Upload the file to the storage account "mcasactivity-logs" container from
4. API Token and Workspace Key will be placed as "Secrets" in the Azure KeyVault `<<Function App Name>><<uniqueid>>` with only Azure Function access policy. If you want to see/update these secrets,
1. API Token and Workspace Key will be placed as "Secrets" in the Azure KeyVault `<<Function App Name>><<uniqueid>>` with only Azure Function access policy. If you want to see/update these secrets,
```
a. Go to Azure KeyVault `<<Function App Name>><<uniqueid>>`
@ -48,7 +46,7 @@ A MCAS API Token is required. See the documentation to learn more about the [API
```
6. The `TimerTrigger` makes it incredibly easy to have your functions executed on a schedule. This sample demonstrates a simple use case of calling your function based on your schedule provided while deploying. If you want to change
2. The `TimerTrigger` makes it incredibly easy to have your functions executed on a schedule. This sample demonstrates a simple use case of calling your function based on your schedule provided while deploying. If you want to change
the schedule
```
a. Click on Function App "Configuration" under Settings
@ -57,7 +55,7 @@ A MCAS API Token is required. See the documentation to learn more about the [API
```
**Note: For a `TimerTrigger` to work, you provide a schedule in the form of a [cron expression](https://en.wikipedia.org/wiki/Cron#CRON_expression)(See the link for full details). A cron expression is a string with 6 separate expressions which represent a given schedule via patterns. The pattern we use to represent every 5 minutes is `0 */5 * * * *`. This, in plain text, means: "When seconds is equal to 0, minutes is divisible by 5, for any hour, day of the month, month, day of the week, or year".**
7. If you change the TimerTigger you need to configure the Lookback setting to match the number of minutes between runs. If you want to change
3. If you change the TimerTigger you need to configure the Lookback setting to match the number of minutes between runs. If you want to change
the Lookback
```
a. Click on Function App "Configuration" under Settings

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

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

@ -129,6 +129,41 @@ function Netskope () {
Do {
$response = GetLogs -Uri $uri -ApiKey $apikey -StartTime $startTime -EndTime $endTime -LogType $logtype -Page $pageLimit -Skip $skip
$netskopeevents = $response.data
$netskopeevents | Add-Member -MemberType NoteProperty dlp_incidentid -Value ""
$netskopeevents | Add-Member -MemberType NoteProperty dlp_parentid -Value ""
$netskopeevents | Add-Member -MemberType NoteProperty connectionid -Value ""
$netskopeevents | Add-Member -MemberType NoteProperty app_sessionid -Value ""
$netskopeevents | Add-Member -MemberType NoteProperty transactionid -Value ""
$netskopeevents | Add-Member -MemberType NoteProperty browser_sessionid -Value ""
$netskopeevents | Add-Member -MemberType NoteProperty requestid -Value ""
if($null -ne $netskopeevents)
{
$netskopeevents | ForEach-Object{
if($_.dlp_incident_id -ne $NULL){
$_.dlp_incidentid = [string]$_.dlp_incident_id
}
if($_.dlp_parent_id -ne $NULL){
$_.dlp_parentid = [string]$_.dlp_parent_id
}
if($_.connection_id -ne $NULL){
$_.connectionid = [string]$_.connection_id
}
if($_.app_session_id -ne $NULL){
$_.app_sessionid = [string]$_.app_session_id
}
if($_.transaction_id -ne $NULL){
$_.transactionid = [string]$_.transaction_id
}
if($_.browser_session_id -ne $NULL){
$_.browser_sessionid = [string]$_.browser_session_id
}
if($_.request_id -ne $NULL){
$_.requestid = [string]$_.request_id
}
}
}
$dataLength = $response.data.Length
$alleventobjs += $netskopeevents

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

@ -2,7 +2,7 @@
To make it easy to build and validate data connectors user experience, we have data connector json templates available for partners to use, validate and submit. This guide provides information on how to fill out the json templates.
The underlying json structure of any of the data connector template is the same, hence this connector template guidance is generalized for CEF, REST or Syslog data connector types in Azure Sentinel. There will be specific recommendations provided for different types as needed.
The underlying json structure of any of the data connector template is the same, hence this connector template guidance is generalized for CEF, REST or Syslog data connector types in Microsoft Sentinel. There will be specific recommendations provided for different types as needed.
# How to use the json template?
@ -13,7 +13,7 @@ Download the json template based on the data connector type and rename it to as
The following nomenclatures appear in the json templates. Note these accordingly to represent your data connector and fill these values accordingly in the template.
1. **PROVIDER NAME** – The name of the vendor who is building the data connector. For e.g. Microsoft, Symantec, Barracuda, etc.
2. **APPLIANCE NAME** – The name of the specific product whose logs or data is being sent to Azure Sentinel via this data connector. For e.g. CloudGen Firewall (from Barracuda), Security Analytics (from Citrix), etc.
2. **APPLIANCE NAME** – The name of the specific product whose logs or data is being sent to Microsoft Sentinel via this data connector. For e.g. CloudGen Firewall (from Barracuda), Security Analytics (from Citrix), etc.
3. **DATATYPE\_NAME** – The name of the default table where the data / logs will be sent to. The location changes for each type of data connector. While naming these:
1. Do **not** have spaces in the data type names.
2. Represent both provider, appliance name and type of data [optionally] as a short name in the data type name. The goal is to be able to disambiguate different data types if there&#39;s going to be separate data types for different appliances from the same provider for different log types (like alerts, events, raw logs, network logs, etc.)
@ -89,7 +89,7 @@ A data connector can have multiple data types and these can be represented by co
3. **permissions** – Represents the required permissions needed for the data connector to be enabled or connected. For e.g. write permissions to the workspace is needed for connector to be enabled, etc. These appear in the connector UX in the prerequisites section. This property value need **not** be updated and can remain as-is.
4. **instructionSteps** – These are the specific instructions to connect to the data connector.
* For CEF and Syslog, leverage the existing text as-is and add anything custom as needed.
* For REST API, either provide a link to your website/documentation that outlines the onboarding guidance to send data to Azure Sentinel **or** provide detailed guidance for customers to send data to Azure Sentinel.
* For REST API, either provide a link to your website/documentation that outlines the onboarding guidance to send data to Microsoft Sentinel **or** provide detailed guidance for customers to send data to Microsoft Sentinel.
* If Connector is dependent on Kusto Function (Parser), **additionalRequirementBanner** and **instruction step** about Parser need to be added in Connector. <p>
# What is the format for redirection/Short links?
@ -100,3 +100,13 @@ A data connector can have multiple data types and these can be represented by co
Expand and add multiple instructions as needed by adding more title and description elements in this block.
## Next steps
Currently in preview, you can also publish your data connector as a Microsoft Sentinel solution.
Microsoft Sentinel solutions provide an in-product experience for central discoverability, single-step deployment, and enablement of end-to-end product and/or domain and/or vertical scenarios in Microsoft Sentinel. For example, use solutions to deliver your data connector packaged with related analytics rules, workbooks, playbooks, and more.
**Tip**: If your solution is being published to the content hub, also open a PR to have it listed in our [content hub catalog](https://docs.microsoft.com/azure/sentinel/sentinel-solutions-catalog). On the docs page, click Edit to open your PR.
For more information, see the [Microsoft Sentinel solution overview](https://docs.microsoft.com/azure/sentinel/sentinel-solutions) and our [Guide to Building Microsoft Sentinel Solutions](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions#readme).

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

@ -1,21 +1,29 @@
# Connect your <<Partner Appliance Name>> to Azure Sentinel
# Connect your <<Partner Appliance Name>> to Microsoft Sentinel
This article explains how to connect your <<Partner Appliance Name>> appliance to Azure Sentinel. The <<Partner Appliance Name>> data connector allows you to easily connect your <<Partner Appliance Name>> logs with Azure Sentinel, to view dashboards, create custom alerts, and improve investigation. <<Add additional specific insights this data connectivity provides to customers>>
This article explains how to connect your <<Partner Appliance Name>> appliance to Microsoft Sentinel. The <<Partner Appliance Name>> data connector allows you to easily connect your <<Partner Appliance Name>> logs with Microsoft Sentinel, to view dashboards, create custom alerts, and improve investigation. <<Add additional specific insights this data connectivity provides to customers>>
> [!NOTE]
> Data will be stored in the geographic location of the workspace on which you are running Azure Sentinel.
**Note**: Data will be stored in the geographic location of the workspace on which you are running Microsoft Sentinel.
## Forward <<Partner Appliance Name>> logs to the Syslog agent
Configure <<Partner Appliance Name>> to forward Syslog messages in CEF format to your Azure workspace via the Syslog agent.
1. <Add specific steps on how customers can configure your appliance to send logs to Syslog - refer to 'https://docs.microsoft.com/azure/sentinel/connect-paloalto' as an example for this section. Adjust numbering below as needed for the last two steps that follows.>
1. <Add specific steps on how customers can configure your appliance to send logs to Syslog. For more information, see our generic [CEF data connector documentation](https://docs.microsoft.com/azure/sentinel/connect-common-event-format). Adjust numbering below as needed for the last two steps that follows.>
2. To use the relevant schema in Log Analytics for the <<Partner Appliance Name>>, search for CommonSecurityLog.
3. Continue to [STEP 3: Validate connectivity](connect-cef-verify.md).
3. Continue with [validating your CEF connectivity](https://docs.microsoft.com/azure/sentinel/troubleshooting-cef-syslog?tabs=rsyslog#validate-cef-connectivity).
## Next steps
In this document, you learned how to connect <<Partner Appliance Name>> to Azure Sentinel. To learn more about Azure Sentinel, see the following articles:
- Learn how to [get visibility into your data, and potential threats](quickstart-get-visibility.md).
- Get started [detecting threats with Azure Sentinel](tutorial-detect-threats-built-in.md).
- [Use workbooks](tutorial-monitor-your-data.md) to monitor your data.
In this document, you learned how to connect <<Partner Appliance Name>> to Microsoft Sentinel. To learn more about Microsoft Sentinel, see the following articles:
- Learn how to [get visibility into your data, and potential threats](https://docs.microsoft.com/azure/sentinel/get-visibility).
- Get started [detecting threats with Microsoft Sentinel](https://docs.microsoft.com/azure/sentinel/detect-threats-built-in).
- [Use workbooks](https://docs.microsoft.com/azure/sentinel/monitor-your-data) to monitor your data.
<### Install as a solution (Preview)
Include this section if you are planning on publishing your data connector as a Microsoft Sentinel solution. Microsoft Sentinel solutions provide an in-product experience for central discoverability, single-step deployment, and enablement of end-to-end product and/or domain and/or vertical scenarios in Microsoft Sentinel. For example, use solutions to deliver your data connector packaged with related analytics rules, workbooks, playbooks, and more.
- When relevant, add instructions for installing your solution, either from the Azure Marketplace, or from the Microsoft Sentinel content hub.
- If your solution is being published to the content hub, also open a PR to have it listed in our [content hub catalog](https://docs.microsoft.com/azure/sentinel/sentinel-solutions-catalog). On the docs page, click Edit to open your PR.
For more information, see the [Microsoft Sentinel solution overview](https://docs.microsoft.com/azure/sentinel/sentinel-solutions) and our [Guide to Building Microsoft Sentinel Solutions](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions#readme).>

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

@ -1,24 +1,19 @@
# Connect your <<Partner Appliance Name>> to Azure Sentinel
# Connect your <<Partner Appliance Name>> to Microsoft Sentinel
<<Partner Appliance Name>> connector allows you to easily connect all your <<Partner Appliance Name>> security solution logs with your Azure Sentinel, to view dashboards, create custom alerts, and improve investigation. <<Add additional specific insights this data connectivity provides to customers>>. Integration between <<Partner Appliance Name>> and Azure Sentinel makes use of REST API.
<<Partner Appliance Name>> connector allows you to easily connect all your <<Partner Appliance Name>> security solution logs with your Microsoft Sentinel, to view dashboards, create custom alerts, and improve investigation. <<Add additional specific insights this data connectivity provides to customers>>. Integration between <<Partner Appliance Name>> and Microsoft Sentinel makes use of REST API.
> [!NOTE]
> Data will be stored in the geographic location of the workspace on which you are running Azure Sentinel.
> Data will be stored in the geographic location of the workspace on which you are running Microsoft Sentinel.
## Configure and connect <<Partner Appliance Name>>
<<Partner Appliance Name>> can integrate and export logs directly to Azure Sentinel.
1. In the Azure Sentinel portal, click Data connectors and select <<Partner Appliance Name>> and then Open connector page.
2. <If you have documentation to connect on your side link to that - refer to 'https://docs.microsoft.com/azure/sentinel/connect-f5-big-ip' as an example for this section>
ELSE
2. <Provide detailed steps to discover the connection in your product with screenshots - refer to 'https://docs.microsoft.com/azure/sentinel/connect-symantec' as an example for this section>
<<Partner Appliance Name>> can integrate and export logs directly to Microsoft Sentinel.
1. In the Microsoft Sentinel portal, click Data connectors and select <<Partner Appliance Name>> and then Open connector page.
2. <If you have documentation to connect on your side link to that. If you don't, provide detailed steps to discover the connection in your product. For more information, see our [generic REST API-based data connector documentation](https://docs.microsoft.com/azure/sentinel/connect-rest-api-template).>
## Find your data
@ -30,8 +25,17 @@ It may take up to 20 minutes until your logs start to appear in Log Analytics.
## Next steps
In this document, you learned how to connect <<Partner Appliance Name>> to Azure Sentinel. To learn more about Azure Sentinel, see the following articles:
- Learn how to [get visibility into your data, and potential threats](quickstart-get-visibility.md).
- Get started [detecting threats with Azure Sentinel](tutorial-detect-threats-built-in.md).
- [Use workbooks](tutorial-monitor-your-data.md) to monitor your data.
In this document, you learned how to connect <<Partner Appliance Name>> to Microsoft Sentinel. To learn more about Microsoft Sentinel, see the following articles:
- Learn how to [get visibility into your data, and potential threats](https://docs.microsoft.com/azure/sentinel/get-visibility).
- Get started [detecting threats with Microsoft Sentinel](https://docs.microsoft.com/azure/sentinel/detect-threats-built-in).
- [Use workbooks](https://docs.microsoft.com/azure/sentinel/monitor-your-data) to monitor your data.
<### Install as a solution (Preview)
Include this section if you are planning on publishing your data connector as a Microsoft Sentinel solution. Microsoft Sentinel solutions provide an in-product experience for central discoverability, single-step deployment, and enablement of end-to-end product and/or domain and/or vertical scenarios in Microsoft Sentinel. For example, use solutions to deliver your data connector packaged with related analytics rules, workbooks, playbooks, and more.
- When relevant, add instructions for installing your solution, either from the Azure Marketplace, or from the Microsoft Sentinel content hub.
- If your solution is being published to the content hub, also open a PR to have it listed in our [content hub catalog](https://docs.microsoft.com/azure/sentinel/sentinel-solutions-catalog). On the docs page, click Edit to open your PR.
For more information, see the [Microsoft Sentinel solution overview](https://docs.microsoft.com/azure/sentinel/sentinel-solutions) and our [Guide to Building Microsoft Sentinel Solutions](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions#readme).>

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

@ -0,0 +1,75 @@
id: fcb9d75c-c3c1-4910-8697-f136bfef2363
name: Potential beaconing activity (ASIM Network Session schema)
description: |
This rule identifies beaconing patterns from Network traffic logs based on recurrent frequency patterns. Such potential outbound beaconing pattern to untrusted public networks should be investigated for any malware callbacks or data exfiltration attempts as discussed in this [Blog](http://www.austintaylor.io/detect/beaconing/intrusion/detection/system/command/control/flare/elastic/stack/2017/06/10/detect-beaconing-with-flare-elasticsearch-and-intrusion-detection-systems/).\<br><br>This rule uses the [Advanced SIEM Information Model (ASIM)](https://aka.ms/AboutASIM) and supports any network session source that compiles with ASIM. To use this Analytics Rule, [deploy the Advanced SIEM information Model (ASIM)](https://aka.ms/DeployASIM).''
severity: Low
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1071
- T1571
tags:
- ParentAlert: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/CommonSecurityLog/PaloAlto-NetworkBeaconing.yaml
ParentVersion: 1.0.0
- Schema: ASIMNetworkSession
SchemaVersion: 0.2.1
query: |
let querystarttime = 2d;
let queryendtime = 1d;
let TimeDeltaThreshold = 10;
let TotalEventsThreshold = 15;
let PercentBeaconThreshold = 80;
imNetworkSession(starttime=querystarttime, endtime=queryendtime)
| where not(ipv4_is_private(DstIpAddr))
| project TimeGenerated, SrcIpAddr, SrcPortNumber, DstIpAddr, DstPortNumber, DstBytes, SrcBytes
| sort by SrcIpAddr asc,TimeGenerated asc, DstIpAddr asc, DstPortNumber asc
| serialize
| extend nextTimeGenerated = next(TimeGenerated, 1), nextSrcIpAddr = next(SrcIpAddr, 1)
| extend TimeDeltainSeconds = datetime_diff('second',nextTimeGenerated,TimeGenerated)
| where SrcIpAddr == nextSrcIpAddr
//Whitelisting criteria/ threshold criteria
| where TimeDeltainSeconds > TimeDeltaThreshold
| project TimeGenerated, TimeDeltainSeconds, SrcIpAddr, SrcPortNumber, DstIpAddr, DstPortNumber, DstBytes, SrcBytes
| summarize count(), sum(DstBytes), sum(SrcBytes), make_list(TimeDeltainSeconds)
by TimeDeltainSeconds, bin(TimeGenerated, 1h), SrcIpAddr, DstIpAddr, DstPortNumber
| summarize (MostFrequentTimeDeltaCount, MostFrequentTimeDeltainSeconds) = arg_max(count_, TimeDeltainSeconds), TotalEvents=sum(count_), TotalSrcBytes = sum(sum_SrcBytes), TotalDstBytes = sum(sum_DstBytes)
by bin(TimeGenerated, 1h), SrcIpAddr, DstIpAddr, DstPortNumber
| where TotalEvents > TotalEventsThreshold
| extend BeaconPercent = MostFrequentTimeDeltaCount/toreal(TotalEvents) * 100
| where BeaconPercent > PercentBeaconThreshold
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
- entityType: IP
fieldMappings:
- identifier: Address
columnName: DstIpAddr
alertDetailsOverride:
alertDisplayNameFormat: Potential beaconing from {{SrcIpAddr}} to {{DstIpAddr}} over port {{DstPortNumber}}
alertDescriptionFormat: Potential beaconing pattern from a client at address {{SrcIpAddr}} to a server at address {{DstIpAddr}} over port {{DstPortNumber}} identified. The recurring frequency is {{MostFrequentTimeDeltaCount}} and the total transferred volume is {{TotalSrcBytes}} bytes. Such potential outbound beaconing pattern to untrusted public networks should be investigated for any malware callbacks or data exfiltration attempts as discussed in this [Blog](http://www.austintaylor.io/detect/beaconing/intrusion/detection/system/command/control/flare/elastic/stack/2017/06/10/detect-beaconing-with-flare-elasticsearch-and-intrusion-detection-systems/)
customDetails:
DstPortNumber: DstPortNumber
FrequenceCount: TotalSrcBytes
FrequencyTime: MostFrequentTimeDeltaCount
TotalDstBytes: TotalDstBytes
version: 1.0.0
kind: Scheduled

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

@ -0,0 +1,107 @@
id: 9176b18f-a946-42c6-a2f6-0f6d17cd6a8a
name: Potential communication with a Domain Generation Algorithm (DGA) based hostname (ASIM Network Session schema)
description: |
'This rule identifies communication with hosts that have a domain name that might have been generated by a Domain Generation Algorithm (DGA). DGAs are used by malware to generate rendezvous points that are difficult to predict in advance. This detection uses the top 1 million domain names to build a model of what normal domains look like nad uses the model to identify domains that may have been randomly generated by an algorithm. You can modify the triThreshold and dgaLengthThreshold query parameters to change Analytic Rule sensitivity. The higher the numbers, the less noisy the rule is. <br>This rule uses the [Advanced SIEM Information Model (ASIM)](https://aka.ms/AboutASIM) and supports any network session source that compiles with ASIM. To use this Analytics Rule, [deploy the Advanced SIEM information Model (ASIM)](https://aka.ms/DeployASIM).'
severity: Medium
requiredDataConnectors: []
queryFrequency: 6h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
tags:
- ParentAlert: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/CommonSecurityLog/MultiVendor-PossibleDGAContacts.yaml
version: 1.0.0
- Schema: ASIMWebSession
SchemaVersion: 0.2.0
relevantTechniques:
- T1568
query: |
let triThreshold = 500;
let querystarttime = 6h;
let dgaLengthThreshold = 8;
// fetch the cisco umbrella top 1M domains
let top1M = (externaldata (Position:int, Domain:string) [@"http://s3-us-west-1.amazonaws.com/umbrella-static/top-1m.csv.zip"] with (format="csv", zipPattern="*.csv"));
// extract tri grams that are above our threshold - i.e. are common
let triBaseline = top1M
| extend Domain = tolower(extract("([^.]*).{0,7}$", 1, Domain))
| extend AllTriGrams = array_concat(extract_all("(...)", Domain), extract_all("(...)", substring(Domain, 1)), extract_all("(...)", substring(Domain, 2)))
| mvexpand Trigram=AllTriGrams to typeof(string)
| summarize triCount=count() by Trigram
| sort by triCount desc
| where triCount > triThreshold
| distinct Trigram;
// collect domain information from common security log, filter and extract the DGA candidate and its trigrams
let allDataSummarized = imWebSession
| where isnotempty(Url)
| extend Name = tolower(tostring(parse_url(Url)["Host"]))
| summarize NameCount=count() by Name
| where Name has "."
| where Name !endswith ".home" and Name !endswith ".lan"
// extract DGA candidate
| extend DGADomain = extract("([^.]*).{0,7}$", 1, Name)
| where strlen(DGADomain) > dgaLengthThreshold
// throw out domains with number in them
| where DGADomain matches regex "^[A-Za-z]{0,}$"
// extract the tri grams from summarized data
| extend AllTriGrams = array_concat(extract_all("(...)", DGADomain), extract_all("(...)", substring(DGADomain, 1)), extract_all("(...)", substring(DGADomain, 2)));
// throw out domains that have repeating tri's and/or >=3 repeating letters
let nonRepeatingTris = allDataSummarized
| join kind=leftanti
(
allDataSummarized
| mvexpand AllTriGrams
| summarize count() by tostring(AllTriGrams), DGADomain
| where count_ > 1
| distinct DGADomain
)
on DGADomain;
// find domains that do not have a common tri in the baseline
let dataWithRareTris = nonRepeatingTris
| join kind=leftanti
(
nonRepeatingTris
| mvexpand AllTriGrams
| extend Trigram = tostring(AllTriGrams)
| distinct Trigram, DGADomain
| join kind=inner
(
triBaseline
)
on Trigram
| distinct DGADomain
)
on DGADomain;
dataWithRareTris
// join DGAs back on connection data
| join kind=inner
(
imWebSession
| where isnotempty(Url)
| extend Url = tolower(Url)
| summarize arg_max(TimeGenerated, EventVendor, SrcIpAddr) by Url
| extend Name=tostring(parse_url(Url)["Host"])
| summarize StartTime=min(TimeGenerated), EndTime=max(TimeGenerated) by Name, SrcIpAddr, Url
)
on Name
| project StartTime, EndTime, Name, DGADomain, SrcIpAddr, Url, NameCount
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
- entityType: Url
fieldMappings:
- identifier: Url
columnName: Url
alertDetailsOverride:
alertDisplayNameFormat: Potential communication from {{SrcIpAddr} with a Domain Generation Algorithm (DGA) based host {{Name}}
alertDescriptionFormat: A client with address {{SrcIpAddr}} communicated with host {{Name}} that have a domain name that might have been generated by a Domain Generation Algorithm (DGA), identified by the pattern {{DGADomain}}. DGAs are used by malware to generate rendezvous points that are difficult to predict in advance. This detection uses the top 1 million domain names to build a model of what normal domains look like and uses the model to identify domains that may have been randomly generated by an algorithm.
customDetails:
DGAPattern: DGADomain
NameCount: NameCount
version: 1.0.0
kind: Scheduled

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

@ -22,7 +22,7 @@ query: |
with(format="csv", ignoreFirstRecord=True));
let knownUserAgents=toscalar(knownUserAgentsIndicators | where Category==threatCategory | where isnotempty(UserAgent) | summarize make_list(UserAgent));
let customUserAgents=toscalar(_GetWatchlist("UnusualUserAgents") | where SearchKey==threatCategory | extend UserAgent=column_ifexists("UserAgent","") | where isnotempty(UserAgent) | summarize make_list(UserAgent));
let fullUAList = array_concat(knownUserAgents,customUserAgents)
let fullUAList = array_concat(knownUserAgents,customUserAgents);
imWebSession(httpuseragent_has_any=fullUAList)
| project SrcIpAddr, Url, TimeGenerated,HttpUserAgent, SrcUsername
@ -50,5 +50,5 @@ customDetails:
eventGroupingSettings:
aggregationKind: AlertPerResult
version: 1.0.1
version: 1.0.2
kind: Scheduled

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

@ -22,7 +22,7 @@ query: |
with(format="csv", ignoreFirstRecord=True));
let knownUserAgents=toscalar(knownUserAgentsIndicators | where Category==threatCategory | where isnotempty(UserAgent) | summarize make_list(UserAgent));
let customUserAgents=toscalar(_GetWatchlist("UnusualUserAgents") | where SearchKey==threatCategory | extend UserAgent=column_ifexists("UserAgent","") | where isnotempty(UserAgent) | summarize make_list(UserAgent));
let fullUAList = array_concat(knownUserAgents,customUserAgents)
let fullUAList = array_concat(knownUserAgents,customUserAgents);
imWebSession(httpuseragent_has_any=fullUAList)
| project SrcIpAddr, Url, TimeGenerated,HttpUserAgent, SrcUsername
entityMappings:
@ -48,5 +48,5 @@ customDetails:
eventGroupingSettings:
aggregationKind: AlertPerResult
version: 1.0.1
version: 1.0.2
kind: Scheduled

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

@ -15,7 +15,7 @@ requiredDataConnectors:
- DeviceFileEvents
- DeviceEvents
queryFrequency: 1d
queryPeriod: 7d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
@ -79,12 +79,12 @@ query: |
| join kind=leftouter (
hashTotals
) on ScriptFingerprintHash
// Calculate prevelance, while we don't need this, it may be useful for responders to know how rare this script is in relation to normal activity
| extend Prevelance = toreal(HashCount) / toreal(totals) * 100
// Calculate prevalence, while we don't need this, it may be useful for responders to know how rare this script is in relation to normal activity
| extend Prevalence = toreal(HashCount) / toreal(totals) * 100
// Where the hash was only ever seen once.
| where HashCount == 1
| extend timestamp = StartTime, IPCustomEntity=CallerIpAddress, AccountCustomEntity=Caller, HostCustomEntity=VirtualMachineName
| project timestamp, StartTime, EndTime, PowershellFileName, VirtualMachineName, Caller, CallerIpAddress, PowershellScriptCommands, PowershellFileSize, ScriptFingerprintHash, IPCustomEntity, AccountCustomEntity, HostCustomEntity
| project timestamp, StartTime, EndTime, PowershellFileName, VirtualMachineName, Caller, CallerIpAddress, PowershellScriptCommands, PowershellFileSize, ScriptFingerprintHash, Prevalence, IPCustomEntity, AccountCustomEntity, HostCustomEntity
entityMappings:
- entityType: Account
fieldMappings:
@ -98,5 +98,5 @@ entityMappings:
fieldMappings:
- identifier: HostName
columnName: HostCustomEntity
version: 1.0.0
kind: scheduled
version: 1.0.1
kind: Scheduled

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

@ -3,7 +3,7 @@ name: Azure WAF matching for Log4j vuln(CVE-2021-44228)
description: |
'This query will alert on a positive pattern match by Azure WAF for CVE-2021-44228 log4j vulnerability exploitation attempt. If possible, it then decodes the malicious command for further analysis.
Refrence: https://www.microsoft.com/security/blog/2021/12/11/guidance-for-preventing-detecting-and-hunting-for-cve-2021-44228-log4j-2-exploitation/'
severity: Medium
severity: High
requiredDataConnectors:
- connectorId: WAF
dataTypes:
@ -36,5 +36,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.0.1
kind: Scheduled

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

@ -7,7 +7,7 @@ severity: Low
requiredDataConnectors:
- connectorId: AzureKeyVault
dataTypes:
- AzureDiagnostics
- KeyVaultData
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt

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

@ -9,7 +9,7 @@ severity: Low
requiredDataConnectors:
- connectorId: AzureKeyVault
dataTypes:
- AzureDiagnostics
- KeyVaultData
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt

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

@ -9,7 +9,7 @@ severity: Low
requiredDataConnectors:
- connectorId: AzureKeyVault
dataTypes:
- AzureDiagnostics
- KeyVaultData
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt

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

@ -12,7 +12,7 @@ queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- CommandAndControl
- Exfiltration
query: |
let lbtime = 10m;
@ -33,5 +33,6 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.1.0
kind: Scheduled

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

@ -12,7 +12,7 @@ queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- CommandAndControl
query: |
let domain_lookBack= 14d;
let timeframe = 1d;
@ -40,5 +40,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.1.0
kind: Scheduled

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

@ -12,7 +12,7 @@ queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- CommandAndControl
query: |
let timeframe = 15m;
Cisco_Umbrella
@ -31,5 +31,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.1.0
kind: Scheduled

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

@ -12,7 +12,7 @@ queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- CommandAndControl
query: |
let timeframe = 15m;
Cisco_Umbrella
@ -31,5 +31,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.1.0
kind: Scheduled

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

@ -12,7 +12,7 @@ queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- CommandAndControl
query: |
let timeframe = 15m;
let user_agents=dynamic([
@ -79,5 +79,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.1.0
kind: Scheduled

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

@ -12,7 +12,7 @@ queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- CommandAndControl
- DefenseEvasion
query: |
let timeframe = 15m;
@ -32,5 +32,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.1.0
kind: Scheduled

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

@ -12,7 +12,7 @@ queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- CommandAndControl
query: |
let lookBack = 14d;
let timeframe = 1d;
@ -37,5 +37,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.1.0
kind: Scheduled

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

@ -12,7 +12,7 @@ queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- CommandAndControl
- InitialAccess
query: |
let lbtime = 10m;
@ -50,5 +50,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.1.0
kind: Scheduled

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

@ -12,7 +12,7 @@ queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- CommandAndControl
query: |
let lbtime = 10m;
Cisco_Umbrella
@ -32,5 +32,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.1.0
kind: Scheduled

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

@ -0,0 +1,36 @@
id: b8b8ba09-1e89-45a1-8bd7-691cd23bfa32
name: Missing Domain Controller Heartbeat
description: |
'This detection will go over the heartbeats received from the agents of Domain Controllers over the last hour, and will create alerts if the last heartbeats were received an hour ago.'
severity: High
requiredDataConnectors: []
queryFrequency: 15m
queryPeriod: 2h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
- DefenseEvasion
query: |
let query_frequency = 15m;
let missing_period = 1h;
//Enter a reference list of hostnames for your DC servers
let DCServersList = dynamic (["DC01.simulandlabs.com","DC02.simulandlabs.com"]);
//Alternatively, a Watchlist can be used
//let DCServersList = _GetWatchlist('HostName-DomainControllers') | project HostName;
Heartbeat
| summarize arg_max(TimeGenerated, *) by Computer
| where Computer in (DCServersList)
//You may specify the OS type of your Domain Controllers
//| where OSType == 'Windows'
| where TimeGenerated between (ago(query_frequency + missing_period) .. ago(missing_period))
| project TimeGenerated, Computer, OSType, Version, ComputerEnvironment, Type, Solutions
| sort by TimeGenerated asc
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: Computer
version: 1.0.0
kind: Scheduled

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

@ -34,10 +34,10 @@ query: |
| where SourceIpAddress != "127.0.0.1"
| summarize count() by SourceIpAddress
| where count_ > signin_threshold
| summarize make_list(SourceIpAddress);
| summarize make_set(SourceIpAddress);
//See if any of those IPs have sucessfully logged into Azure AD.
SigninLogs
| where ResultType !in ("0", "50125", "50140")
| where ResultType in ("0", "50125", "50140")
| where IPAddress in (aws_fails)
| extend Reason = "Multiple failed AWS Console logins from IP address"
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress
@ -50,5 +50,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
version: 1.0.1
kind: Scheduled

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

@ -10,6 +10,8 @@ tags:
- CVE-2021-44228
- Schema: ASIMDns
SchemaVersion: 0.1.1
- Schema: ASIMNetworkSession
SchemaVersion: 0.2.0
requiredDataConnectors:
- connectorId: Office365
dataTypes:
@ -53,8 +55,8 @@ requiredDataConnectors:
- connectorId: AzureFirewall
dataTypes:
- AzureDiagnostics
queryFrequency: 1d
queryPeriod: 1d
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
@ -63,112 +65,130 @@ query: |
let IPList = externaldata(IPAddress:string)[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Log4j_IOC_List.csv"] with (format="csv", ignoreFirstRecord=True);
let IPRegex = '[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}';
//Network logs
let CSlogSourceIP = CommonSecurityLog | summarize by IPAddress = SourceIP, Type;
let CSlogDestIP = CommonSecurityLog | summarize by IPAddress = DestinationIP, Type;
let CSlogMsgIP = CommonSecurityLog | extend MessageIP = extract(IPRegex, 0, Message) | summarize by IPAddress = MessageIP, Type;
let DnsIP = DnsEvents | summarize by IPAddress = IPAddresses, Type;
// If you have enabled the imDNS and/or imNetworkSession normalization in your workspace, you can uncomment one or both below. Reference - https://docs.microsoft.com/azure/sentinel/normalization
//let imDnsIP = imDns (response_has_any_prefix=IPList) | summarize by IPAddress = ResponseName, Type;
//let imNetSessIP = imNetworkSession (dstipaddr_has_any_prefix=IPList) | summarize by IPAddress = DstIpAddr, Type;
//Cloud service logs
let officeIP = OfficeActivity | summarize by IPAddress = ClientIP, Type;
let signinIP = SigninLogs | summarize by IPAddress, Type;
let nonintSigninIP = AADNonInteractiveUserSignInLogs | summarize by IPAddress, Type;
let azureActIP = AzureActivity | summarize by IPAddress = CallerIpAddress, Type;
let awsCtIP = AWSCloudTrail | summarize by IPAddress = SourceIpAddress, Type;
//Device logs
let vmConnSourceIP = VMConnection | summarize by IPAddress = SourceIp, Type;
let vmConnDestIP = VMConnection | summarize by IPAddress = DestinationIp, Type;
let iisLogIP = W3CIISLog | summarize by IPAddress = cIP, Type;
let devNetIP = DeviceNetworkEvents | summarize by IPAddress = RemoteIP, Type;
//need to parse to get IP
let azureDiagIP = AzureDiagnostics | where ResourceType == "AZUREFIREWALLS" | where Category in ("AzureFirewallApplicationRule", "AzureFirewallNetworkRule")
| where msg_s has_any (IPList) | parse msg_s with Protocol 'request from ' SourceHost ':' SourcePort 'to ' DestinationHost ':' DestinationPort '. Action:' Action | summarize by IPAddress = DestinationHost, Type;
let sysEvtIP = Event | where Source == "Microsoft-Windows-Sysmon" | where EventID == 3 | where EventData has_any (IPList) | extend EvData = parse_xml(EventData)
| extend EventDetail = EvData.DataItem.EventData.Data
| extend SourceIP = tostring(EventDetail.[9].["#text"]), DestinationIP = tostring(EventDetail.[14].["#text"])
| where SourceIP in (IPList) or DestinationIP in (IPList) | extend IPAddress = iff(SourceIP in (IPList), SourceIP, DestinationIP) | summarize by IPAddress, Type;
// If you have enabled the imDNS and/or imNetworkSession normalization in your workdspace, you can uncomment below and include. Reference - https://docs.microsoft.com/azure/sentinel/normalization
//let ipsort = union isfuzzy=true CSlogDestIP, CSlogMsgIP, CSlogSourceIP, DnsIP, officeIP, signinIP, nonintSigninIP, azureActIP, awsCtIP, vmConnDestIP, vmConnSourceIP, azureDiagIP, sysEvtIP, imDnsIP, imNetSessIP
// If you uncomment above, then comment out the line below
let ipsort = union isfuzzy=true CSlogDestIP, CSlogMsgIP, CSlogSourceIP, DnsIP, officeIP, signinIP, nonintSigninIP, azureActIP, awsCtIP, vmConnDestIP, vmConnSourceIP, azureDiagIP, sysEvtIP
| summarize by IPAddress
| where isnotempty(IPAddress) | where not(ipv4_is_private(IPAddress)) and IPAddress !in ('0.0.0.0','127.0.0.1');
let ipMatch = ipsort | where IPAddress in (IPList);
(union isfuzzy=true
(CommonSecurityLog
| where SourceIP in (IPList) or DestinationIP in (IPList) or Message has_any (IPList)
| where SourceIP in (ipMatch) or DestinationIP in (ipMatch) or Message has_any (ipMatch)
| project TimeGenerated, SourceIP, DestinationIP, Message, SourceUserID, RequestURL, Type
| extend MessageIP = extract(IPRegex, 0, Message)
| extend IPMatch = case(SourceIP in (IPList), "SourceIP", DestinationIP in (IPList), "DestinationIP", MessageIP in (IPList), "Message", "No Match")
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by SourceIP, DestinationIP, DeviceProduct, DeviceAction, Message, MessageIP, Protocol, SourcePort, DestinationPort, DeviceAddress, DeviceName, IPMatch, LogType = Type
| extend timestamp = StartTime, IPCustomEntity = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, IPMatch == "Message", MessageIP, "No Match")
| extend IPMatch = case(SourceIP in (ipMatch), "SourceIP", DestinationIP in (ipMatch), "DestinationIP", MessageIP in (ipMatch), "Message", "No Match")
| extend timestamp = TimeGenerated, IPCustomEntity = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, IPMatch == "Message", MessageIP, "No Match")
),
(OfficeActivity
| where ClientIP in (ipMatch)
| project TimeGenerated, UserAgent, Operation, RecordType, UserId, ClientIP, Type
| extend SourceIPAddress = ClientIP, Account = UserId
| where SourceIPAddress in (IPList)
| extend timestamp = TimeGenerated , IPCustomEntity = SourceIPAddress , AccountCustomEntity = Account, LogType = Type
| extend timestamp = TimeGenerated , IPCustomEntity = SourceIPAddress , AccountCustomEntity = Account
),
(DnsEvents
| where IPAddresses has_any (IPList)
| where IPAddresses has_any (ipMatch)
| project TimeGenerated, Computer, IPAddresses, Name, ClientIP, Type
| extend DestinationIPAddress = IPAddresses, Host = Computer
| extend timestamp = TimeGenerated, IPCustomEntity = DestinationIPAddress, HostCustomEntity = Host, LogType = Type
),
(imDns (response_has_any_prefix=IPList)
| extend DestinationIPAddress = ResponseName, Host = SrcIpAddr
| extend timestamp = TimeGenerated, IPCustomEntity = DestinationIPAddress, HostCustomEntity = Host, LogType = Type
| extend timestamp = TimeGenerated, IPCustomEntity = DestinationIPAddress, HostCustomEntity = Host
),
(VMConnection
| where SourceIp in (IPList) or DestinationIp in (IPList)
| extend IPMatch = case( SourceIp in (IPList), "SourceIP", DestinationIp in (IPList), "DestinationIP", "None")
| extend timestamp = TimeGenerated , IPCustomEntity = case(IPMatch == "SourceIP", SourceIp, IPMatch == "DestinationIP", DestinationIp, "None"), Host = Computer, LogType = Type
| where SourceIp in (ipMatch) or DestinationIp in (ipMatch)
| project TimeGenerated, Computer, SourceIp, DestinationIp, Type
| extend IPMatch = case( SourceIp in (ipMatch), "SourceIP", DestinationIp in (ipMatch), "DestinationIP", "None")
| extend timestamp = TimeGenerated , IPCustomEntity = case(IPMatch == "SourceIP", SourceIp, IPMatch == "DestinationIP", DestinationIp, "None"), Host = Computer
),
(Event
| where Source == "Microsoft-Windows-Sysmon"
| where EventID == 3
| where EventData has_any (ipMatch)
| project TimeGenerated, EventData, UserName, Computer, Type
| extend EvData = parse_xml(EventData)
| extend EventDetail = EvData.DataItem.EventData.Data
| extend SourceIP = EventDetail.[9].["#text"], DestinationIP = EventDetail.[14].["#text"]
| where SourceIP in (IPList) or DestinationIP in (IPList)
| extend IPMatch = case( SourceIP in (IPList), "SourceIP", DestinationIP in (IPList), "DestinationIP", "None")
| extend timestamp = TimeGenerated, AccountCustomEntity = UserName, HostCustomEntity = Computer , IPCustomEntity = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, "None"), LogType = Type
),
(WireData
| where isnotempty(RemoteIP)
| where RemoteIP in (IPList)
| extend timestamp = TimeGenerated, IPCustomEntity = RemoteIP, HostCustomEntity = Computer, LogType = Type
| extend SourceIP = tostring(EventDetail.[9].["#text"]), DestinationIP = tostring(EventDetail.[14].["#text"])
| where SourceIP in (ipMatch) or DestinationIP in (ipMatch)
| extend IPMatch = case( SourceIP in (ipMatch), "SourceIP", DestinationIP in (ipMatch), "DestinationIP", "None")
| extend timestamp = TimeGenerated, AccountCustomEntity = UserName, HostCustomEntity = Computer , IPCustomEntity = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, "None")
),
(SigninLogs
| where isnotempty(IPAddress)
| where IPAddress in (IPList)
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress, LogType = Type
| where IPAddress in (ipMatch)
| project TimeGenerated, UserPrincipalName, IPAddress, Type
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress
),
(AADNonInteractiveUserSignInLogs
| where isnotempty(IPAddress)
| where IPAddress in (IPList)
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress, LogType = Type
| where IPAddress in (ipMatch)
| project TimeGenerated, UserPrincipalName, IPAddress, Type
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress
),
(W3CIISLog
| where isnotempty(cIP)
| where cIP in (IPList)
| extend timestamp = TimeGenerated, IPCustomEntity = cIP, HostCustomEntity = Computer, AccountCustomEntity = csUserName, LogType = Type
| where cIP in (ipMatch)
| project TimeGenerated, Computer, cIP, csUserName, Type
| extend timestamp = TimeGenerated, IPCustomEntity = cIP, HostCustomEntity = Computer, AccountCustomEntity = csUserName
),
(AzureActivity
| where isnotempty(CallerIpAddress)
| where CallerIpAddress in (IPList)
| extend timestamp = TimeGenerated, IPCustomEntity = CallerIpAddress, AccountCustomEntity = Caller, LogType = Type
| where CallerIpAddress in (ipMatch)
| project TimeGenerated, CallerIpAddress, Caller, Type
| extend timestamp = TimeGenerated, IPCustomEntity = CallerIpAddress, AccountCustomEntity = Caller
),
(
AWSCloudTrail
| where isnotempty(SourceIpAddress)
| where SourceIpAddress in (IPList)
| extend timestamp = TimeGenerated, IPCustomEntity = SourceIpAddress, AccountCustomEntity = UserIdentityUserName, LogType = Type
| where SourceIpAddress in (ipMatch)
| project TimeGenerated, SourceIpAddress, UserIdentityUserName, Type
| extend timestamp = TimeGenerated, IPCustomEntity = SourceIpAddress, AccountCustomEntity = UserIdentityUserName
),
(
DeviceNetworkEvents
| where isnotempty(RemoteIP)
| where RemoteIP in (IPList)
| extend timestamp = TimeGenerated, IPCustomEntity = RemoteIP, HostCustomEntity = DeviceName, LogType = Type
| where RemoteIP in (ipMatch)
| project TimeGenerated, RemoteIP, DeviceName, Type
| extend timestamp = TimeGenerated, IPCustomEntity = RemoteIP, HostCustomEntity = DeviceName
),
(
AzureDiagnostics
| where ResourceType == "AZUREFIREWALLS"
| where Category == "AzureFirewallApplicationRule"
| parse msg_s with Protocol 'request from ' SourceHost ':' SourcePort 'to ' DestinationHost ':' DestinationPort '. Action:' Action
| where isnotempty(DestinationHost)
| where DestinationHost has_any (IPList)
| extend DestinationIP = DestinationHost
| extend IPCustomEntity = SourceHost, LogType = Type
),
(
AzureDiagnostics
| where ResourceType == "AZUREFIREWALLS"
| where Category == "AzureFirewallNetworkRule"
| parse msg_s with Protocol 'request from ' SourceHost ':' SourcePort 'to ' DestinationHost ':' DestinationPort '. Action:' Action
| where isnotempty(DestinationHost)
| where DestinationHost has_any (IPList)
| extend DestinationIP = DestinationHost
| extend IPCustomEntity = SourceHost, LogType = Type
),
(
DeviceProcessEvents
| where InitiatingProcessFileName =~ "java.exe" and ProcessCommandLine has_all ('curl -s','wget') or
ProcessCommandLine has_all ('curl',@'${jndi') or
ProcessCommandLine has_any ("${jndi:ldap://", "${jndi:rmi:/", "${jndi:ldaps:/", "${jndi:dns:/", "${jndi:iiop://","${jndi:",'${web:','${jvmrunargs:')
| extend LogType = Type
),
(
DeviceNetworkEvents
| where RemoteIP in(IPList) and ActionType != "ConnectionFailed"
| extend LogType = Type
| where Category in ("AzureFirewallApplicationRule", "AzureFirewallNetworkRule")
| where msg_s has_any (ipMatch)
| project TimeGenerated, msg_s, Type
| parse msg_s with Protocol 'request from ' SourceIP ':' SourcePort 'to ' DestinationIP ':' DestinationPort '. Action:' Action
| where DestinationIP has_any (ipMatch)
| extend timestamp = TimeGenerated, IPCustomEntity = DestinationIP
)
// If you have enabled the imDNS and/or imNetworkSession normalization in your workdspace, you can uncomment below and include. Reference - https://docs.microsoft.com/azure/sentinel/normalization
//,
//(imDns (response_has_any_prefix=IPList)
//| project TimeGenerated, ResponseName, SrcIpAddr, Type
//| extend DestinationIPAddress = ResponseName, Host = SrcIpAddr
//| extend timestamp = TimeGenerated, IPCustomEntity = DestinationIPAddress, HostCustomEntity = Host
//),
//(imNetworkSession (dstipaddr_has_any_prefix=IPList)
//| project TimeGenerated, DstIpAddr, SrcIpAddr, Type
//| extend timestamp = TimeGenerated, IPCustomEntity = DstIpAddr, HostCustomEntity = SrcIpAddr
//)
)
entityMappings:
- entityType: Account
@ -183,5 +203,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.2
version: 2.0.0
kind: Scheduled

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

@ -71,7 +71,7 @@ query: |
| where Total > PerUserThreshold
| extend ResetPivot = "PerUserReset"),
(pwrmd
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ComputerList = make_set(Computer, 25), AccountList = make_set(Account, 25), AccountType = make_set(AccountType, 25), Account = arg_max(Account, TimeGenerated), Computer = arg_max(Computer , TimeGenerated), TargetUserList = make_set(TargetUserName, 25), TargetUserName = arg_max(TargetUserName, TimeGenerated), Total=count() by Type
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ComputerList = make_set(Computer, 25), AccountList = make_set(Account, 25), AccountType = make_set(AccountType, 25), Computer = arg_max(Computer , TimeGenerated), TargetUserList = make_set(TargetUserName, 25), TargetUserName = arg_max(TargetUserName, TimeGenerated), Total=count() by Type
| where Total > TotalThreshold
| extend ResetPivot = "TotalUserReset")
)

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

@ -2,7 +2,7 @@ id: acc4c247-aaf7-494b-b5da-17f18863878a
name: External guest invitations by default guest followed by Azure AD powershell signin
description: |
'By default guests have capability to invite more external guest user, who can do suspicious Azure AD enumeration. This detection will first look at guests
inviting external guests users who are then logging via Azure AD powershell after accpeting invitation.
inviting external guests users who are then logging via various powershell CLI after accepting invitation.
Ref : 'https://danielchronlund.com/2021/11/18/scary-azure-ad-tenant-enumeration-using-regular-b2b-guest-accounts/'
severity: Medium
requiredDataConnectors:
@ -30,13 +30,27 @@ query: |
| extend InitiatedByUser = iff(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)),
tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName), tostring(parse_json(tostring(InitiatedBy.app)).displayName))
| where InitiatedByUser has_any ("live.com#", "#EXT#")
| extend parsedUser = iff(InitiatedByUser has "live.com#", tostring(split(InitiatedByUser, "#")[1]),tostring(split(InitiatedByUser, "#EXT#")[1])) , InvitationTime = TimeGenerated
| extend
parsedUser = iff(InitiatedByUser has "live.com#", tostring(split(InitiatedByUser, "#")[1]),tostring(split(InitiatedByUser, "#EXT#")[1])),
InvitationTime = TimeGenerated
| join (
SigninLogs
| where UserType == "Guest" and AppDisplayName == "Microsoft Azure PowerShell"
| where UserType == "Guest"
| where AppId has_any
("1b730954-1685-4b74-9bfd-dac224a7b894",// Azure Active Directory PowerShell
"04b07795-8ddb-461a-bbee-02f9e1bf7b46",// Microsoft Azure CLI
"1950a258-227b-4e31-a9cf-717495945fc2",// Microsoft Azure PowerShell
"a0c73c16-a7e3-4564-9a95-2bdf47383716",// Microsoft Exchange Online Remote PowerShell
"fb78d390-0c51-40cd-8e17-fdbfab77341b",// Microsoft Exchange REST API Based Powershell
"d1ddf0e4-d672-4dae-b554-9d5bdfd93547",// Microsoft Intune PowerShell
"9bc3ab49-b65d-410a-85ad-de819febfddc",// Microsoft SharePoint Online Management Shell
"12128f48-ec9e-42f0-b203-ea49fb6af367",// MS Teams Powershell Cmdlets
"89bee1f7-5e6e-4d8a-9f3d-ecd601259da7",// Office365 Shell WCSS-Client
"23d8f6bd-1eb0-4cc2-a08c-7bf525c67bcd" // Power BI PowerShell
)
| extend SigninTime = TimeGenerated
) on $left.parsedUser == $right.UserPrincipalName
| project InvitationTime, SigninTime, InitiatedByUser, OperationName, AppDisplayName , IPAddress, UserType
| project InvitationTime, SigninTime, InitiatedByUser, OperationName, AppDisplayName, IPAddress, UserType
entityMappings:
- entityType: Account
fieldMappings:
@ -46,5 +60,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPAddress
version: 1.0.0
kind: scheduled
version: 1.0.1
kind: Scheduled

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

@ -42,7 +42,7 @@ tags:
- SchemaVersion: 0.2.1
query: |
let UserAgentString = dynamic (["${jndi:ldap:/", "${jndi:rmi:/", "${jndi:ldaps:/", "${jndi:dns:/", "${jndi:iiop:/","${jndi:","${jndi:nds:/","${jndi:corba/"]);
let UARegex = @'\\$\\{j\\$\\{::-\\}n\\$\\{::-\\}d\\$\\{::-\\}[a-zA-Z]';
let UARegex = @'(\\$|%24)(\\{|%7B)([^jJ]*[jJ])([^nN]*[nN])([^dD]*[dD])([^iI]*[iI])(:|%3A|\\$|%24|}|%7D)';
(union isfuzzy=true
(OfficeActivity
| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex
@ -101,5 +101,5 @@ entityMappings:
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.0
version: 1.0.1
kind: Scheduled

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

@ -0,0 +1,60 @@
id: bff058b2-500e-4ae5-bb49-a5b1423cbd5b
name: Accessed files shared by temporary external user
description: |
'This detection identifies an external user is added to a Team or Teams chat
and shares a files which is accessed by many users (>10) and the users is removed within short period of time. This might be
an indicator of suspicious activity.'
severity: Low
requiredDataConnectors:
- connectorId: Office365
dataTypes:
- OfficeActivity (Teams)
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1566
query: |
let fileAccessThrehold = 10;
OfficeActivity
| where OfficeWorkload =~ "MicrosoftTeams"
| where Operation =~ "MemberAdded"
| extend UPN = tostring(parse_json(Members)[0].UPN)
| where UPN contains ("#EXT#")
| project TimeAdded=TimeGenerated, Operation, UPN, UserWhoAdded = UserId, TeamName
| join kind = inner(
OfficeActivity
| where OfficeWorkload =~ "MicrosoftTeams"
| where Operation =~ "MemberRemoved"
| extend UPN = tostring(parse_json(Members)[0].UPN)
| where UPN contains ("#EXT#")
| project TimeDeleted=TimeGenerated, Operation, UPN, UserWhoDeleted = UserId, TeamName
) on UPN
| where TimeDeleted > TimeAdded
| join kind=inner
(
OfficeActivity
| where RecordType == "SharePointFileOperation"
| where SourceRelativeUrl has "Microsoft Teams Chat Files"
| where Operation == "FileUploaded"
| join kind = inner
(
OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation == "FileAccessed"
| where SourceRelativeUrl has "Microsoft Teams Chat Files"
| summarize FileAccessCount = count() by OfficeObjectId
| where FileAccessCount > fileAccessThrehold
) on $left.OfficeObjectId == $right.OfficeObjectId
)on $left.UPN == $right.UserId
| extend timestamp=TimeGenerated, AccountCustomEntity = UserWhoAdded
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
version: 1.0.0
kind: Scheduled

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

@ -35,35 +35,37 @@ query: |
(
SecurityEvent
| where EventID == '4656'
| where EventData has aadHealthMonAgentRegKey
| extend EventData = parse_xml(EventData).EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "")
| evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID)
| extend ObjectName = column_ifexists("ObjectName", ""),
ObjectType = column_ifexists("ObjectType", "")
| where ObjectType == 'Key'
| where ObjectName == aadHealthMonAgentRegKey
| extend SubjectUserName = column_ifexists("SubjectUserName", ""),
SubjectDomainName = column_ifexists("SubjectDomainName", ""),
ObjectName = column_ifexists("ObjectName", ""),
ObjectType = column_ifexists("ObjectType", ""),
ProcessName = column_ifexists("ProcessName", "")
| extend Process = split(ProcessName, '\\', -1)[-1],
Account = strcat(SubjectDomainName, "\\", SubjectUserName)
| where ObjectType == 'Key'
| where ObjectName == aadHealthMonAgentRegKey
| where Process !in (aadConnectHealthProcs)
| summarize StartTime = max(TimeGenerated), EndTime = min(TimeGenerated), count() by EventID, Account, Computer, Process, SubjectUserName, SubjectDomainName, ObjectName, ObjectType, ProcessName
),
(
SecurityEvent
| where EventID == '4663'
| extend Process = split(ProcessName, '\\', -1)[-1]
| where ObjectType == 'Key'
| where ObjectName == aadHealthMonAgentRegKey
| extend Process = tostring(split(ProcessName, '\\', -1)[-1])
| where Process !in (aadConnectHealthProcs)
| summarize StartTime = max(TimeGenerated), EndTime = min(TimeGenerated), count() by EventID, Account, Computer, Process, SubjectUserName, SubjectDomainName, ObjectName, ObjectType, ProcessName
)
)
// You can filter out potential machine accounts
//| where AccountType != 'Machine'
| extend timestamp = TimeGenerated, AccountCustomEntity = Account, HostCustomEntity = Computer
| summarize count() by ProcessName
| extend timestamp = StartTime, AccountCustomEntity = Account, HostCustomEntity = Computer
entityMappings:
- entityType: Account
fieldMappings:
@ -73,5 +75,5 @@ entityMappings:
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity
version: 1.0.0
version: 1.0.1
kind: Scheduled

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

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

@ -1,7 +1,7 @@
id: 4915c713-ab38-432e-800b-8e2d46933de6
name: New internet-exposed SSH endpoints
description: |
'Looks for SSH endpoints with a history of sign-ins only from private IP addresses are accessed from a public IP address.'
'Looks for SSH endpoints that rarely are accessed from a public IP address, in comparison with their history of sign-ins from private IP addresses.'
severity: Medium
requiredDataConnectors:
- connectorId: Syslog
@ -63,5 +63,5 @@ entityMappings:
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity
version: 1.0.0
version: 1.0.1
kind: Scheduled

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

@ -28,12 +28,13 @@ query: |
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true
| where isnotempty(FileHashValue)
| extend FileHashValue = toupper(FileHashValue)
// using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
| join kind=innerunique (
SecurityEvent | where TimeGenerated >= ago(dt_lookBack)
| where EventID in ("8003","8002","8005")
| where isnotempty(FileHash)
| extend SecurityEvent_TimeGenerated = TimeGenerated, Event = EventID
| extend SecurityEvent_TimeGenerated = TimeGenerated, Event = EventID, FileHash = toupper(FileHash)
)
on $left.FileHashValue == $right.FileHash
| where SecurityEvent_TimeGenerated < ExpirationDateTime
@ -54,5 +55,5 @@ entityMappings:
fieldMappings:
- identifier: Url
columnName: URLCustomEntity
version: 1.2.1
version: 1.2.2
kind: Scheduled

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

@ -44,7 +44,7 @@ query: |
| summarize AppService_TimeGenerated = arg_max(AppService_TimeGenerated, *) by IndicatorId, CIp
| project AppService_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, ExpirationDateTime, ConfidenceScore, TI_ipEntity, CsUsername,
WebApp = split(_ResourceId, '/')[8], CIp, CsHost, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress, _ResourceId
| extend timestamp = AppService_TimeGenerated, AccountCustomEntity = CsUsername, IPCustomEntity = CIp, URLCustomEntity = CsHost
| extend timestamp = AppService_TimeGenerated, AccountCustomEntity = CsUsername, IPCustomEntity = CIp, URLCustomEntity = Url, HostCustomEntity = CsHost
entityMappings:
- entityType: Host
fieldMappings:
@ -66,5 +66,5 @@ entityMappings:
fieldMappings:
- identifier: ResourceId
columnName: _ResourceId
version: 1.2.1
version: 1.2.2
kind: Scheduled

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

@ -39,7 +39,7 @@ query: |
AzureDiagnostics
| where TimeGenerated >= ago(dt_lookBack)
| where OperationName in ("AzureFirewallApplicationRuleLog", "AzureFirewallNetworkRuleLog")
| parse kind=regex flags=U msg_s with Protocol 'request from ' SourceHost 'to ' DestinationHost @'\.? Action: ' Action @'\.' Rest_msg
| parse kind=regex flags=U msg_s with Protocol 'request from ' SourceHost 'to ' DestinationHost @'\.? Action: ' Firewall_Action @'\.' Rest_msg
| extend SourceAddress = extract(@'([\.0-9]+)(:[\.0-9]+)?', 1, SourceHost)
| extend DestinationAddress = extract(@'([\.0-9]+)(:[\.0-9]+)?', 1, DestinationHost)
| extend RemoteIP = case(not(ipv4_is_private(DestinationAddress)), DestinationAddress, not(ipv4_is_private(SourceAddress)), SourceAddress, "")
@ -51,7 +51,7 @@ query: |
| where AzureFirewall_TimeGenerated < ExpirationDateTime
| summarize AzureFirewall_TimeGenerated = arg_max(AzureFirewall_TimeGenerated, *) by IndicatorId, RemoteIP
| project LatestIndicatorTime, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, DomainName, ExpirationDateTime, ConfidenceScore, AzureFirewall_TimeGenerated,
TI_ipEntity, Resource, Category, msg_s, SourceAddress, DestinationAddress, Action, Protocol, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress
TI_ipEntity, Resource, Category, msg_s, SourceAddress, DestinationAddress, Firewall_Action, Protocol, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress
| extend timestamp = AzureFirewall_TimeGenerated, IPCustomEntity = TI_ipEntity, URLCustomEntity = Url
entityMappings:
- entityType: IP
@ -62,5 +62,5 @@ entityMappings:
fieldMappings:
- identifier: Url
columnName: URLCustomEntity
version: 1.1.1
version: 1.1.2
kind: Scheduled

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

@ -12,7 +12,7 @@ requiredDataConnectors:
- ThreatIntelligenceIndicator
- connectorId: AzureKeyVault
dataTypes:
- AzureDiagnostics
- KeyVaultData
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt

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

@ -0,0 +1,54 @@
id: 66c81ae2-1f89-4433-be00-2fbbd9ba5ebe
name: TI map IP entity to CommonSecurityLog
description: |
'Identifies a match in CommonSecurityLog from any IP IOC from TI'
severity: Medium
requiredDataConnectors:
- connectorId: ThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: ThreatIntelligenceTaxii
dataTypes:
- ThreatIntelligenceIndicator
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
query: |
let IPRegex = '[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}';
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
ThreatIntelligenceIndicator
| where TimeGenerated >= ago(ioc_lookBack) and ExpirationDateTime > now()
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true
// Picking up only IOC's that contain the entities we want
| where isnotempty(NetworkIP) or isnotempty(EmailSourceIpAddress) or isnotempty(NetworkDestinationIP) or isnotempty(NetworkSourceIP)
// As there is potentially more than 1 indicator type for matching IP, taking NetworkIP first, then others if that is empty.
// Taking the first non-empty value based on potential IOC match availability
| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)
// using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
| join kind=innerunique (
CommonSecurityLog
| where TimeGenerated >= ago(dt_lookBack)
| extend MessageIP = extract(IPRegex, 0, Message)
| extend CS_ipEntity = iff(isnotempty(SourceIP), SourceIP, DestinationIP)
| extend CS_ipEntity = iff(isempty(CS_ipEntity) and isnotempty(MessageIP), MessageIP, CS_ipEntity)
| extend CommonSecurityLog_TimeGenerated = TimeGenerated
)
on $left.TI_ipEntity == $right.CS_ipEntity
| where CommonSecurityLog_TimeGenerated < ExpirationDateTime
| summarize CommonSecurityLog_TimeGenerated = arg_max(CommonSecurityLog_TimeGenerated, *) by IndicatorId, CS_ipEntity
| project CommonSecurityLog_TimeGenerated, SourceIP, DestinationIP, MessageIP, Message, DeviceVendor, DeviceProduct, IndicatorId, ThreatType, ExpirationDateTime, ConfidenceScore, TI_ipEntity, CS_ipEntity, LogSeverity, DeviceAction
| extend timestamp = CommonSecurityLog_TimeGenerated, IPCustomEntity = CS_ipEntity
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
kind: Scheduled

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

@ -4,9 +4,8 @@ description: |
'This detection uses Normalized Process Events to hunt Certutil activities'
requiredDataConnectors: []
tactics:
- Command And Control
- CommandAndControl
relevantTechniques:
- T1105

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

@ -8,8 +8,7 @@ description: |
In general, this should identify processes on a Host that are rare and rare for the environment.
References: https://medium.com/udacity/shannon-entropy-information-gain-and-picking-balls-from-buckets-5810d35d54b4
https://en.wiktionary.org/wiki/Shannon_entropy'
requiredDataConnectors:
- connectorId: []
requiredDataConnectors: []
tactics:
- Execution
query: |
@ -123,5 +122,3 @@ query: |
| project-reorder StartTime, EndTime, ResultCount, EventID, EventVendor, EventProduct, DvcHostname, ActorUserId, Account, AccountType, Weight, ProcessEntropy,TargetProcessFileName, TargetProcessFilePath, TargetProcessCommandLine, ActingProcessFileName, AllHostsProcessCount, ProcessCountOnHost, DistinctHostsProcessCount, _ResourceId, DvcId
| sort by Weight asc, ProcessEntropy asc, TargetProcessFilePath asc
| extend timestamp = StartTime, HostCustomEntity = DvcHostname, AccountCustomEntity = Account

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

@ -17,4 +17,3 @@ query: |
| summarize minTimeGenerated=min(TimeGenerated), maxTimeGenerated=max(TimeGenerated), count() by ActorUsername, Target, CommandLine, Dvc, EventVendor, EventProduct
| sort by ActorUsername, Target
| extend timestamp = minTimeGenerated, AccountCustomEntity = ActorUsername, HostCustomEntity = Dvc

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

@ -25,4 +25,3 @@ query: |
| where CommandLine has "/add" or (CreatedOnLocalMachine == 0 and CommandLine !has "/domain")
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), MachineCount=dcount(Dvc) by CreatedUser, CreatedOnLocalMachine, ActingProcessFileName, FileName, CommandLine, ActingProcessCommandLine, EventVendor, EventProduct
| extend timestamp = StartTimeUtc, AccountCustomEntity = CreatedUser

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

@ -5,8 +5,7 @@ description: |
These new processes could be benign new programs installed on hosts;
However, especially in normally stable environments, these new processes could provide an indication of an unauthorized/malicious binary that has been installed and run.
Reviewing the wider context of the logon sessions in which these binaries ran can provide a good starting point for identifying possible attacks.'
requiredDataConnectors:
- connectorId: []
requiredDataConnectors: []
tactics:
- Execution
query: |

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

@ -6,7 +6,7 @@ description: |
requiredDataConnectors: []
tactics:
- Defense Evasion
- DefenseEvasion
relevantTechniques:
- T1218.011
query: |

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

@ -4,7 +4,7 @@ description: |
'An attacker could look to introduce upstream compromised software packages by creating a new package feed within Azure DevOps. This query looks for new Feeds and includes details on any Azure AD Identity Protection alerts related to the user account creating the feed to assist in triage.'
requiredDataConnectors: []
tactics:
- Initial Access
- InitialAccess
relevantTechniques:
- T1195
query: |

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

@ -17,10 +17,11 @@ tags:
- log4shell
query: |
let log4jcmdstring = dynamic(["${jndi:ldap","${jndi:dns","${jndi:rmi","${jndi:corba","${jndi:iiop","${jndi:nis","${jndi:nds"]);
let log4jRegex = @'(\\$|%24)(\\{|%7B)([^jJ]*[jJ])([^nN]*[nN])([^dD]*[dD])([^iI]*[iI])(:|%3A|\\$|%24|}|%7D)';
AzureDiagnostics
| where Category in ("FrontdoorWebApplicationFirewallLog", "FrontdoorAccessLog", "ApplicationGatewayFirewallLog", "ApplicationGatewayAccessLog")
//The regex and the string matching look for the most common attacks. This is not supposed to be comprehensive.
| where originalRequestUriWithArgs_s has_any (log4jcmdstring) or originalRequestUriWithArgs_s matches regex '\\$\\{j\\$\\{::-\\}n\\$\\{::-\\}d\\$\\{::-\\}[a-zA-Z]' or userAgent_s has_any (log4jcmdstring) or userAgent_s matches regex '\\$\\{j\\$\\{::-\\}n\\$\\{::-\\}d\\$\\{::-\\}[a-zA-Z]'
| where originalRequestUriWithArgs_s has_any (log4jcmdstring) or originalRequestUriWithArgs_s matches regex log4jRegex or userAgent_s has_any (log4jcmdstring) or userAgent_s matches regex log4jRegex
| extend CmdLine = iff(originalRequestUriWithArgs_s has 'Base64/', split(split(originalRequestUriWithArgs_s, "Base64/",1)[0], "}", 0)[0], split(split(userAgent_s, "Base64/",1)[0], "}", 0)[0])
| extend CmdLine = base64_decode_tostring(tostring(CmdLine))
| where CmdLine has_any ("wget","curl")
@ -31,3 +32,4 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.1

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

@ -0,0 +1,58 @@
id: bf094505-fd2e-484f-b72a-acd79ee00ce8
name: Network Connection to New External LDAP Server
description: |
'This hunting query looks for outbound network connections using the LDAP protocol to external IP addresses, where that IP address has not had an LDAP network connection to it in the 14 days preceding the query timeframe. This could indicate someone exploiting a vulnerability such as CVE-2021-44228 to trigger the connection to a malicious LDAP server.
For more details on Apache Log4j Remote Code Execution Vulnerability - https://community.riskiq.com/article/505098fc/description
Find more details on collecting EXECVE data into Microsoft Sentinel - https://techcommunity.microsoft.com/t5/azure-sentinel/hunting-threats-on-linux-with-azure-sentinel/ba-p/1344431'
requiredDataConnectors:
- connectorId: CheckPoint
dataTypes:
- CommonSecurityLog (CheckPoint)
- connectorId: CiscoASA
dataTypes:
- CommonSecurityLog (Cisco)
- connectorId: PaloAltoNetworks
dataTypes:
- CommonSecurityLog (PaloAlto)
tactics:
- InitialAccess
relevantTechniques:
- T1190
tags:
- CVE-2021-44228
- Log4j
- Log4Shell
query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = starttime - 14d;
let legacy_ldap = (
CommonSecurityLog
| where TimeGenerated between(lookback..starttime)
// Filter to LDAP connections only
| where ApplicationProtocol =~ "ldap"
// Check LDAP server is external
| extend private = ipv4_is_private(DestinationIP)
| where private == false
// Filter out events where network connection was blocked - change this to expand hunt
| where DeviceAction has_any ("allow", "accept", "allowed")
| summarize by DestinationIP);
CommonSecurityLog
| where TimeGenerated between(starttime..endtime)
| where ApplicationProtocol =~ "ldap"
| extend private = ipv4_is_private(DestinationIP)
| where private == false
| where DestinationIP !in (legacy_ldap)
| where DeviceAction has_any ("allow", "accept", "allowed")
| extend timestamp = TimeGenerated
| project-reorder TimeGenerated, SourceIP, DestinationIP, ApplicationProtocol, DestinationPort, SentBytes, ReceivedBytes, DeviceAction
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIP
- entityType: IP
fieldMappings:
- identifier: Address
columnName: DestinationIP
version: 1.0.0

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

@ -1,9 +1,9 @@
id: 19abc034-139e-4e64-a05d-cb07ce8b003b
name: Malicious Connection to LDAP port for CVE-2021-44228 vulnerability
description: |
'This hunting query looks for connection to LDAP port to find possible exploitation attempts for CVE-2021-44228 involving log4j vulnerability.
Log4j is an open-source Apache logging library that is used in many Java-based applications. Awarness of normal baseline traffic of an enviornment for java.exe
while using this query will help detrmine normal from anaomalous.
'This hunting query looks for connection to the default LDAP ports to find possible exploitation attempts for CVE-2021-44228 involving log4j vulnerability.
The attack is not limited only to these ports. Log4j is an open-source Apache logging library that is used in many Java-based applications.
Awareness of normal baseline traffic of an environment for java.exe while using this query will help determine normal from anomalous.
Refrence: https://www.microsoft.com/security/blog/2021/12/11/guidance-for-preventing-detecting-and-hunting-for-cve-2021-44228-log4j-2-exploitation/'
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection

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

@ -12,7 +12,7 @@ requiredDataConnectors:
dataTypes:
- DeviceProcessEvents
tactics:
- DefenceEvasion
- DefenseEvasion
relevantTechniques:
- T1027
query: |

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

@ -8,7 +8,7 @@ requiredDataConnectors:
dataTypes:
- SecurityEvent
tactics:
- Command And Control
- CommandAndControl
relevantTechniques:
- T1105

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

@ -8,7 +8,7 @@ requiredDataConnectors:
dataTypes:
- SecurityEvent
tactics:
- Defense Evasion
- DefenseEvasion
relevantTechniques:
- T1218.011
query: |

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

@ -1,3 +1,4 @@
id: 53b6d42e-ff74-46a8-abee-ec72181f66ba
name: Sign-ins from IPs that attempt sign-ins to disabled accounts
description: |
'Identifies IPs with failed attempts to sign in to one or more disabled accounts signed in successfully to another account.

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

@ -0,0 +1,42 @@
id: 6fee32b3-3271-4a3f-9b01-dbd9432a1707
name: Possible Container Miner related artifacts detected
description: |
'This query uses syslog data to alert on possible artifacts associated with container running image related to digital cryptocurrency mining.
Attackers may perform such operations post compromise as seen after CVE-2021-44228 log4j vulnerability exploitation to scope and prioritize post-compromise objectives.
For more details on Apache Log4j Remote Code Execution Vulnerability - https://community.riskiq.com/article/505098fc/description
Find more details on collecting EXECVE data into Microsoft Sentinel - https://techcommunity.microsoft.com/t5/azure-sentinel/hunting-threats-on-linux-with-azure-sentinel/ba-p/1344431'
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
tactics:
- Impact
- Execution
relevantTechniques:
- T1496
- T1203
tags:
- CVE-2021-44228
- Log4j
- Log4Shell
query: |
Syslog
| where Facility == 'user'
| where SyslogMessage has "AUOMS_EXECVE"
| parse SyslogMessage with "type=" EventType " audit(" * "): " EventData
| where EventType =~ "AUOMS_EXECVE"
| parse EventData with * "syscall=" syscall " syscall_r=" * " success=" success " exit=" exit " a0" * " ppid=" ppid " pid=" pid " audit_user=" audit_user " auid=" auid " user=" user " uid=" uid " group=" group " gid=" gid "effective_user=" effective_user " euid=" euid " set_user=" set_user " suid=" suid " filesystem_user=" filesystem_user " fsuid=" fsuid " effective_group=" effective_group " egid=" egid " set_group=" set_group " sgid=" sgid " filesystem_group=" filesystem_group " fsgid=" fsgid " tty=" tty " ses=" ses " comm=\"" comm "\" exe=\"" exe "\"" * "cwd=\"" cwd "\"" * "name=\"" name "\"" * "cmdline=\"" cmdline "\" containerid=" containerid
| where (exe has "docker" and cmdline has_any ("monero-miner","minergate-cli","aeon-miner","xmr-miner")) or (exe has_any ("bash","dash") and cmdline has "docker kill" and cmdline has_any ("gakeaws","monero","xmr","pocosow"))
| project TimeGenerated, Computer, audit_user, user, cmdline
| extend AccountCustomEntity = user, HostCustomEntity = Computer, timestamp = TimeGenerated
| sort by TimeGenerated desc
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
version: 1.0.0

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше