Merge branch 'master' into Infoblox-CDC-dataconnector

This commit is contained in:
sschuur 2021-02-21 15:54:29 -08:00 коммит произвёл GitHub
Родитель 38d775cc49 83525d19a7
Коммит fe9d1b4b00
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
238 изменённых файлов: 28321 добавлений и 3090 удалений

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

@ -9,24 +9,30 @@ import * as logger from "./utils/logger";
import { ConnectorCategory } from "./utils/dataConnector";
export async function IsValidDataConnectorSchema(filePath: string): Promise<ExitCode> {
let jsonFile = JSON.parse(fs.readFileSync(filePath, "utf8"));
if(isPotentialConnectorJson(jsonFile))
{
let connectorCategory = getConnectorCategory(jsonFile.dataTypes, jsonFile.instructionSteps);
let schema = JSON.parse(fs.readFileSync(".script/utils/schemas/"+ connectorCategory +"_ConnectorSchema.json", "utf8"));
isValidSchema(jsonFile, schema);
isValidId(jsonFile.id);
isValidDataType(jsonFile.dataTypes);
/* Disabling temporarily till we get confirmation from PM*/
// isValidFileName(filePath
isValidPermissions(jsonFile.permissions, connectorCategory);
if(!filePath.includes('Templates'))
{
let jsonFile = JSON.parse(fs.readFileSync(filePath, "utf8"));
if(isPotentialConnectorJson(jsonFile))
{
let connectorCategory = getConnectorCategory(jsonFile.dataTypes, jsonFile.instructionSteps);
let schema = JSON.parse(fs.readFileSync(".script/utils/schemas/"+ connectorCategory +"_ConnectorSchema.json", "utf8"));
isValidSchema(jsonFile, schema);
isValidId(jsonFile.id);
isValidDataType(jsonFile.dataTypes);
/* Disabling temporarily till we get confirmation from PM*/
// isValidFileName(filePath
isValidPermissions(jsonFile.permissions, connectorCategory);
}
else{
console.warn(`Could not identify json file as a connector. Skipping File path: ${filePath}`)
}
}
else{
console.warn(`Could not identify json file as a connector. Skipping File path: ${filePath}`)
}
return ExitCode.SUCCESS;
console.warn(`Skipping Files under Templates folder : ${filePath}`)
}
return ExitCode.SUCCESS;
}
function isPotentialConnectorJson(jsonFile: any) {

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

@ -1,69 +1,105 @@
{
"Name": "AzureDevOpsAuditing",
"Properties": [
{
"Name":"AzureDevOpsAuditing",
"Properties": [
{
"Name": "TenantId",
"Type": " String"
},
{
"Name": "Id",
"Type": " String"
},
{
"Name": "CorrelationId",
"Type": " String"
},
{
"Name": "ActivityId",
"Type": " String"
},
{
"Name": "ActorCUID",
"Type": " String"
},
{
"Name": "ActorUserId",
"Type": " String"
},
{
"Name": "ActorUPN",
"Type": " String"
},
{
"Name": "AuthenticationMechanism",
"Type": " String"
},
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "Data",
"Type": "Dynamic"
},
{
"Name": "Area",
"Type": "String"
},
{
"Name": "OperationName",
"Type": "String"
},
{
"Name": "Details",
"Type": "String"
},
{
"Name": "GroupName",
"Type": "String"
},
{
"Name": "ActorUPN",
"Type": "String"
},
{
"Name": "ActorDisplayName",
"Type": "String"
},
{
"Name": "EntityName",
"Type": "String"
},
{
"Name": "AuthenticationMechanism",
"Type": "String"
},
{
"Name": "IpAddress",
"Type": "String"
},
{
"Name": "UserAgent",
"Type": "String"
},
{
"Name": "AuthenticationMechanism",
"Type": "String"
"Name": "ScopeType",
"Type": " String"
},
{
"Name": "ScopeDisplayName",
"Type": "String"
"Type": " String"
},
{
"Name": "ScopeId",
"Type": " String"
},
{
"Name": "ProjectId",
"Type": " String"
},
{
"Name": "ProjectName",
"Type": "String"
"Type": " String"
},
{
"Name": "ProjectId",
"Type": "String"
"Name": "IpAddress",
"Type": " String"
},
{
"Name": "UserAgent",
"Type": " String"
},
{
"Name": "OperationName",
"Type": " String"
},
{
"Name": "Data",
"Type": "dynamic"
},
{
"Name": "Details",
"Type": " String"
},
{
"Name": "Area",
"Type": " String"
},
{
"Name": "Category",
"Type": " String"
},
{
"Name": "CategoryDisplayName",
"Type": " String"
},
{
"Name": "ActorDisplayName",
"Type": " String"
},
{
"Name": "SourceSystem",
"Type": " String"
},
{
"Name": "Type",
"Type": " String"
}
]
}

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

@ -0,0 +1,229 @@
{
"Name": "CiscoISEEvent",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "EventId",
"Type": "String"
},
{
"Name": "EventSeverity",
"Type": "String"
},
{
"Name": "EventCategory",
"Type": "String"
},
{
"Name": "EventMessage",
"Type": "String"
},
{
"Name": "ConfigVersionId",
"Type": "String"
},
{
"Name": "DvcIpAddr",
"Type": "String"
},
{
"Name": "DvcHostname",
"Type": "String"
},
{
"Name": "DstIpAddr",
"Type": "String"
},
{
"Name": "DstPortNumber",
"Type": "String"
},
{
"Name": "DstUserName",
"Type": "String"
},
{
"Name": "NetworkProtocol",
"Type": "String"
},
{
"Name": "RequestLatency",
"Type": "String"
},
{
"Name": "NasIpAddress",
"Type": "String"
},
{
"Name": "NasPort",
"Type": "String"
},
{
"Name": "NasPortType",
"Type": "String"
},
{
"Name": "NasIdentifier",
"Type": "String"
},
{
"Name": "ServiceType",
"Type": "String"
},
{
"Name": "FramedMtu",
"Type": "String"
},
{
"Name": "CalledStationId",
"Type": "String"
},
{
"Name": "CallingStationId",
"Type": "String"
},
{
"Name": "EventType",
"Type": "String"
},
{
"Name": "DvcAction",
"Type": "DateTime"
},
{
"Name": "PrivilegeLevel",
"Type": "String"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "NetworkDeviceProfileId",
"Type": "String"
},
{
"Name": "AcsSessionId",
"Type": "String"
},
{
"Name": "AcctSessionId",
"Type": "String"
},
{
"Name": "AuthenType",
"Type": "String"
},
{
"Name": "AuthenticationIdentityStore",
"Type": "String"
},
{
"Name": "AuthenticationMethod",
"Type": "String"
},
{
"Name": "SelectedAccessService",
"Type": "String"
},
{
"Name": "SelectedShellProfile",
"Type": "String"
},
{
"Name": "IdentityGroup",
"Type": "String"
},
{
"Name": "Service",
"Type": "String"
},
{
"Name": "ServiceArgument",
"Type": "String"
},
{
"Name": "CmdSet",
"Type": "String"
},
{
"Name": "MatchedCommandSet",
"Type": "String"
},
{
"Name": "AuthenMethod",
"Type": "String"
},
{
"Name": "SelectedCommandSet",
"Type": "String"
},
{
"Name": "NetworkDeviceProfileName",
"Type": "String"
},
{
"Name": "PostureStatus",
"Type": "String"
},
{
"Name": "SelectedAuthorizationProfiles",
"Type": "String"
},
{
"Name": "AuthorizationPolicyMatchedRule",
"Type": "String"
},
{
"Name": "DvcMacAddr",
"Type": "String"
},
{
"Name": "DevicePublicMac",
"Type": "String"
},
{
"Name": "DevicePlatform",
"Type": "String"
},
{
"Name": "DevicePlatformVersion",
"Type": "String"
},
{
"Name": "DeviceType",
"Type": "String"
},
{
"Name": "HttpUserAgentOriginal",
"Type": "String"
},
{
"Name": "EventResult",
"Type": "String"
},
{
"Name": "RadiusPacketType",
"Type": "String"
},
{
"Name": "EventTypeDetailed",
"Type": "String"
},
{
"Name": "EventResultDetails",
"Type": "String"
}
]
}

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

@ -0,0 +1,165 @@
{
"Name": "Cisco_Umbrella",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "EventType",
"Type": "String"
},
{
"Name": "NetworkSessionId",
"Type": "String"
},
{
"Name": "Identities",
"Type": "String"
},
{
"Name": "NetworkRuleName",
"Type": "String"
},
{
"Name": "IdentityType",
"Type": "String"
},
{
"Name": "NetworkDirection",
"Type": "String"
},
{
"Name": "NetworkProtocol",
"Type": "String"
},
{
"Name": "NetworkPackets",
"Type": "String"
},
{
"Name": "SourceIP",
"Type": "String"
},
{
"Name": "SrcPortNumber",
"Type": "String"
},
{
"Name": "DstIpAddr",
"Type": "String"
},
{
"Name": "DvcHostname",
"Type": "String"
},
{
"Name": "NetworkRuleNumber",
"Type": "String"
},
{
"Name": "DvcAction",
"Type": "String"
},
{
"Name": "DnsQueryName",
"Type": "String"
},
{
"Name": "ThreatCategory",
"Type": "String"
},
{
"Name": "DnsQueryTypeName",
"Type": "String"
},
{
"Name": "DnsResponseCodeName",
"Type": "String"
},
{
"Name": "IdentityTypes",
"Type": "String"
},
{
"Name": "PolicyIdentity",
"Type": "String"
},
{
"Name": "PolicyIdentityType",
"Type": "String"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "DstPortNumber",
"Type": "String"
},
{
"Name": "EventEndTime",
"Type": "DateTime"
},
{
"Name": "SrcNatIpAddr",
"Type": "String"
},
{
"Name": "HttpContentType",
"Type": "String"
},
{
"Name": "HttpReferrerOriginal",
"Type": "String"
},
{
"Name": "HttpUserAgentOriginal",
"Type": "String"
},
{
"Name": "HttpStatusCode",
"Type": "String"
},
{
"Name": "SrcBytes",
"Type": "Double"
},
{
"Name": "DstBytes",
"Type": "Double"
},
{
"Name": "HttpResponseBodyBytes",
"Type": "Double"
},
{
"Name": "HashSha256",
"Type": "String"
},
{
"Name": "AvDetections",
"Type": "String"
},
{
"Name": "AmpDisposition",
"Type": "String"
},
{
"Name": "ThreatName",
"Type": "String"
},
{
"Name": "AmpScore",
"Type": "String"
},
{
"Name": "UrlOriginal",
"Type": "String"
},
{
"Name": "UrlCategory",
"Type": "String"
}
]
}

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

@ -0,0 +1,638 @@
{
"Name": "CrowdStrikeFalconEventStream",
"Properties":
[
{
"Name": "TenantId",
"Type": "String"
},
{
"Name": "SourceSystem",
"Type": "String"
},
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "ReceiptTime",
"Type": "DateTime"
},
{
"Name": "DeviceVendor",
"Type": "String"
},
{
"Name": "DeviceProduct",
"Type": "String"
},
{
"Name": "DeviceEventClassID",
"Type": "String"
},
{
"Name": "LogSeverity",
"Type": "String"
},
{
"Name": "OriginalLogSeverity",
"Type": "String"
},
{
"Name": "DeviceAction",
"Type": "String"
},
{
"Name": "SimplifiedDeviceAction",
"Type": "String"
},
{
"Name": "Computer",
"Type": "String"
},
{
"Name": "CommunicationDirection",
"Type": "String"
},
{
"Name": "DeviceFacility",
"Type": "String"
},
{
"Name": "DestinationPort",
"Type": "Int"
},
{
"Name": "DestinationIP",
"Type": "String"
},
{
"Name": "DeviceAddress",
"Type": "String"
},
{
"Name": "DeviceName",
"Type": "String"
},
{
"Name": "Message",
"Type": "String"
},
{
"Name": "Protocol",
"Type": "String"
},
{
"Name": "SourcePort",
"Type": "Int"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "RemoteIP",
"Type": "String"
},
{
"Name": "RemotePort",
"Type": "String"
},
{
"Name": "MaliciousIP",
"Type": "String"
},
{
"Name": "ThreatSeverity",
"Type": "Int"
},
{
"Name": "IndicatorThreatType",
"Type": "String"
},
{
"Name": "ThreatDescription",
"Type": "String"
},
{
"Name": "ThreatConfidence",
"Type": "String"
},
{
"Name": "ReportReferenceLink",
"Type": "String"
},
{
"Name": "MaliciousIPLongitude",
"Type": "real"
},
{
"Name": "MaliciousIPLatitude",
"Type": "real"
},
{
"Name": "MaliciousIPCountry",
"Type": "String"
},
{
"Name": "DeviceVersion",
"Type": "String"
},
{
"Name": "Activity",
"Type": "String"
},
{
"Name": "ApplicationProtocol",
"Type": "String"
},
{
"Name": "EventCount",
"Type": "Int"
},
{
"Name": "DestinationDnsDomain",
"Type": "String"
},
{
"Name": "DestinationServiceName",
"Type": "String"
},
{
"Name": "DstIpAddr",
"Type": "String"
},
{
"Name": "DestinationTranslatedPort",
"Type": "Int"
},
{
"Name": "DeviceDnsDomain",
"Type": "String"
},
{
"Name": "DeviceExternalID",
"Type": "String"
},
{
"Name": "DeviceInboundInterface",
"Type": "String"
},
{
"Name": "DeviceNtDomain",
"Type": "String"
},
{
"Name": "DeviceOutboundInterface",
"Type": "String"
},
{
"Name": "DevicePayloadId",
"Type": "String"
},
{
"Name": "ProcessName",
"Type": "String"
},
{
"Name": "DeviceTranslatedAddress",
"Type": "String"
},
{
"Name": "DstHostName",
"Type": "String"
},
{
"Name": "DestinationMACAddress",
"Type": "String"
},
{
"Name": "DstNtDomain",
"Type": "String"
},
{
"Name": "DestinationProcessId",
"Type": "Int"
},
{
"Name": "DestinationUserPrivileges",
"Type": "String"
},
{
"Name": "DestinationProcessName",
"Type": "String"
},
{
"Name": "DeviceTimeZone",
"Type": "String"
},
{
"Name": "DestinationUserID",
"Type": "String"
},
{
"Name": "DstUserName",
"Type": "String"
},
{
"Name": "DeviceMacAddress",
"Type": "String"
},
{
"Name": "ProcessID",
"Type": "Int"
},
{
"Name": "ExternalID",
"Type": "Int"
},
{
"Name": "FileCreateTime",
"Type": "String"
},
{
"Name": "FileHash",
"Type": "String"
},
{
"Name": "FileID",
"Type": "String"
},
{
"Name": "FileModificationTime",
"Type": "String"
},
{
"Name": "FilePath",
"Type": "String"
},
{
"Name": "FilePermission",
"Type": "String"
},
{
"Name": "FileType",
"Type": "String"
},
{
"Name": "FileName",
"Type": "String"
},
{
"Name": "FileSize",
"Type": "Int"
},
{
"Name": "ReceivedBytes",
"Type": "long"
},
{
"Name": "OldFileCreateTime",
"Type": "String"
},
{
"Name": "OldFileHash",
"Type": "String"
},
{
"Name": "OldFileID",
"Type": "String"
},
{
"Name": "OldFileModificationTime",
"Type": "String"
},
{
"Name": "OldFileName",
"Type": "String"
},
{
"Name": "OldFilePath",
"Type": "String"
},
{
"Name": "OldFilePermission",
"Type": "String"
},
{
"Name": "OldFileSize",
"Type": "Int"
},
{
"Name": "OldFileType",
"Type": "String"
},
{
"Name": "SentBytes",
"Type": "long"
},
{
"Name": "RequestURL",
"Type": "String"
},
{
"Name": "RequestClientApplication",
"Type": "String"
},
{
"Name": "RequestContext",
"Type": "String"
},
{
"Name": "RequestCookies",
"Type": "String"
},
{
"Name": "RequestMethod",
"Type": "String"
},
{
"Name": "SourceHostName",
"Type": "String"
},
{
"Name": "SrcMacAddr",
"Type": "String"
},
{
"Name": "SourceNTDomain",
"Type": "String"
},
{
"Name": "SourceDnsDomain",
"Type": "String"
},
{
"Name": "SourceServiceName",
"Type": "String"
},
{
"Name": "SourceTranslatedAddress",
"Type": "String"
},
{
"Name": "SourceTranslatedPort",
"Type": "Int"
},
{
"Name": "SourceProcessId",
"Type": "Int"
},
{
"Name": "SourceUserPrivileges",
"Type": "String"
},
{
"Name": "SourceProcessName",
"Type": "String"
},
{
"Name": "SourceUserID",
"Type": "String"
},
{
"Name": "SourceUserName",
"Type": "String"
},
{
"Name": "EventType",
"Type": "String"
},
{
"Name": "DeviceCustomIPv6Address1",
"Type": "String"
},
{
"Name": "DeviceCustomIPv6Address1Label",
"Type": "String"
},
{
"Name": "DeviceCustomIPv6Address2",
"Type": "String"
},
{
"Name": "DeviceCustomIPv6Address2Label",
"Type": "String"
},
{
"Name": "DeviceCustomIPv6Address3",
"Type": "String"
},
{
"Name": "DeviceCustomIPv6Address3Label",
"Type": "String"
},
{
"Name": "DeviceCustomIPv6Address4",
"Type": "String"
},
{
"Name": "DeviceCustomIPv6Address4Label",
"Type": "String"
},
{
"Name": "DeviceCustomFloatingPoint1",
"Type": "real"
},
{
"Name": "DeviceCustomFloatingPoint1Label",
"Type": "String"
},
{
"Name": "DeviceCustomFloatingPoint2",
"Type": "real"
},
{
"Name": "DeviceCustomFloatingPoint2Label",
"Type": "String"
},
{
"Name": "DeviceCustomFloatingPoint3",
"Type": "real"
},
{
"Name": "DeviceCustomFloatingPoint3Label",
"Type": "String"
},
{
"Name": "DeviceCustomFloatingPoint4",
"Type": "real"
},
{
"Name": "DeviceCustomFloatingPoint4Label",
"Type": "String"
},
{
"Name": "FlexDate1",
"Type": "String"
},
{
"Name": "FlexDate1Label",
"Type": "String"
},
{
"Name": "FlexNumber1",
"Type": "Int"
},
{
"Name": "FlexNumber1Label",
"Type": "String"
},
{
"Name": "FlexNumber2",
"Type": "Int"
},
{
"Name": "FlexNumber2Label",
"Type": "String"
},
{
"Name": "FlexString1",
"Type": "String"
},
{
"Name": "FlexString1Label",
"Type": "String"
},
{
"Name": "FlexString2",
"Type": "String"
},
{
"Name": "FlexString2Label",
"Type": "String"
},
{
"Name": "AdditionalExtensions",
"Type": "String"
},
{
"Name": "StartTime",
"Type": "DateTime"
},
{
"Name": "EndTime",
"Type": "DateTime"
},
{
"Name": "Type",
"Type": "String"
},
{
"Name": "_ResourceId",
"Type": "String"
},
{
"Name": "Outcome",
"Type": "String"
},
{
"Name": "Technique",
"Type": "String"
},
{
"Name": "PatternDisposition",
"Type": "String"
},
{
"Name": "SessionStartTime",
"Type": "DateTime"
},
{
"Name": "SessionEndTime",
"Type": "DateTime"
},
{
"Name": "ParentProcessId",
"Type": "Int"
},
{
"Name": "ChildProcessId",
"Type": "Int"
},
{
"Name": "Offset",
"Type": "Int"
},
{
"Name": "EventTimestamp",
"Type": "DateTime"
},
{
"Name": "ExeWrittenTime",
"Type": "DateTime"
},
{
"Name": "DnsRequestTime",
"Type": "DateTime"
},
{
"Name": "NetworkAccessTime",
"Type": "DateTime"
},
{
"Name": "DocAccessTime",
"Type": "DateTime"
},
{
"Name": "HashSpreadingEventTime",
"Type": "DateTime"
},
{
"Name": "HashSpreadingSensorTime",
"Type": "DateTime"
},
{
"Name": "ScanResultName",
"Type": "String"
},
{
"Name": "WrittenExeFileName",
"Type": "String"
},
{
"Name": "QuarantineFileSHA256",
"Type": "String"
},
{
"Name": "ScanResultEngine",
"Type": "String"
},
{
"Name": "AccessedDocFileName",
"Type": "String"
},
{
"Name": "WrittenExeFilePath",
"Type": "String"
},
{
"Name": "AccessedDocFilePath",
"Type": "String"
},
{
"Name": "QuarantineFilePath",
"Type": "String"
},
{
"Name": "ScanResultVersion",
"Type": "String"
},
{
"Name": "CommandLine",
"Type": "String"
},
{
"Name": "FalconHostLink",
"Type": "String"
},
{
"Name": "SensorId",
"Type": "String"
},
{
"Name": "Severity",
"Type": "String"
}
]
}

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

@ -0,0 +1,13 @@
{
"Name": "NGINX_CL",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "RawData",
"Type": "String"
}
]
}

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

@ -0,0 +1,565 @@
{
"Name": "ProofpointPOD",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "FilterModulesUrldefenseCountsNoRewriteIsLargeMsgPartSize",
"Type": "Double"
},
{
"Name": "SrcDvcHostname",
"Type": "String"
},
{
"Name": "PpsVersion",
"Type": "String"
},
{
"Name": "PpsCid",
"Type": "String"
},
{
"Name": "MsgParts",
"Type": "String"
},
{
"Name": "MetadataOriginDataAgent",
"Type": "String"
},
{
"Name": "MetadataOriginDataVersion",
"Type": "String"
},
{
"Name": "MetadataOriginDataCid",
"Type": "String"
},
{
"Name": "EventOriginalTime",
"Type": "DateTime"
},
{
"Name": "TlsCipher",
"Type": "String"
},
{
"Name": "TlsCipherBits",
"Type": "Double"
},
{
"Name": "TlsVersion",
"Type": "String"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "NetworkSessionId",
"Type": "String"
},
{
"Name": "SrcDvcHostname",
"Type": "String"
},
{
"Name": "SrcGeoCountry",
"Type": "String"
},
{
"Name": "ConnectionHelo",
"Type": "String"
},
{
"Name": "NetworkProtocol",
"Type": "String"
},
{
"Name": "NetworkConnectionState",
"Type": "String"
},
{
"Name": "NetworkBytes",
"Type": "Double"
},
{
"Name": "MsgLang",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderSubject",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderMessageId",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderTo",
"Type": "String"
},
{
"Name": "MsgNormalizedHeadertoHashed",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderFrom",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderFromHashed",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderFrom",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderFromHashed",
"Type": "String"
},
{
"Name": "MsgHeaderMessageId",
"Type": "String"
},
{
"Name": "MsgHeaderSubject",
"Type": "String"
},
{
"Name": "MsgHeaderTo",
"Type": "String"
},
{
"Name": "MsgHeaderToHashed",
"Type": "String"
},
{
"Name": "MsgParsedAddressesFromHashed",
"Type": "String"
},
{
"Name": "MsgParsedAddressesFrom",
"Type": "String"
},
{
"Name": "MsgParsedAddressesToHashed",
"Type": "String"
},
{
"Name": "MsgParsedAddressesTo",
"Type": "String"
},
{
"Name": "NetworkDuration",
"Type": "Double"
},
{
"Name": "FilterActions",
"Type": "String"
},
{
"Name": "FilterRoutes",
"Type": "String"
},
{
"Name": "FilterQid",
"Type": "String"
},
{
"Name": "EventStartTime",
"Type": "DateTime"
},
{
"Name": "NetworkDirection",
"Type": "String"
},
{
"Name": "FilterQuarantineRule",
"Type": "String"
},
{
"Name": "FilterQuarantineFolder",
"Type": "String"
},
{
"Name": "FilterModulesDmarcSrvid",
"Type": "String"
},
{
"Name": "FilterModulesDmarcRecords",
"Type": "String"
},
{
"Name": "FilterModulesDmarcFilterdResult",
"Type": "String"
},
{
"Name": "FilterModulesDmarcAuthResults",
"Type": "String"
},
{
"Name": "FilterModulesSpfDomain",
"Type": "String"
},
{
"Name": "FilterModulesSpfResult",
"Type": "String"
},
{
"Name": "FilterModulesSpamTriggeredClassifier",
"Type": "String"
},
{
"Name": "FilterModulesSpamSafeBlockedListMatches",
"Type": "String"
},
{
"Name": "FilterModulesSpamVersionEngine",
"Type": "String"
},
{
"Name": "FilterModulesSpamVersionDefinitions",
"Type": "String"
},
{
"Name": "FilterModulesSpamScoresOverall",
"Type": "Double"
},
{
"Name": "FilterModulesSpamScoresEngine",
"Type": "Double"
},
{
"Name": "FilterModulesSpamScoresClassifiers",
"Type": "String"
},
{
"Name": "FilterModulesSpamLangs",
"Type": "String"
},
{
"Name": "FilterModulesUrldefenseVersionEngine",
"Type": "String"
},
{
"Name": "FilterModulesUrldefenseCountsUnique",
"Type": "Double"
},
{
"Name": "FilterModulesUrldefenseCountsRewritten",
"Type": "Double"
},
{
"Name": "FilterModulesUrldefenseCountsTotal",
"Type": "Double"
},
{
"Name": "FilterModulesDkimv",
"Type": "String"
},
{
"Name": "FilterModulesPdrV2Response",
"Type": "String"
},
{
"Name": "FilterModulesZerohourScore",
"Type": "String"
},
{
"Name": "FilterDisposition",
"Type": "String"
},
{
"Name": "FilterSuborgsRcpts",
"Type": "String"
},
{
"Name": "FilterSuborgsSender",
"Type": "String"
},
{
"Name": "FilterMsgSizeBytes",
"Type": "Double"
},
{
"Name": "FilterVerifiedRcptsHashed",
"Type": "String"
},
{
"Name": "FilterVerifiedRcpts",
"Type": "String"
},
{
"Name": "Guid",
"Type": "String"
},
{
"Name": "EnvelopeRcptsHashed",
"Type": "String"
},
{
"Name": "DstUserUpn",
"Type": "String"
},
{
"Name": "EnvelopeFromHashed",
"Type": "String"
},
{
"Name": "SrcUserUpn",
"Type": "String"
},
{
"Name": "EventType",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderReturnPathHashed",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderXMailer",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderReturnPath",
"Type": "String"
},
{
"Name": "MsgHeaderXMailer",
"Type": "String"
},
{
"Name": "MsgHeaderReturnPathHashed",
"Type": "String"
},
{
"Name": "MsgHeaderReturnPath",
"Type": "String"
},
{
"Name": "FilterModulesSpamCharsets",
"Type": "String"
},
{
"Name": "FilterModulesDmarcAlignment",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderXOriginatingIp",
"Type": "String"
},
{
"Name": "MsgHeaderXOriginatingIp",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderReplyTo",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderReplyToHashed",
"Type": "String"
},
{
"Name": "MsgHeaderReplyToHashed",
"Type": "String"
},
{
"Name": "MsgHeaderReplyTo",
"Type": "String"
},
{
"Name": "FilterModulesUrldefenseCountsNoRewriteIsEmail",
"Type": "Double"
},
{
"Name": "FilterModulesPdrV2Rscore",
"Type": "Double"
},
{
"Name": "FilterOrigGuid",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderCc",
"Type": "String"
},
{
"Name": "MsgNormalizedHeaderCcHashed",
"Type": "String"
},
{
"Name": "MsgParsedAddressesCcHashed",
"Type": "String"
},
{
"Name": "MsgParsedAddressesCc",
"Type": "String"
},
{
"Name": "MsgHeaderCcHashed",
"Type": "String"
},
{
"Name": "MsgHeaderCc",
"Type": "String"
},
{
"Name": "FilterModulesAvVirusNames",
"Type": "String"
},
{
"Name": "FilterThrottleIp",
"Type": "String"
},
{
"Name": "FilterModulesUrldefenseCountsNoRewriteIsUnsupportedScheme",
"Type": "Double"
},
{
"Name": "FilterModulesUrldefenseCountsNoRewriteIsSchemeless",
"Type": "Double"
},
{
"Name": "FilterModulesUrldefenseCountsNoRewriteIsMaxLengthExceeded",
"Type": "Double"
},
{
"Name": "FilterModulesUrldefenseCountsNoRewriteIsExcludedDomain",
"Type": "Double"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "SmMsgid",
"Type": "String"
},
{
"Name": "PpsCid",
"Type": "String"
},
{
"Name": "PpsAgent",
"Type": "String"
},
{
"Name": "Id",
"Type": "String"
},
{
"Name": "EventUid",
"Type": "String"
},
{
"Name": "SmNrcpts",
"Type": "String"
},
{
"Name": "NetworkBytes",
"Type": "String"
},
{
"Name": "SmAuth",
"Type": "String"
},
{
"Name": "TlsEstablished",
"Type": "String"
},
{
"Name": "SrcNatIpAddr",
"Type": "String"
},
{
"Name": "ProcessName",
"Type": "String"
},
{
"Name": "NetworkProtocol",
"Type": "String"
},
{
"Name": "SrcUserUpn",
"Type": "String"
},
{
"Name": "SmClass",
"Type": "String"
},
{
"Name": "SmQid",
"Type": "String"
},
{
"Name": "EventOriginalTime",
"Type": "DateTime"
},
{
"Name": "EventOriginalMessage",
"Type": "String"
},
{
"Name": "MetadataOriginDataAgent",
"Type": "String"
},
{
"Name": "MetadataOriginDataCid",
"Type": "String"
},
{
"Name": "EventType",
"Type": "String"
},
{
"Name": "SmMailer",
"Type": "String"
},
{
"Name": "NetworkConnectionStateDetailed",
"Type": "String"
},
{
"Name": "SmDsn",
"Type": "String"
},
{
"Name": "DstUserUpn",
"Type": "String"
},
{
"Name": "NetworkDuration",
"Type": "String"
},
{
"Name": "SmPri",
"Type": "String"
},
{
"Name": "SmXdelay",
"Type": "String"
},
{
"Name": "SmCtladdr",
"Type": "String"
}
]
}

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

@ -12,7 +12,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="YamlDotNet" Version="6.0.0" />
<PackageReference Include="Microsoft.Azure.Sentinel.KustoServices" Version="1.0.6" />
<PackageReference Include="Microsoft.Azure.Sentinel.KustoServices" Version="1.0.9" />
</ItemGroup>
</Project>

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

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

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

@ -27,6 +27,11 @@ describe("dataConnectorValidator", () => {
await checkValid(".script/tests/dataConnectorValidatorTest/testFiles/missingIdAndConnectivityCriteria.json");
});
// Skipping json files if exists in Template folder.
it("should skip .json file if exist under Templates folder", async () => {
await checkValid(".script/tests/dataConnectorValidatorTest/testFiles/Templates/Connector_REST_API_template.json");
});
it("should throw an exception when dataConnectorSchema.json is missing a required property", async () => {
await checkInvalid(".script/tests/dataConnectorValidatorTest/testFiles/missingPublisherProperty.json", "SchemaError");
});

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

@ -0,0 +1,93 @@
{
"id": "ProviderNameApplianceName",
"title": "PROVIDER NAME APPLIANCE NAME",
"publisher": "PROVIDER NAME",
"descriptionMarkdown": "Use this template if you have a REST API connection to push data into Azure Sentinel Log Analytics.",
"graphQueries": [
{
"metricName": "Total data received",
"legend": "DATATYPE_NAME",
"baseQuery": "DATATYPE_NAME"
}
],
"sampleQueries": [
{
"description" : "One-line title for your sample query 1",
"query": "Kusto Query 1"
}
],
"dataTypes": [
{
"name": "DATATYPE_NAME",
"lastDataReceivedQuery": "DATATYPE_NAME\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
}
],
"connectivityCriterias": [
{
"type": "IsConnectedQuery",
"value": [
"DATATYPE_NAME\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)"
]
}
],
"availability": {
"status": 1,
"isPreview": true
},
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "read and write permissions are required.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"write": true,
"read": true,
"delete": true
}
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key)",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {
"action": true
}
}
],
"customs": [
{
"name": "Include custom pre-requisites if the connectivity requires - else delete customs",
"description": "Description for any custom pre-requisite"
}
]
},
"instructionSteps": [
{
"title": "",
"description": "1. How to get access to the data connector\n 2. If you have documentation to connect on your side link to that\n 3. Else, provide step by step instructions to discover the connection in your product\n",
"instructions": [
{
"parameters": {
"fillWith": [
"WorkspaceId"
],
"label": "Workspace ID"
},
"type": "CopyableLabel"
},
{
"parameters": {
"fillWith": [
"PrimaryKey"
],
"label": "Primary Key"
},
"type": "CopyableLabel"
}
]
}
]
}

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

@ -35,6 +35,7 @@
"Citrix",
"CitrixWAF",
"CyberArk",
"CyberpionSecurityLogs",
"Darktrace",
"DDOS",
"DNS",

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

@ -3,7 +3,7 @@
# the last matching pattern has the most precendence.
# Core team members
* @liemilyg @mgladi @orco365 @shalinoid @KobyKoren @lizamash @shainw @ianhelle @timbMSFT @juliango2100 @dicolanl @Amitbergman @sagamzu @YaronFruchtmann @preetikr @Yaniv-Shasha @sarah-yo @nazang @ehudk-msft @oshvartz @Liatlishams @NoamLandress @laithhisham
* @liemilyg @mgladi @orco365 @shalinoid @KobyKoren @shainw @ianhelle @timbMSFT @juliango2100 @dicolanl @Amitbergman @sagamzu @YaronFruchtmann @preetikr @Yaniv-Shasha @sarah-yo @nazang @ehudk-msft @oshvartz @Liatlishams @NoamLandress @laithhisham
# This is copied from here: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners

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

@ -0,0 +1,114 @@
{
"id": "DarktraceDarktrace",
"title": "AI Analyst Darktrace",
"publisher": "Darktrace",
"descriptionMarkdown": "The Darktrace connector lets users connect Darktrace Model Breaches in real-time with Azure Sentinel, allowing creation of custom Dashboards, Workbooks, Notebooks and Custom Alerts to improve investigation. Azure Sentinel's enhanced visibility into Darktrace logs enables monitoring and mitigation of security threats.",
"graphQueries": [
{
"metricName": "Total data received",
"legend": "Darktrace",
"baseQuery": "CommonSecurityLog\n| where DeviceVendor == \"Darktrace\" "
}
],
"sampleQueries": [
{
"description": "first 10 most recent data breaches",
"query": "CommonSecurityLog\n| where DeviceVendor == \"Darktrace\"\n| order by TimeGenerated desc \n| limit 10"
}
],
"dataTypes": [
{
"name": "CommonSecurityLog (Darktrace)",
"lastDataReceivedQuery": "CommonSecurityLog\n| where DeviceVendor == \"Darktrace\"\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
}
],
"connectivityCriterias": [
{
"type": "IsConnectedQuery",
"value": [
"CommonSecurityLog\n| where DeviceVendor == \"Darktrace\"\n| summarize LastLogReceived = max(TimeGenerated)\n| project IsConnected = LastLogReceived > ago(30d)"
]
}
],
"availability": {
"status": 1,
"isPreview": true
},
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "read and write permissions are required.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"read": true,
"write": true,
"delete": true
}
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {
"action": true
}
}
]
},
"instructionSteps": [
{
"title": "1. Linux Syslog agent configuration",
"description": "Install and configure the Linux agent to collect your Common Event Format (CEF) Syslog messages and forward them to Azure Sentinel.\n\n> Notice that the data from all regions will be stored in the selected workspace",
"innerSteps": [
{
"title": "1.1 Select or create a Linux machine",
"description": "Select or create a Linux machine that Azure Sentinel will use as the proxy between your security solution and Azure Sentinel this machine can be on your on-prem environment, Azure or other clouds."
},
{
"title": "1.2 Install the CEF collector on the Linux machine",
"description": "Install the Microsoft Monitoring Agent on your Linux machine and configure the machine to listen on the necessary port and forward messages to your Azure Sentinel workspace. The CEF collector collects CEF messages on port 514 TCP.\n\n> 1. Make sure that you have Python on your machine using the following command: python -version.\n\n> 2. You must have elevated permissions (sudo) on your machine.",
"instructions": [
{
"parameters": {
"fillWith": [
"WorkspaceId",
"PrimaryKey"
],
"label": "Run the following command to install and apply the CEF collector:",
"value": "sudo wget -O cef_installer.py https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/DataConnectors/CEF/cef_installer.py&&sudo python cef_installer.py {0} {1}"
},
"type": "CopyableLabel"
}
]
}
]
},
{
"title": "2. Forward Common Event Format (CEF) logs to Syslog agent",
"description": "Configure Darktrace to forward Syslog messages in CEF format to your Azure workspace via the Syslog agent. \n\n 1) Within the Darktrace Threat Visualizer, navigate to the System Config page in the main menu under Admin. \n\n 2) From the left-hand menu, select Modules and choose Azure Sentinel from the available Workflow Integrations.\\n 3) A configuration window will open. Locate Azure Sentinel Syslog CEF and click New to reveal the configuration settings, unless already exposed. \n\n 4) In the Server configuration field, enter the location of the log forwarder and optionally modify the communication port. Ensure that the port selected is set to 514 and is allowed by any intermediary firewalls. \n\n 5) Configure any alert thresholds, time offsets or additional settings as required. \n\n 6) Review any additional configuration options you may wish to enable that alter the Syslog syntax.\n\n 7) Enable Send Alerts and save your changes."
},
{
"title": "3. Validate connection",
"description": "Follow the instructions to validate your connectivity:\n\nOpen Log Analytics to check if the logs are received using the CommonSecurityLog schema.\n\n>It may take about 20 minutes until the connection streams data to your workspace.\n\nIf the logs are not received, run the following connectivity validation script:\n\n> 1. Make sure that you have Python on your machine using the following command: python -version\n\n>2. You must have elevated permissions (sudo) on your machine",
"instructions": [
{
"parameters": {
"fillWith": [
"WorkspaceId"
],
"label": "Run the following command to validate your connectivity:",
"value": "sudo wget -O cef_troubleshoot.py https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/DataConnectors/CEF/cef_troubleshoot.py&&sudo python cef_troubleshoot.py {0}"
},
"type": "CopyableLabel"
}
]
},
{
"title": "4. Secure your machine ",
"description": "Make sure to configure the machine's security according to your organization's security policy\n\n\n[Learn more >](https://aka.ms/SecureCEF)"
}
]
}

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

@ -74,7 +74,7 @@
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key)",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {
@ -92,11 +92,11 @@
},
{
"title": "1. Configure the Syslog server",
"description": "You will first need a **linux Syslog** server that Alsid for AD will send logs to. Typically you can run **rsyslog** on **Ubuntu**.\n You can then configure this server as you whish but it is recommended to be able to output AFAD logs in a separate file."
"description": "You will first need a **linux Syslog** server that Alsid for AD will send logs to. Typically you can run **rsyslog** on **Ubuntu**.\n You can then configure this server as you wish but it is recommended to be able to output AFAD logs in a separate file."
},
{
"title": "2. Configure Alsid to send logs to your Syslog server",
"description": "On your **Alsid for AD** portal, go to *System*, *Configuration* and then *Syslog*.\nFrom there you can create a new Syslog alert toward your Syslog server.\n\nOnce this is done, check that the logs are correctly gathered on your server in a seperate file (to do this, you can use the *Test the configuration* button in the Syslog alert configuration in AFAD)."
"description": "On your **Alsid for AD** portal, go to *System*, *Configuration* and then *Syslog*.\nFrom there you can create a new Syslog alert toward your Syslog server.\n\nOnce this is done, check that the logs are correctly gathered on your server in a separate file (to do this, you can use the *Test the configuration* button in the Syslog alert configuration in AFAD)."
},
{
"title": "3. Install and onboard the Microsoft agent for Linux",
@ -138,7 +138,7 @@
},
{
"title": "4. Configure the logs to be collected by the agents",
"description": "Configure the agent to collect the logs.\n\n1. Under workspace advanced settings **Configuration**, select **Data** and then **Custom Logs**.\n2. Select **Apply below configuration to my machines** and click **Add**.\n4. Upload a sample AFAD Syslog file from the **Linux** machine running the **Syslog** server and click **Next**.\n5. Set the record delimiter to **New Line** if not already the case and click **Next**.\n6. Select **Linux** and enter the file path to the **Syslog** file, click **+** then **Next**.\n7. Set the **Name** to *AlsidForADLog_CL* then click **Done** (Azure automatically adds *_CL* at the end of the name, there must be only one, make sure the name is not *AlsidForADLog_CL_CL*).\n\nAll of theses steps are showcased [here](https://www.youtube.com/watch?v=JwV1uZSyXM4&feature=youtu.be) as an example",
"description": "Configure the agent to collect the logs.\n\n1. Under workspace advanced settings **Configuration**, select **Data** and then **Custom Logs**.\n2. Select **Apply below configuration to my machines** and click **Add**.\n4. Upload a sample AFAD Syslog file from the **Linux** machine running the **Syslog** server and click **Next**.\n5. Set the record delimiter to **New Line** if not already the case and click **Next**.\n6. Select **Linux** and enter the file path to the **Syslog** file, click **+** then **Next**.\n7. In the Name field type *AlsidForADLog* before the _CL suffix, then click **Done**.\n\nAll of theses steps are showcased [here](https://www.youtube.com/watch?v=JwV1uZSyXM4&feature=youtu.be) as an example",
"instructions": [
{
"parameters": {

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

@ -31,7 +31,7 @@
}
],
"availability": {
"status": 1,
"status": 2,
"isPreview": true
},
"permissions": {
@ -49,7 +49,7 @@
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key)",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {

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

@ -1,114 +0,0 @@
{
"id": "DarktraceDarktrace",
"title": "Darktrace",
"publisher": "Darktrace",
"descriptionMarkdown": "The Darktrace connector lets users connect Darktrace Model Breaches in real-time with Azure Sentinel, allowing creation of custom Dashboards, Workbooks, Notebooks and Custom Alerts to improve investigation. Azure Sentinel's enhanced visibility into Darktrace logs enables monitoring and mitigation of security threats.",
"graphQueries": [
{
"metricName": "Total data received",
"legend": "Darktrace",
"baseQuery": "CommonSecurityLog\n| where DeviceVendor == \"Darktrace\"\n| where DeviceProduct == \"Enterprise Immune System\""
}
],
"sampleQueries": [
{
"description": "first 10 most recent data breaches",
"query": "CommonSecurityLog\n| where DeviceVendor == \"Darktrace\"\n| where DeviceProduct == \"Enterprise Immune System\"\n| order by TimeGenerated desc \n| limit 10"
}
],
"dataTypes": [
{
"name": "CommonSecurityLog (Darktrace)",
"lastDataReceivedQuery": "CommonSecurityLog\n| where DeviceVendor == \"Darktrace\"\n| where DeviceProduct == \"Enterprise Immune System\"\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
}
],
"connectivityCriterias": [
{
"type": "IsConnectedQuery",
"value": [
"CommonSecurityLog\n| where DeviceVendor == \"Darktrace\"\n| where DeviceProduct == \"Enterprise Immune System\"\n| summarize LastLogReceived = max(TimeGenerated)\n| project IsConnected = LastLogReceived > ago(30d)"
]
}
],
"availability": {
"status": 1,
"isPreview": true
},
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "read and write permissions are required.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"read": true,
"write": true,
"delete": true
}
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {
"action": true
}
}
]
},
"instructionSteps": [
{
"title": "1. Linux Syslog agent configuration",
"description": "Install and configure the Linux agent to collect your Common Event Format (CEF) Syslog messages and forward them to Azure Sentinel.\n\n> Notice that the data from all regions will be stored in the selected workspace",
"innerSteps": [
{
"title": "1.1 Select or create a Linux machine",
"description": "Select or create a Linux machine that Azure Sentinel will use as the proxy between your security solution and Azure Sentinel this machine can be on your on-prem environment, Azure or other clouds."
},
{
"title": "1.2 Install the CEF collector on the Linux machine",
"description": "Install the Microsoft Monitoring Agent on your Linux machine and configure the machine to listen on the necessary port and forward messages to your Azure Sentinel workspace. The CEF collector collects CEF messages on port 514 TCP.\n\n> 1. Make sure that you have Python on your machine using the following command: python -version.\n\n> 2. You must have elevated permissions (sudo) on your machine.",
"instructions": [
{
"parameters": {
"fillWith": [
"WorkspaceId",
"PrimaryKey"
],
"label": "Run the following command to install and apply the CEF collector:",
"value": "sudo wget -O cef_installer.py https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/DataConnectors/CEF/cef_installer.py&&sudo python cef_installer.py {0} {1}"
},
"type": "CopyableLabel"
}
]
}
]
},
{
"title": "2. Forward Common Event Format (CEF) logs to Syslog agent",
"description": "Set your security solution to send Syslog messages in CEF format to the proxy machine. Make sure you to send the logs to port 514 TCP on the machine's IP address."
},
{
"title": "3. Validate connection",
"description": "Follow the instructions to validate your connectivity:\n\nOpen Log Analytics to check if the logs are received using the CommonSecurityLog schema.\n\n>It may take about 20 minutes until the connection streams data to your workspace.\n\nIf the logs are not received, run the following connectivity validation script:\n\n> 1. Make sure that you have Python on your machine using the following command: python -version\n\n>2. You must have elevated permissions (sudo) on your machine",
"instructions": [
{
"parameters": {
"fillWith": [
"WorkspaceId"
],
"label": "Run the following command to validate your connectivity:",
"value": "sudo wget -O cef_troubleshoot.py https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/DataConnectors/CEF/cef_troubleshoot.py&&sudo python cef_troubleshoot.py {0}"
},
"type": "CopyableLabel"
}
]
},
{
"title": "4. Secure your machine ",
"description": "Make sure to configure the machine's security according to your organization's security policy\n\n\n[Learn more >](https://aka.ms/SecureCEF)"
}
]
}

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

@ -0,0 +1,74 @@
param(
[Parameter(Mandatory=$true)]$DocuSignEnvironment,
[Parameter(Mandatory=$true)]$IntegrationKey
)
If ($DocuSignEnvironment.ToLower() -eq "developer") {
$jwtHost = "account-d"
}
Else {
$jwtHost = "account"
}
$scopes = "signature%20impersonation"
$PORT = '8080'
$IP = 'localhost'
$state = [Convert]::ToString($(Get-Random -Maximum 1000000000), 16)
$authorizationEndpoint = "https://$jwtHost.docusign.com/oauth"
$redirectUri = "http://${IP}:${PORT}/authorization-code/callback"
$redirectUriEscaped = [Uri]::EscapeDataString($redirectURI)
$authorizationURL = "$authorizationEndpoint/auth?scope=$scopes&redirect_uri=$redirectUriEscaped&client_id=$IntegrationKey&state=$state&response_type=code"
Write-Output "The authorization URL is: $authorizationURL"
Write-Output ""
# Request the authorization code
# Use Http Server
$http = New-Object System.Net.HttpListener
# Hostname and port to listen on
$http.Prefixes.Add($redirectURI + "/")
# Start the Http Server
$http.Start()
if ($http.IsListening) {
Write-Output "Open the following URL in a browser to continue:" $authorizationURL
Start-Process $authorizationURL
}
while ($http.IsListening) {
$context = $http.GetContext()
if ($context.Request.HttpMethod -eq 'GET' -and $context.Request.Url.LocalPath -match '/authorization-code/callback') {
# write-host "Check context"
# write-host "$($context.Request.UserHostAddress) => $($context.Request.Url)" -f 'mag'
[string]$html = '
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
Ok. You may close this tab and return to the shell. This window closes automatically in five seconds.
<script type="text/javascript">
setTimeout(
function ( )
{
self.close();
}, 5000 );
</script>
</body>
</html>
'
# Respond to the request
$buffer = [System.Text.Encoding]::UTF8.GetBytes($html) # Convert HTML to bytes
$context.Response.ContentLength64 = $buffer.Length
$context.Response.OutputStream.Write($buffer, 0, $buffer.Length) # Stream HTML to browser
$context.Response.OutputStream.Close() # Close the response
Start-Sleep 10
$http.Stop()
}
}

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

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

@ -1,13 +1,16 @@
<#
Title: DocuSign Security Events Data Connector
Language: PowerShell
Version: 1.0
Version: 2.0
Author: Sreedhar Ande
Last Modified: 1/13/2021
Comment: Inital Release
Last Modified: 2/16/2021
Comment: V2 re-designed;
Ingests Security Events for your DocuSign account into Azure Log Analytics Workspace using DocuSign Monitor REST API
Ingests DocuSign Account Users into Azure Log Analytics Workspace using DocuSign Users REST API
Note:Above API's resumes getting records from the spot where the previous call left off to avoid duplication of records in DocuSignSecurityEvents_CL and DocuSignUsers_CL Log Analytics Workspace custom tables
DESCRIPTION
This Function App calls the DocuSign Monitor REST API (https://{ORG}.docusign.net/api/v2.0/datasets/monitor/stream/) to pull the security events for your DocuSign account.
This Function App calls the DocuSign Monitor REST API (https://lens.docusign.net/api/v2.0/datasets/monitor/stream/) to pull the security events for your DocuSign account.
The response from the DocuSign Monitor REST 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.
#>
@ -18,13 +21,12 @@ param($Timer)
# Get the current universal time in the default string format.
$currentUTCtime = (Get-Date).ToUniversalTime()
# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.
if ($Timer.IsPastDue) {
Write-Host "PowerShell timer is running late!"
Write-Host "DocuSign-SecurityEvents: Azure Function triggered at: $currentUTCtime - timer is running late!"
}
else{
Write-Host "DocuSign-SecurityEvents: Azure Function triggered at: $currentUTCtime - timer is ontime!"
}
# Write an information log with the current time.
Write-Host "PowerShell timer trigger function ran! TIME: $currentUTCtime"
# Main
if ($env:MSI_SECRET -and (Get-Module -ListAvailable Az.Accounts)){
@ -33,16 +35,31 @@ if ($env:MSI_SECRET -and (Get-Module -ListAvailable Az.Accounts)){
$AzureWebJobsStorage = $env:AzureWebJobsStorage
$DocuSignAccessToken = $env:DocuSignOAuthAccessToken
$DocuSignIntegrationKey = $env:DocuSignIntegrationKey
$DocuSignAdminUserGUID = $env:DocuSignAdminUserGUID
$DocuSignAccountAPIID = $env:DocuSignAccountAPIID
$DocuSignEnvironment = $env:DocuSignEnvironment
$workspaceId = $env:WorkspaceId
$workspaceKey = $env:WorkspaceKey
$storageAccountContainer = "docusign-monitor"
$CustomLogTable = $env:CustomLogTableName
$tempDir=$env:TMPDIR
#The AzureTenant variable is used to specify other cloud environments like Azure Gov(.us) etc.,
$AzureTenant = $env:AZURE_TENANT
$storageAccountTableName = "docusignexecutions"
$LATableDSMAPI = $env:LATableDSMAPI
$LATableDSUsers = $env:LATableDSUsers
$LAURI = $env:LAURI
$DocuSignUserInfoBaseURI = $env:DocuSignUserInfoBaseURI
# Flag to turn on/off DocuSign Users information into LA Workspace Table
$DocuSignUsersIngestion = $env:NeedDocuSignUsers
$currentStartTime = (get-date).ToUniversalTime() | get-date -Format yyyy-MM-ddTHH:mm:ss:ffffffZ
Write-Output "LAURI : $LAURI"
if($LAURI.Trim() -notmatch 'https:\/\/([\w\-]+)\.ods\.opinsights\.azure.([a-zA-Z\.]+)$')
{
Write-Error -Message "DocuSign-SecurityEvents: Invalid Log Analytics Uri." -ErrorAction Stop
Exit
}
Function Write-OMSLogfile {
<#
@ -117,14 +134,15 @@ Function Write-OMSLogfile {
-method $method `
-contentType $contentType `
-resource $resource
$uri = "https://" + $customerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01"
$LAURI = $LAURI.Trim() + $resource + "?api-version=2016-04-01"
Write-Output "LAURI : $LAURI"
$headers = @{
"Authorization" = $signature;
"Log-Type" = $type;
"x-ms-date" = $rfc1123date
"time-generated-field" = $dateTime
}
$response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $Body -UseBasicParsing
$response = Invoke-WebRequest -Uri $LAURI.Trim() -Method $method -ContentType $contentType -Headers $headers -Body $Body -UseBasicParsing
Write-Verbose -message ('Post Function Return Code ' + $response.statuscode)
return $response.statuscode
}
@ -144,7 +162,7 @@ Function Write-OMSLogfile {
return $returnCode
}
Function SendToLogA ($eventsData) {
Function SendToLogA ($eventsData, $eventsTable) {
#Test Size; Log A limit is 30MB
$tempdata = @()
$tempDataSize = 0
@ -155,7 +173,7 @@ Function SendToLogA ($eventsData) {
$tempdata += $record
$tempDataSize += ($record | ConvertTo-Json -depth 20).Length
if ($tempDataSize -gt 25MB) {
$postLAStatus = Write-OMSLogfile -dateTime (Get-Date) -type $CustomLogTable -logdata $tempdata -CustomerID $workspaceId -SharedKey $workspaceKey
$postLAStatus = Write-OMSLogfile -dateTime (Get-Date) -type $eventsTable -logdata $tempdata -CustomerID $workspaceId -SharedKey $workspaceKey
write-Host "Sending data = $TempDataSize"
$tempdata = $null
$tempdata = @()
@ -163,127 +181,247 @@ Function SendToLogA ($eventsData) {
}
}
Write-Host "Sending left over data = $Tempdatasize"
$postLAStatus = Write-OMSLogfile -dateTime (Get-Date) -type $CustomLogTable -logdata $eventsData -CustomerID $workspaceId -SharedKey $workspaceKey
$postLAStatus = Write-OMSLogfile -dateTime (Get-Date) -type $eventsTable -logdata $eventsData -CustomerID $workspaceId -SharedKey $workspaceKey
}
Else {
$postLAStatus = Write-OMSLogfile -dateTime (Get-Date) -type $CustomLogTable -logdata $eventsData -CustomerID $workspaceId -SharedKey $workspaceKey
$postLAStatus = Write-OMSLogfile -dateTime (Get-Date) -type $eventsTable -logdata $eventsData -CustomerID $workspaceId -SharedKey $workspaceKey
}
return $postLAStatus
return $postLAStatus
}
$docuSignAPIHeaders = @{
Authorization = "bearer $DocuSignAccessToken"
'Content-Type' = "application/json"
If ($DocuSignEnvironment.ToLower() -eq "developer") {
$jwtHost = "account-d"
$dsmHost = "lens-d"
}
Else {
$jwtHost = "account"
$dsmHost = "lens"
}
#Get Orgs from ORGS.json in Az Storage
$apiVersion = "eSignature"
$timestamp = [int][double]::Parse((Get-Date (Get-Date).ToUniversalTime() -UFormat %s))
$storageAccountContext = New-AzStorageContext -ConnectionString $AzureWebJobsStorage
$checkBlob = Get-AzStorageBlob -Blob ORGS.json -Container $storageAccountContainer -Context $storageAccountContext
$checkBlob = Get-AzStorageBlob -Blob "DocuSignRSAPrivateKey.key" -Container $storageAccountContainer -Context $storageAccountContext
if($null -ne $checkBlob){
Get-AzStorageBlobContent -Blob ORGS.json -Container $storageAccountContainer -Context $storageAccountContext -Destination "$tempDir\orgs.json" -Force
$docuSignOrgs = Get-Content "$tempDir\orgs.json" | ConvertFrom-Json
Get-AzStorageBlobContent -Blob "DocuSignRSAPrivateKey.key" -Container $storageAccountContainer -Context $storageAccountContext -Destination "C:\local\Temp\DocuSignRSAPrivateKey.key" -Force
$privateKeyPath = "C:\local\Temp\DocuSignRSAPrivateKey.key"
}
else{
Write-Error "No ORGS.json file, exiting"
Write-Error "No DocuSignRSAPrivateKey.key file, exiting"
exit
}
foreach($org in $docuSignOrgs){
$orgName = $org.org
Write-Host "Starting to process ORG: $orgName"
#check for last run file
$checkBlob = Get-AzStorageBlob -Blob "lastrun-Monitor.json" -Container $storageAccountContainer -Context $storageAccountContext
if($null -ne $checkBlob){
#Blob found get data
Get-AzStorageBlobContent -Blob "lastrun-Monitor.json" -Container $storageAccountContainer -Context $storageAccountContext -Destination "$tempDir\lastrun-Monitor.json" -Force
$lastRunMonitorContext = Get-Content "$tempDir\lastrun-Monitor.json" | ConvertFrom-Json
}
else {
#no blob create the context
$lastRun = $currentStartTime
$lastRunMonitor = @"
{
"org":$orgName
"lastRun": "$lastRun",
"lastRunEndCursor": ""
if ($apiVersion -eq "rooms") {
$scopes = "signature%20impersonation%20dtr.rooms.read%20dtr.rooms.write%20dtr.documents.read%20dtr.documents.write%20dtr.profile.read%20dtr.profile.write%20dtr.company.read%20dtr.company.write%20room_forms"
} elseif ($apiVersion -eq "eSignature") {
$scopes = "signature%20impersonation"
} elseif ($apiVersion -eq "click") {
$scopes = "click.manage"
}
"@
$lastRunMonitor | Out-File "$tempDir\lastrun-Monitor.json"
$lastRunMonitorContext = $lastRunMonitor | ConvertFrom-Json
}
$lastRunEndCursorContext = $lastRunMonitorContext | Where-Object {$_.org -eq $orgName}
if([string]::IsNullOrEmpty($lastRunEndCursorContext.lastRunEndCursor)){
$lastRunEndCursorValue=""
}
else {
$lastRunEndCursorValue = $lastRunEndCursorContext.lastRunEndCursor
}
$complete=$false
$iterations=0
DO{
$iterations++
try{
$docuSignMonitorAPI=$null
$monitorApiResponse = $null
$docuSignMonitorAPI = "https://${orgName}.docusign.net/api/v2.0/datasets/monitor/stream?cursor=${lastRunEndCursorValue}&limit=2000"
$monitorApiResponse = Invoke-RestMethod -Uri $docuSignMonitorAPI -Method 'GET' -Headers $docuSignAPIHeaders
Write-Output "Iteration:$iterations"
# Get the endCursor value from the response.
# This lets you resume getting records from the spot where this call left off
$currentRunEndCursorValue = $monitorApiResponse.endCursor
Write-Output "currentRunEndCursorValue :$currentRunEndCursorValue"
Write-Output "Last run cursorValue : $lastRunEndCursorValue"
if (![string]::IsNullOrEmpty($lastRunEndCursorValue))
{
# If the endCursor from the response is the same as the one that you already have,
# it means that you have reached the end of the records
if ($currentRunEndCursorValue.Substring(0, $currentRunEndCursorValue.LastIndexOf('_')) -eq $lastRunEndCursorValue.Substring(0, $lastRunEndCursorValue.LastIndexOf('_')))
{
Write-Output 'Current run endCursor & last run endCursor values are the same. This indicates that you have reached the end of your available records.'
$complete=$true
}
}
if(!$complete){
Write-Output "Updating the cursor value of $lastRunEndCursorValue to the new value of $currentRunEndCursorValue"
$lastRunEndCursorValue=$currentRunEndCursorValue
$postReturnCode = SendToLogA -EventsData $monitorApiResponse.data
if($postReturnCode -eq 200)
{
Write-Host ("{$monitorApiResponse.data.length} DocuSign Security Events have been ingested into Azure Log Analytics Workspace Table {$CustomLogTable}")
}
Remove-Item $monitorApiResponse
$lastRunEndCursorContext.org = $orgName
$lastRunEndCursorContext.lastRunEndCursor = $lastRunEndCursorValue
$lastRunEndCursorContext.lastRun = $currentStartTime
$lastRunMonitorContext | ConvertTo-Json | Out-File "$tempDir\lastrun-Monitor.json"
Set-AzStorageBlobContent -Blob "lastrun-Monitor.json" -Container $storageAccountContainer -Context $storageAccountContext -File "$tempDir\lastrun-Monitor.json" -Force
Remove-Item "$tempDir\lastrun-Monitor.json" -Force
Remove-Item "$tempDir\orgs.json" -Force
Start-Sleep -Second 5
}
}
catch{
$int = 0
foreach($header in $_.Exception.Response.Headers){
if($header -eq "X-DocuSign-TraceToken"){ write-host "TraceToken : " $_.Exception.Response.Headers[$int]}
$int++
}
write-host "Error : $_.ErrorDetails.Message"
write-host "Command : $_.InvocationInfo.Line"
$complete = $true
}
# Step 1. Create a JWT
$decJwtHeader = [ordered]@{
'typ' = 'JWT';
'alg' = 'RS256'
} | ConvertTo-Json -Compress
# Remove %20 from scope string
$scopes = $scopes -replace '%20',' '
$exp = $timestamp + 7200
$decJwtPayLoad = [ordered]@{
'iss' = $DocuSignIntegrationKey;
'sub' = $DocuSignAdminUserGUID;
'iat' = $timestamp;
'exp' = $exp;
'aud' = "$jwtHost.docusign.com";
'scope' = $scopes
} | ConvertTo-Json -Compress
$encJwtHeaderBytes = [System.Text.Encoding]::UTF8.GetBytes($decJwtHeader)
$encJwtHeader = [System.Convert]::ToBase64String($encJwtHeaderBytes) -replace '\+', '-' -replace '/', '_' -replace '='
$encJwtPayLoadBytes = [System.Text.Encoding]::UTF8.GetBytes($decJwtPayLoad)
$encJwtPayLoad = [System.Convert]::ToBase64String($encJwtPayLoadBytes) -replace '\+', '-' -replace '/', '_' -replace '='
$jwtToken = "$encJwtHeader.$encJwtPayLoad"
try{
Add-Type -Path "C:\home\site\wwwroot\Modules\DerConverter.dll"
Add-Type -Path "C:\home\site\wwwroot\Modules\PemUtils.dll"
$keyStream = [System.IO.File]::OpenRead($privateKeyPath)
$rsaParameters = [PemUtils.PemReader]::new($keyStream).ReadRsaKey()
$rsa = [System.Security.Cryptography.RSA]::Create($rsaParameters)
$tokenBytes = [System.Text.Encoding]::ASCII.GetBytes($jwtToken)
$signedToken = $rsa.SignData(
$tokenBytes,
[System.Security.Cryptography.HashAlgorithmName]::SHA256,
[System.Security.Cryptography.RSASignaturePadding]::Pkcs1)
$signedBase64Token = [System.Convert]::ToBase64String($signedToken) -replace '\+', '-' -replace '/', '_' -replace '='
$jwtToken = "$encJwtHeader.$encJwtPayLoad.$signedBase64Token"
$keyStream.Close()
$keyStream.Dispose()
}
catch {
Write-Output "Please check you have DerConverter.dll and PemUtils.dll under C:\home\site\wwwroot\Modules"
$keyStream.Close()
$keyStream.Dispose()
}
# Step 2. Obtain the access token
try {
Write-Output "Obtaining DocuSign access token"
$authorizationEndpoint = "https://$jwtHost.docusign.com/oauth/"
$tokenResponse = Invoke-WebRequest `
-Uri "$authorizationEndpoint/token" `
-Method "POST" `
-Body "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=$jwtToken"
} While ($complete -eq $false )
$docuSignAccessToken = ($tokenResponse | ConvertFrom-Json).access_token
#Setup uri Headers for requests to DSM API & User API
$docuSignAPIHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$docuSignAPIHeaders.Add("Content-Type", "application/json")
$docuSignAPIHeaders.Add("Authorization", "Bearer $docuSignAccessToken")
} # closing foreach
$StorageTable = Get-AzStorageTable -Name $storageAccountTableName -Context $storageAccountContext -ErrorAction Ignore
if($null -eq $StorageTable.Name){
New-AzStorageTable -Name $storageAccountTableName -Context $storageAccountContext
$docuSignTimeStampTbl = (Get-AzStorageTable -Name $storageAccountTableName -Context $storageAccountContext.Context).cloudTable
Add-AzTableRow -table $docuSignTimeStampTbl -PartitionKey "part1" -RowKey "lastRunEndCursor" -property @{"lastCursorValue"=""} -UpdateExisting
Add-AzTableRow -table $docuSignTimeStampTbl -PartitionKey "part2" -RowKey "endUserPosition" -property @{"endUserPositionValue"=""} -UpdateExisting
}
Else {
$docuSignTimeStampTbl = (Get-AzStorageTable -Name $storageAccountTableName -Context $storageAccountContext.Context).cloudTable
}
# retrieve the last execution values
$lastExeEndCursor = Get-azTableRow -table $docuSignTimeStampTbl -partitionKey "part1" -RowKey "lastRunEndCursor" -ErrorAction Ignore
$lastExeEndPos = Get-azTableRow -table $docuSignTimeStampTbl -partitionKey "part2" -RowKey "endUserPosition" -ErrorAction Ignore
$lastRunEndCursorValue = $lastExeEndCursor.lastCursorValue
$startUserValue = [int]$lastExeEndPos.endUserPositionValue
if ($startUserValue -gt 0){
$startUserValue = $startUserValue + 1
}
$complete=$false
$iterations=0
DO{
$iterations++
try{
$docuSignMonitorAPI=$null
$monitorApiResponse = $null
$docuSignMonitorAPI = "https://$dsmHost.docusign.net/api/v2.0/datasets/monitor/stream?cursor=${lastRunEndCursorValue}&limit=2000"
Write-Output "Calling DocuSign Monitor API"
$monitorApiResponse = Invoke-RestMethod -Uri $docuSignMonitorAPI -Method 'GET' -Headers $docuSignAPIHeaders
# Display the data
Write-Output "Iteration:$iterations"
# Get the endCursor value from the response. This lets you resume
# getting records from the spot where this call left off
#Response from Invoke-RestMethod
$currentRunEndCursorValue = $monitorApiResponse.endCursor
Write-Output "currentRunEndCursorValue :$currentRunEndCursorValue"
Write-Output "Last run cursorValue : $lastRunEndCursorValue"
if (![string]::IsNullOrEmpty($lastRunEndCursorValue))
{
# If the endCursor from the response is the same as the one that you already have,
# it means that you have reached the end of the records
if ($currentRunEndCursorValue.Substring(0, $currentRunEndCursorValue.LastIndexOf('_')) -eq $lastRunEndCursorValue.Substring(0, $lastRunEndCursorValue.LastIndexOf('_')))
{
Write-Output 'Current run endCursor & last run endCursor values are the same. This indicates that you have reached the end of your available records.'
$complete=$true
}
}
if(!$complete){
Write-Output "Updating the cursor value of $lastRunEndCursorValue to the new value of $currentRunEndCursorValue"
$lastRunEndCursorValue=$currentRunEndCursorValue
$securityEvents = $monitorApiResponse.data
$securityEventsCount = $monitorApiResponse.data.length
$postReturnCode = SendToLogA -EventsData $securityEvents -EventsTable $LATableDSMAPI
$securityEventsCount = $monitorApiResponse.data.length
if($postReturnCode -eq 200)
{
Write-Output ("$securityEventsCount - DocuSign Security Events have been ingested into Azure Log Analytics Workspace Table --> $LATableDSMAPI")
}
Remove-Item $monitorApiResponse
Add-AzTableRow -table $docuSignTimeStampTbl -PartitionKey "part1" -RowKey "lastRunEndCursor" -property @{"lastCursorValue"=$lastRunEndCursorValue} -UpdateExisting
Start-Sleep -Second 5
}
}
catch{
$int = 0
foreach($header in $_.Exception.Response.Headers){
if($header -eq "X-DocuSign-TraceToken"){ write-host "TraceToken : " $_.Exception.Response.Headers[$int]}
$int++
}
write-host "Error : $_.ErrorDetails.Message"
write-host "Command : $_.InvocationInfo.Line"
$complete = $true
}
} While ($complete -eq $false )
#users Export
if ($DocuSignUsersIngestion.ToLower() -eq "true"){
Write-Host "Ingesting DocuSign Users information to $LATableDSUsers"
try{
$docuSignUsersAPI = $null
$userApiResponse = $null
$docuSignUsersAPI = "$DocuSignUserInfoBaseURI/restapi/v2.1/accounts/$DocuSignAccountAPIID/users?additional_info=true&start_position=$startUserValue"
Write-Output "Calling DocuSign Users API"
$userApiResponse = Invoke-RestMethod -Uri $docuSignUsersAPI -Method 'GET' -Headers $docuSignAPIHeaders
$userEndPosition = $userApiResponse.endPosition
$docuSignUsers = $userApiResponse.users
$totalUsers = $userApiResponse.totalSetSize
Write-Output "Total DocuSign Users $totalUsers"
Write-Output "Updating endPosition for users value $startUserValue to the new value of $userEndPosition"
$startUserValue=$userEndPosition
$postReturnCode = SendToLogA -EventsData $docuSignUsers -EventsTable $LATableDSUsers
if($postReturnCode -eq 200)
{
Write-Host ("$totalUsers users have been ingested into Azure Log Analytics Workspace Table $LATableDSUsers")
}
Remove-Item $userApiResponse
Add-AzTableRow -table $docuSignTimeStampTbl -PartitionKey "part2" -RowKey "endUserPosition" -property @{"endUserPositionValue"=$startUserValue.ToString()} -UpdateExisting
}
catch {
$int = 0
foreach($header in $_.Exception.Response.Headers){
if($header -eq "X-DocuSign-TraceToken"){ write-host "TraceToken : " $_.Exception.Response.Headers[$int]}
$int++
}
write-host "Error : $_.ErrorDetails.Message"
write-host "Command : $_.InvocationInfo.Line"
}
}
Remove-Item $privateKeyPath -Force
Write-Output "Done."
}
catch {
$int = 0
foreach($header in $_.Exception.Response.Headers){
if($header -eq "X-DocuSign-TraceToken")
{ write-host "TraceToken : " $_.Exception.Response.Headers[$int]}
$int++
}
write-host "Error : $_.ErrorDetails.Message"
write-host "Command : $_.InvocationInfo.Line"
}
Write-Output "Done."

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

@ -0,0 +1,15 @@
## 2.0
- Added CHANGELOG.MD to track future code changes
- Re-designed architecture of the Data connector
- Implemented logic to generate JWT Token and then get Access Token to interact with DocuSign API
- Implemented logic to ingest DocuSign Users into Log Analytics Table
- Added logic to update base uri to retrive users using Environment Variable
- Created single ARM Template to support both Azure Commerical & Azure Gov (.US) Tenants
- Updated README.MD
## 1.0
- Ingesting DocuSign Security Events into Azure Log Analytics Workspace
- Using DocuSign Access Token to interact with DocuSign Monitor API
- Access Token expires every 1 hr
- Updated "function.json" inorder to accept TimeTrigger(CRON Expression) from Function App environment variable. Providing more flexibility to the user to change schedule to trigger Function App

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

@ -1,3 +0,0 @@
[
{"org": ""}
]

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

@ -1,7 +0,0 @@
[
{
"org": "",
"lastRunEndCursor": "",
"lastRun": ""
}
]

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

@ -1,111 +1,96 @@
# Ingest DocuSign Security Events
Author: Sreedhar Ande
DocuSign-SecurityEvents Data connector ingests security events for your DocuSign account into Azure Log Analytics Workspace using DocuSign Monitor REST API
DocuSign-SecurityEvents Data connector ingests
1. Security Events for your DocuSign account into Azure Log Analytics Workspace using DocuSign Monitor REST API
2. DocuSign Account Users into Azure Log Analytics Workspace using DocuSign Users REST API
Following are the configuration steps to deploy Data connector.
Technical Blog
https://techcommunity.microsoft.com/t5/azure-sentinel/protecting-your-docusign-agreements-with-azure-sentinel/ba-p/2085502
**Note**
Above API's resumes getting records from the spot where the previous call left off to avoid duplication of records in DocuSignSecurityEvents_CL and DocuSignUsers_CL Log Analytics Workspace custom tables
## **Pre-requisites**
1. Obtain DocuSign OAuth Token
Option #1
DocuSign OAuth Token is required. See the documentation to obtain https://developers.docusign.com/platform/auth/jwt/jwt-get-token/
1. Login to your DocuSign Account
2. To create new "Integration Key", click on "Add & Integration Key"
![IntegrationKey](./images/2IntegrationKey.png)
3. Youll see a dialog box to enter your app name. Give your app a short, but descriptive name, such as "Azure Sentinel Integration"
4. Select ADD to add your app. Your app is automatically assigned an integration key (GUID) value that cannot be changed, as shown here
![AppAzSentinelIntegration](./images/AppAzSentinelIntegration.png)
5. Under Authentication, Select "Authorization Code Grant" as Azure Sentinel Data Connector uses JWT Grant Flow to get "Access Token" to communicate with DocuSign Monitor API and Users API
6. Select ADD SECRET KEY, which creates a new, automatically generated GUID value that represents a secret key
**Note**
Copy the secret key to a safe location by selecting the copy icon shown in the image.After your integration settings are saved, secret keys are masked for security reasons and cannot be revealed again. If you dont copy them first, your only option will be to delete the secret key in question and add a new one.
7. Set a redirect URI for your app which DocuSign will redirect the browser after authentication when using the Authorization Code Grant.
Option #2
1. https://apiexplorer.docusign.com/
2. Authenticate using your credentials
3. Select any API end point and click on "Send Request"
4. If you receive "Success" response - copy the Authorization Bearer token (token only without Bearer prefix)
8. Under Additional Settings, Select "ADD URI", which displays a new text box for you to enter the URI add in the following **redirect uri** `http://localhost:8080/authorization-code/callback` where your authenticated users will be redirected.
2. Copy two json files (ORGS.json and lastrun-Monitor.json) from Function Dependencies folder to your local drive
3. Edit the ORGS.json file and update "org": "sampleorg" and replace sample org with your org name.
```
If you have single org
[
{
"org": "sampleorg1"
}
]
9. RSA key pair is required to use the JWT Grant authentication flow. To generate navigate to Service Integration, Click on "ADD RSA KEYPAIR", which creates a new, automatically generated GUID value that represents the ID for the private and public key pair
**Note:**
You are only able to view your RSA key pair immediately after creating it, so be sure to save it or record it to a safe place. To ensure the key pairs security, there is no way to go back and view it again after you close the window.
If you have multiple org's
[
{
"org": "sampleorg1"
},
{
"org": "sampleorg2"
},
{
"org": "sampleorg3"
}
]
```
10. **Important** Copy the **private_key** into the file **"DocuSignRSAPrivateKey.key"** If you dont copy them first, your only option will be to delete the RSA key pair and add a new one. Select OK, then select SAVE.
![RSAKeyPair](./images/RSAKeyPair.png)
4. Edit lastrun-Monitor.json and update "org": "sampleorg" and replace sample org with your org name
### Request Application Consent
```
If you have single org
1. Run **[Application_Consent.ps1.](./Application_Consent.ps1)** and provide values for the following
```
DocuSignEnvironment: Enter value as Developer or Production
IntegrationKey: Enter DocuSign App Integration Key
```
2. Script will construct a URI value matching the "DocuSignEnvironment". This path differs depending on whether your app is in the development environment or in production.
For the developer demo environment, the base URI is https://account-d.docusign.com/oauth/auth
For the production platform, the base URI is https://account.docusign.com/oauth/auth
[
{
"org": "sampleorg1",
"lastRunEndCursor": "",
"lastRun": ""
}
]
3. Script will prompt you to log in to your DocuSign account and be presented with a request to grant signature and impersonation permissions to your app, as shown by the screenshot.
If you have multiple org's
4. Click on Accept, After you grants permission, youll be able to use the OAuth JWT Grant flow to impersonate that user and make API calls.
![consent](./images/consent.png)
[
{
"org": "sampleorg1",
"lastRunEndCursor": "",
"lastRun": ""
},
{
"org": "sampleorg2",
"lastRunEndCursor": "",
"lastRun": ""
}
]
```
**Note**
Its only one-time step to collect consent
## Deploy the Function App template
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FDataConnectors%2FDocuSign-SecurityEvents%2Fazuredeploy_dotcomtenants.json" target="_blank">
<img src="https://aka.ms/deploytoazurebutton"/>
</a>
<a href="https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FDataConnectors%2FDocuSign-SecurityEvents%2Fazuredeploy_dotgovtenants.json" target="_blank">
<img src="https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazuregov.png"/>
</a>
## Configuration Steps to Deploy Function App
1. Click on Deploy to Azure/Deploy to Azure Gov button
1. Click on Deploy to Azure (For both Commercial & Azure GOV)
<a href="https://aka.ms/sentinel-docusignconnector-azuredeploy" target="_blank">
<img src="https://aka.ms/deploytoazurebutton"/>
</a>
2. Select the preferred **Subscription**, **Resource Group** and **Location**
**Note**
Best practice : Create new Resource Group while deploying - all the resources of your custom Data connector will reside in the newly created Resource
Group
3. Enter the following value in the ARM template deployment
```
"DocuSignAccessToken": This is the DocuSign OAuth Token
"DocuSign Integration Key": DocuSign App Integration Key
"DocuSignAdminUserGUID" : Admin User Name GUID
"DocuSignAccountAPIID" : DocuSign Account API ID
"Workspace Id": Azure Log Analytics Workspace Id
"Workspace Key": Azure Log Analytics Workspace Key
"CustomLogTableName": Azure Log Analytics Custom Log Table Name
"Function Schedule": The `TimerTrigger` makes it incredibly easy to have your functions executed on a schedule. The default **Time Interval** is set to pull
the last ten (10) minutes of data.
```
## Post Deployment Steps
1. After successful deployment go to your Resource Group and search for storage account, named - `docusign<<uniqueid>>` and upload previously edited json files under "docusign-monitor" container
```
ORGS.json
lastrun-Monitor.json
```
1. **Important**
After successful deployment, Navigate to Resource Group and search for storage account, named - `<<FunctionAppName>><<uniqueid>>` and upload previously saved file **"DocuSignRSAPrivateKey.key"** to "docusign-monitor" container
2. DocuSignAccessToken and Workspace Key will be placed as "Secrets" in the Azure KeyVault `docusignkv<<uniqueid>>` with only Azure Function access policy. If you want to see/update these secrets,
2. DocuSignIntegrationKey, DocuSignAdminUserGUID, DocuSignAccountID and Workspace Key will be placed as "Secrets" in the Azure KeyVault `<<FunctionAppName>><<uniqueid>>` with only Azure Function access policy. If you want to see/update these secrets,
```
a. Go to Azure KeyVault "docusignkv<<uniqueid>>"
a. Go to Azure KeyVault "<<FunctionAppName>><<uniqueid>>"
b. Click on "Access Policies" under Settings
c. Click on "Add Access Policy"
i. Configure from template : Secret Management
@ -115,34 +100,74 @@ Following are the configuration steps to deploy Data connector.
d. Click "Save"
```
After granting permissions, If you want to update/change value for any Secrets
** Step 1 : Update existing Secret Value **
```
a. Go to Azure KeyVault "<<FunctionAppName>><<uniqueid>>"
b. Click on "Secrets" and select "Secret Name"
c. Click on "New Version" to create a new version of the existing secret.
d. Copy "Secret Identifier"
```
** Step 2 : Update KeyVault Reference in Azure Function **
```
a. Go to your Resource Group --> Click on Function App `<<FunctionAppName>><<uniqueid>>`
b. Click on Function App "Configuration" under Settings
c. Click on envionment variable that has value in KeyVault under "Application Settings"
d. Update value @Microsoft.KeyVault(SecretUri=<<Step 1 copied Secret Identifier URI>>).
e. Before clicking OK, make sure the status is "Resolved"
```
3. 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 the time interval needs to be modified, it is recommended to change the Function App Timer Trigger accordingly update environment variable **"Schedule**" (post deployment) to prevent overlapping data ingestion.
3. The `TimerTrigger` makes it incredibly easy to have your functions executed on a schedule. The default **Time Interval** is set to pull the last ten (10) minutes of data. If the time interval needs to be modified, it is recommended to change the Function App Timer Trigger accordingly update environment variable **"Schedule**" to prevent overlapping data ingestion.
```
a. Go to your Resource Group --> Click on Function App `docusign<<uniqueid>>`
a. Go to your Resource Group --> Click on Function App `<<FunctionAppName>><<uniqueid>>`
b. Click on Function App "Configuration" under Settings
c. Click on "Schedule" under "Application Settings"
d. Update your own schedule using cron expression.
```
**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 10 minutes is `0 */10 * * * *`. This, in plain text, means: "When seconds is equal to 0, minutes is divisible by 10, for any hour, day of the month, month, day of the week, or year".**
4. Verify Temp folder path
```
a. Go to your Resource Group --> Click on Function App `docusign<<uniqueid>>`
b. Click on "Advanced Tools" under Development Tools
c. Click on Go --> You will be redirected to Web App --> Check Temp folder path.
d. It can be either C:\local\Temp\ or D:\local\Temp\.
```
5. After finding Temp folder path
```
a. Go to your Resource Group --> Click on Function App `docusign<<uniqueid>>`
b. Click on "Configuration" under Settings
c. Click on "TMPDIR" under "Application Settings"
d. Update Drive (C//D) based on your findings from Step 9.
```
**Note: Make sure the value in "TMPDIR" doesnt have "\\" at the end.**
4. To target your DocuSign Environment, Update the Environment Variable "DocuSignEnvironment"
```
a. Go to your Resource Group --> Click on Function App `<<FunctionAppName>><<uniqueid>>`
b. Click on Function App "Configuration" under Settings
c. Click on "DocuSignEnvironment" under "Application Settings"
d. By Default its "Developer". Update your target environment
Ex: Developer or Production`
6. **For Azure Gov customers only**, You will see additional environment variable "Azure Tenant" under "Configuration" --> "Application Settings" and its default
value is ".us"
```
5. You can Switch On/Off DocuSign Users Ingestion using "NeedDocuSignUsers" boolean Environment Variable
```
a. Go to your Resource Group --> Click on Function App `<<FunctionAppName>><<uniqueid>>`
b. Click on Function App "Configuration" under Settings
c. Click on "NeedDocuSignUsers" under "Application Settings"
d. By default its "True", you can set it "False" if you dont want DocuSign Users information into your LA Workspace
Currently this Function App supports "Azure Gov(.US)" tenants
Ex: https://portal.azure.us
```
6. To interact with DocuSign UserInfo API, Update the Environment Variable "DocuSignUserInfoBaseURI" with baseuri
```
a. Go to your Resource Group --> Click on Function App `<<FunctionAppName>><<uniqueid>>`
b. Click on Function App "Configuration" under Settings
c. Click on "DocuSignUserInfoBaseURI" under "Application Settings"
d. By Default its "https://demo.docusign.net" targeting Demo envionment `
```
7. You can edit/update LA Table Name for DocuSign SecurityEvents
```
a. Go to your Resource Group --> Click on Function App `<<FunctionAppName>><<uniqueid>>`
b. Click on Function App "Configuration" under Settings
c. Click on "LATableDSMAPI" under "Application Settings"
d. By default its "DocuSignSecurityEvents"
```
8. You can edit/update LA Table Name for DocuSign Users
```
a. Go to your Resource Group --> Click on Function App `<<FunctionAppName>><<uniqueid>>`
b. Click on Function App "Configuration" under Settings
c. Click on "LATableDSUsers" under "Application Settings"
d. By default its "DocuSignUsers"
```

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

@ -9,11 +9,25 @@
"description": "Specifies the name of the Function App."
}
},
"DocuSignAccessToken": {
"defaultValue": "Enter the DocuSign OAuth Token",
"DocuSignIntegrationKey": {
"defaultValue": "Enter the DocuSign Integration Key",
"type": "string",
"metadata": {
"description": "Specifies DocuSign OAuth Token."
"description": "Specifies DocuSign Integration Key."
}
},
"DocuSignAdminUserGUID": {
"defaultValue": "Enter the DocuSign Admin User GUID",
"type": "string",
"metadata": {
"description": "Specifies DocuSign Admin User GUID"
}
},
"DocuSignAccountAPIID": {
"defaultValue": "Enter the DocuSign Account ID",
"type": "string",
"metadata": {
"description": "Specifies DocuSign Account ID"
}
},
"WorkspaceId": {
@ -29,28 +43,19 @@
"metadata": {
"description": "Specifies the Azure Log Analytics Workspace Key."
}
},
"CustomLogTableName": {
"type": "string",
"defaultValue": "DocuSignSecurityEvents",
"metadata": {
"description": "Specifies the Azure Log Analytics Custom Log Table Name."
}
},
"FunctionSchedule": {
"type": "string",
"defaultValue": "0 */10 * * * *",
"metadata": {
"description": "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 1 hour is `0 0 * * * *`. 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"
}
}
}
},
"variables": {
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]",
"KeyVaultName": "[tolower(concat('docusignkv', uniqueString(resourceGroup().id, subscription().id)))]",
"DocuSignOAuthToken": "DocuSignOAuthToken",
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id), uniqueString(subscription().id))]",
"StorageAccountName":"[concat(substring(variables('FunctionName'), 0, 20), 'sa')]",
"KeyVaultName": "[concat(substring(variables('FunctionName'), 0, 20), 'kv')]",
"DocuSignIntegrationKey": "DocuSignIntegrationKey",
"DocuSignAdminUserGUID" : "DocuSignAdminUserGUID",
"DocuSignAccountAPIID" : "DocuSignAccountAPIID",
"LogAnalyticsWorkspaceKey": "LogAnalyticsWorkspaceKey",
"StorageContainerName": "docusign-monitor"
"StorageContainerName": "docusign-monitor",
"StorageSuffix":"[environment().suffixes.storage]",
"LogAnaltyicsUri":"[replace(environment().portal, 'https://portal', concat('https://', toLower(parameters('WorkspaceId')), '.ods.opinsights'))]"
},
"resources": [
{
@ -67,7 +72,7 @@
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[tolower(variables('FunctionName'))]",
"name": "[variables('StorageAccountName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS",
@ -119,9 +124,9 @@
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"name": "[concat(variables('StorageAccountName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('StorageAccountName')))]"
],
"sku": {
"name": "Standard_LRS",
@ -140,9 +145,9 @@
{
"type": "Microsoft.Storage/storageAccounts/fileServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"name": "[concat(variables('StorageAccountName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('StorageAccountName')))]"
],
"sku": {
"name": "Standard_LRS",
@ -161,7 +166,7 @@
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]",
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('StorageAccountName')))]",
"[resourceId('Microsoft.Web/serverfarms', variables('FunctionName'))]",
"[resourceId('Microsoft.Insights/components', variables('FunctionName'))]"
],
@ -174,33 +179,44 @@
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('FunctionName'))]",
"httpsOnly": true,
"clientAffinityEnabled": true,
"alwaysOn": true
"alwaysOn": true,
"siteConfig": {
"powerShellVersion": "~7"
}
},
"resources": [
{
"apiVersion": "2018-11-01",
"type": "config",
"name": "appsettings",
"name": "appsettings",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('FunctionName'))]",
"[resourceId('Microsoft.KeyVault/vaults/', variables('KeyVaultName'))]",
"[resourceId('Microsoft.KeyVault/vaults/secrets', variables('KeyVaultName'), variables('DocuSignOAuthToken'))]",
"[resourceId('Microsoft.KeyVault/vaults/secrets', variables('KeyVaultName'), variables('DocuSignIntegrationKey'))]",
"[resourceId('Microsoft.KeyVault/vaults/secrets', variables('KeyVaultName'), variables('DocuSignAdminUserGUID'))]",
"[resourceId('Microsoft.KeyVault/vaults/secrets', variables('KeyVaultName'), variables('DocuSignAccountAPIID'))]",
"[resourceId('Microsoft.KeyVault/vaults/secrets', variables('KeyVaultName'), variables('LogAnalyticsWorkspaceKey'))]"
],
"properties": {
"FUNCTIONS_EXTENSION_VERSION": "~3",
"FUNCTIONS_WORKER_RUNTIME": "powershell",
"FUNCTIONS_WORKER_RUNTIME": "powershell",
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.insights/components', variables('FunctionName')), '2015-05-01').InstrumentationKey]",
"APPLICATIONINSIGHTS_CONNECTION_STRING": "[reference(resourceId('microsoft.insights/components', variables('FunctionName')), '2015-05-01').ConnectionString]",
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=core.windows.net')]",
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=core.windows.net')]",
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('StorageAccountName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('StorageAccountName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]",
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('StorageAccountName')),';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('StorageAccountName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]",
"WEBSITE_CONTENTSHARE": "[toLower(variables('FunctionName'))]",
"DocuSignOAuthAccessToken": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('DocuSignOAuthToken')).secretUriWithVersion, ')')]",
"TMPDIR": "D:\\local\\Temp",
"DocuSignIntegrationKey": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('DocuSignIntegrationKey')).secretUriWithVersion, ')')]",
"DocuSignAdminUserGUID": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('DocuSignAdminUserGUID')).secretUriWithVersion, ')')]",
"DocuSignAccountAPIID": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('DocuSignAccountAPIID')).secretUriWithVersion, ')')]",
"WorkspaceId": "[parameters('WorkspaceId')]",
"WorkspaceKey": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('LogAnalyticsWorkspaceKey')).secretUriWithVersion, ')')]",
"Schedule": "[parameters('FunctionSchedule')]",
"CustomLogTableName": "[parameters('CustomLogTableName')]",
"Schedule": "0 */10 * * * *",
"LATableDSMAPI": "DocuSignSecurityEvents",
"LATableDSUsers": "DocuSignUsers",
"DocuSignEnvironment": "Developer",
"NeedDocuSignUsers":"True",
"LAURI": "[variables('LogAnaltyicsUri')]",
"DocuSignUserInfoBaseURI" : "https://demo.docusign.net",
"WEBSITE_RUN_FROM_PACKAGE": "https://github.com/Azure/Azure-Sentinel/blob/master/DataConnectors/DocuSign-SecurityEvents/AzureFunctionDocuSignMonitor/DocuSignMonitorTimerTrigger.zip?raw=true"
}
}
@ -240,18 +256,48 @@
{
"type": "secrets",
"apiVersion": "2016-10-01",
"name": "[variables('DocuSignOAuthToken')]",
"name": "[variables('DocuSignIntegrationKey')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/', variables('KeyVaultName'))]"
],
"properties": {
"value": "[parameters('DocuSignAccessToken')]",
"value": "[parameters('DocuSignIntegrationKey')]",
"contentType": "string",
"attributes": {
"enabled": true
}
}
},
},
{
"type": "secrets",
"apiVersion": "2016-10-01",
"name": "[variables('DocuSignAdminUserGUID')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/', variables('KeyVaultName'))]"
],
"properties": {
"value": "[parameters('DocuSignAdminUserGUID')]",
"contentType": "string",
"attributes": {
"enabled": true
}
}
},
{
"type": "secrets",
"apiVersion": "2016-10-01",
"name": "[variables('DocuSignAccountAPIID')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/', variables('KeyVaultName'))]"
],
"properties": {
"value": "[parameters('DocuSignAccountAPIID')]",
"contentType": "string",
"attributes": {
"enabled": true
}
}
},
{
"type": "secrets",
"apiVersion": "2016-10-01",
@ -269,26 +315,13 @@
}
]
},
{
"type": "Microsoft.Web/sites/hostNameBindings",
"apiVersion": "2018-11-01",
"name": "[concat(variables('FunctionName'), '/', variables('FunctionName'), '.azurewebsites.net')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('FunctionName'))]"
],
"properties": {
"siteName": "[variables('FunctionName')]",
"hostNameType": "Verified"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-hosts')]",
"name": "[concat(variables('StorageAccountName'), '/default/azure-webjobs-hosts')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('StorageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]"
],
"properties": {
"publicAccess": "None"
@ -297,10 +330,10 @@
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-secrets')]",
"name": "[concat(variables('StorageAccountName'), '/default/azure-webjobs-secrets')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('StorageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]"
],
"properties": {
"publicAccess": "None"
@ -309,10 +342,10 @@
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), concat('/default/', variables('StorageContainerName')))]",
"name": "[concat(variables('StorageAccountName'), concat('/default/', variables('StorageContainerName')))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('StorageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]"
],
"properties": {
"publicAccess": "None"
@ -321,10 +354,10 @@
{
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/', tolower(variables('FunctionName')))]",
"name": "[concat(variables('StorageAccountName'), '/default/', tolower(variables('StorageAccountName')))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
"[resourceId('Microsoft.Storage/storageAccounts/fileServices', variables('StorageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]"
],
"properties": {
"shareQuota": 5120

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

@ -1,335 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"FunctionName": {
"defaultValue": "DocuSign",
"type": "string",
"metadata": {
"description": "Specifies the name of the Function App."
}
},
"DocuSignAccessToken": {
"defaultValue": "Enter the DocuSign OAuth Token",
"type": "string",
"metadata": {
"description": "Specifies DocuSign OAuth Token."
}
},
"WorkspaceId": {
"type": "string",
"defaultValue": "<WorkspaceId>",
"metadata": {
"description": "Specifies the Azure Log Analytics Workspace Id."
}
},
"WorkspaceKey": {
"type": "string",
"defaultValue": "<WorkspaceKey>",
"metadata": {
"description": "Specifies the Azure Log Analytics Workspace Key."
}
},
"CustomLogTableName": {
"type": "string",
"defaultValue": "DocuSignSecurityEvents",
"metadata": {
"description": "Specifies the Azure Log Analytics Custom Log Table Name."
}
},
"FunctionSchedule": {
"type": "string",
"defaultValue": "0 */10 * * * *",
"metadata": {
"description": "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 1 hour is `0 0 * * * *`. 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"
}
}
},
"variables": {
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]",
"KeyVaultName": "[tolower(concat('docusignkv', uniqueString(resourceGroup().id, subscription().id)))]",
"DocuSignOAuthToken": "DocuSignOAuthToken",
"LogAnalyticsWorkspaceKey": "LogAnalyticsWorkspaceKey",
"StorageContainerName": "docusign-monitor"
},
"resources": [
{
"type": "Microsoft.Insights/components",
"apiVersion": "2015-05-01",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"kind": "web",
"properties": {
"Application_Type": "web",
"ApplicationId": "[variables('FunctionName')]"
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[tolower(variables('FunctionName'))]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [
],
"ipRules": [
],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"keyType": "Account",
"enabled": true
},
"blob": {
"keyType": "Account",
"enabled": true
}
},
"keySource": "Microsoft.Storage"
}
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2018-02-01",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Y1",
"tier": "Dynamic"
},
"kind": "functionapp",
"properties": {
"name": "[variables('FunctionName')]",
"workerSize": "0",
"workerSizeId": "0",
"numberOfWorkers": "1"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"cors": {
"corsRules": [
]
},
"deleteRetentionPolicy": {
"enabled": false
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"cors": {
"corsRules": [
]
}
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]",
"[resourceId('Microsoft.Web/serverfarms', variables('FunctionName'))]",
"[resourceId('Microsoft.Insights/components', variables('FunctionName'))]"
],
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"name": "[variables('FunctionName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('FunctionName'))]",
"httpsOnly": true,
"clientAffinityEnabled": true,
"alwaysOn": true
},
"resources": [
{
"apiVersion": "2018-11-01",
"type": "config",
"name": "appsettings",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('FunctionName'))]",
"[resourceId('Microsoft.KeyVault/vaults/', variables('KeyVaultName'))]",
"[resourceId('Microsoft.KeyVault/vaults/secrets', variables('KeyVaultName'), variables('DocuSignOAuthToken'))]",
"[resourceId('Microsoft.KeyVault/vaults/secrets', variables('KeyVaultName'), variables('LogAnalyticsWorkspaceKey'))]"
],
"properties": {
"FUNCTIONS_EXTENSION_VERSION": "~3",
"FUNCTIONS_WORKER_RUNTIME": "powershell",
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.insights/components', variables('FunctionName')), '2015-05-01').InstrumentationKey]",
"APPLICATIONINSIGHTS_CONNECTION_STRING": "[reference(resourceId('microsoft.insights/components', variables('FunctionName')), '2015-05-01').ConnectionString]",
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=core.usgovcloudapi.net')]",
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=core.usgovcloudapi.net')]",
"WEBSITE_CONTENTSHARE": "[toLower(variables('FunctionName'))]",
"DocuSignOAuthAccessToken": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('DocuSignOAuthToken')).secretUriWithVersion, ')')]",
"TMPDIR": "D:\\local\\Temp",
"WorkspaceId": "[parameters('WorkspaceId')]",
"WorkspaceKey": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('LogAnalyticsWorkspaceKey')).secretUriWithVersion, ')')]",
"Schedule": "[parameters('FunctionSchedule')]",
"CustomLogTableName": "[parameters('CustomLogTableName')]",
"AZURE_TENANT": ".us",
"WEBSITE_RUN_FROM_PACKAGE": "https://github.com/Azure/Azure-Sentinel/blob/master/DataConnectors/DocuSign-SecurityEvents/AzureFunctionDocuSignMonitor/DocuSignMonitorTimerTrigger.zip?raw=true"
}
}
]
},
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2016-10-01",
"name": "[variables('KeyVaultName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('FunctionName'))]"
],
"properties": {
"sku": {
"family": "A",
"name": "Standard"
},
"tenantId": "[subscription().tenantId]",
"accessPolicies": [
{
"tenantId": "[subscription().tenantId]",
"objectId": "[reference(resourceId('Microsoft.Web/sites', variables('FunctionName')),'2019-08-01', 'full').identity.principalId]",
"permissions": {
"secrets": [ "get",
"list"
]
}
}
],
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": true,
"enableSoftDelete": true
},
"resources": [
{
"type": "secrets",
"apiVersion": "2016-10-01",
"name": "[variables('DocuSignOAuthToken')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/', variables('KeyVaultName'))]"
],
"properties": {
"value": "[parameters('DocuSignAccessToken')]",
"contentType": "string",
"attributes": {
"enabled": true
}
}
},
{
"type": "secrets",
"apiVersion": "2016-10-01",
"name": "[variables('LogAnalyticsWorkspaceKey')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/', variables('KeyVaultName'))]"
],
"properties": {
"value": "[parameters('WorkspaceKey')]",
"contentType": "string",
"attributes": {
"enabled": true
}
}
}
]
},
{
"type": "Microsoft.Web/sites/hostNameBindings",
"apiVersion": "2018-11-01",
"name": "[concat(variables('FunctionName'), '/', variables('FunctionName'), '.azurewebsites.us')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('FunctionName'))]"
],
"properties": {
"siteName": "[variables('FunctionName')]",
"hostNameType": "Verified"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-hosts')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-secrets')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), concat('/default/', variables('StorageContainerName')))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/', tolower(variables('FunctionName')))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"shareQuota": 5120
}
}
]
}

Двоичные данные
DataConnectors/DocuSign-SecurityEvents/images/2IntegrationKey.png Normal file

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

После

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

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

После

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

Двоичные данные
DataConnectors/DocuSign-SecurityEvents/images/RSAKeyPair.png Normal file

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

После

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

Двоичные данные
DataConnectors/DocuSign-SecurityEvents/images/consent.png Normal file

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

После

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

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

@ -44,7 +44,7 @@
}
],
"availability": {
"status": 1,
"status": 2,
"isPreview": true
},
"permissions": {

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

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

@ -1,11 +1,10 @@
<#
Title: GitHub Repo Logs Data Connector
Language: PowerShell
Version: 1.1
Version: 1.2
Author: Nicholas Dicola, Sreedhar Ande
Last Modified: 12/11/2020
Comment: Inital Release
Last Modified: 02/08/2021
DESCRIPTION
This Function App calls the GitHub REST API (https://api.github.com/) to pull the GitHub
Audit, Repo and Vulnerability logs. The response from the GitHub API is recieved in JSON format. This function will build the signature and authorization header
@ -38,8 +37,19 @@ $personalAccessToken = $env:PersonalAccessToken
$workspaceId = $env:WorkspaceId
$workspaceKey = $env:WorkspaceKey
$storageAccountContainer = "github-repo-logs"
$AuditLogTable = "GitHub_CL"
$RepoLogTable = "GitHubRepoLogs_CL"
$AuditLogTable = $env:GitHubAuditLogsTableName
if ([string]::IsNullOrEmpty($AuditLogTable))
{
$AuditLogTable = "GitHub_CL"
}
$RepoLogTable = $env:GitHubRepoLogsTableName
if ([string]::IsNullOrEmpty($RepoLogTable))
{
$RepoLogTable = "GitHubRepoLogs_CL"
}
#The AzureTenant variable is used to specify other cloud environments like Azure Gov(.us) etc.,
$AzureTenant = $env:AZURE_TENANT
@ -150,11 +160,11 @@ function Write-OMSLogfile {
$logdata | Add-Member -MemberType NoteProperty -Name "DateTime" -Value $dateTime
#Build the JSON file
$logMessage = ConvertTo-Json $logdata -Depth 20
$logMessage = ($logdata | ConvertTo-Json -Depth 20)
Write-Verbose -Message $logMessage
#Submit the data
$returnCode = PostLogAnalyticsData -CustomerID $CustomerID -SharedKey $SharedKey -Body ([System.Text.Encoding]::UTF8.GetBytes($logMessage)) -Type $type
$returnCode = PostLogAnalyticsData -CustomerID $CustomerID -SharedKey $SharedKey -Body $logMessage -Type $type
Write-Verbose -Message "Post Statement Return Code $returnCode"
return $returnCode
}
@ -250,7 +260,7 @@ foreach($org in $githubOrgs){
$results = Invoke-RestMethod -Method Post -Uri $uri -Body $AuditQuery -Headers $headers
if(($results.data.organization.auditLog.edges).Count -ne 0){
#write to log A to be added later
SendToLogA -gitHubData ($results.data.organization.auditLog.edges | Convertto-json -depth 20) -customLogName $AuditLogTable
SendToLogA -gitHubData ($results.data.organization.auditLog.edges) -customLogName $AuditLogTable
}
$hasNextPage = $results.data.organization.auditLog.pageInfo.hasNextPage
$lastRunContext.lastContext = $results.data.organization.auditLog.pageInfo.endCursor
@ -315,67 +325,81 @@ foreach($org in $githubOrgs){
$uri = "https://api.github.com/repos/$orgName/$repoName/traffic/popular/referrers"
$referrerLogs = $null
$referrerLogs = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers
$referrerLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$referrerLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$referrerLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Referrers
#Send to log A;
SendToLogA -gitHubData $referrerLogs -customLogName $RepoLogTable
if ($referrerLogs.Length -gt 0){
$referrerLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$referrerLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$referrerLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Referrers
#Send to log A;
SendToLogA -gitHubData $referrerLogs -customLogName $RepoLogTable
}
$uri = "https://api.github.com/repos/$orgName/$repoName/traffic/popular/paths"
$pathLogs = $null
$pathLogs = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers
$pathLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$pathLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$pathLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Paths
#Send to log A;
SendToLogA -gitHubData $pathLogs -customLogName $RepoLogTable
if ($pathLogs.Length -gt 0){
$pathLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$pathLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$pathLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Paths
#Send to log A;
SendToLogA -gitHubData $pathLogs -customLogName $RepoLogTable
}
$uri = "https://api.github.com/repos/$orgName/$repoName/traffic/views"
$viewLogs = $null
$viewLogs = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers
$viewLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$viewLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$viewLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Views
#Send to log A
SendToLogA -gitHubData $viewLogs -customLogName $RepoLogTable
if ($viewLogs.Length -gt 0){
$viewLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$viewLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$viewLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Views
#Send to log A
SendToLogA -gitHubData $viewLogs -customLogName $RepoLogTable
}
$uri = "https://api.github.com/repos/$orgName/$repoName/traffic/clones"
$cloneLogs = $null
$cloneLogs = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers
$cloneLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$cloneLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$cloneLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Clones
#Send to log A
SendToLogA -gitHubData $cloneLogs -customLogName $RepoLogTable
if ($cloneLogs.Length -gt 0){
$cloneLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$cloneLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$cloneLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Clones
#Send to log A
SendToLogA -gitHubData $cloneLogs -customLogName $RepoLogTable
}
$uri = "https://api.github.com/repos/$orgName/$repoName/commits"
$commitLogs = $null
$commitLogs = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers
$commitLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$commitLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$commitLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Commits
#Send to log A
SendToLogA -gitHubData $commitLogs -customLogName $RepoLogTable
if ($commitLogs.Length -gt 0){
$commitLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$commitLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$commitLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Commits
#Send to log A
SendToLogA -gitHubData $commitLogs -customLogName $RepoLogTable
}
$uri = "https://api.github.com/repos/$orgName/$repoName/collaborators"
$collaboratorLogs = $null
$collaboratorLogs = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers
$collaboratorLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$collaboratorLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$collaboratorLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Collaborators
#Send to log A
SendToLogA -gitHubData $collaboratorLogs -customLogName $RepoLogTable
if ($collaboratorLogs.Length -gt 0){
$collaboratorLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$collaboratorLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$collaboratorLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Collaborators
#Send to log A
SendToLogA -gitHubData $collaboratorLogs -customLogName $RepoLogTable
}
$uri = "https://api.github.com/repos/$orgName/$repoName/forks"
$forkLogs = $null
$forkLogs = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers
$forkLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$forkLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$forkLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Forks
#Send to log A
SendToLogA -gitHubData $forkLogs -customLogName $RepoLogTable
}
if ($forkLogs.Length -gt 0){
$forkLogs | Add-Member -NotePropertyName OrgName -NotePropertyValue $orgName
$forkLogs | Add-Member -NotePropertyName Repository -NotePropertyValue $repoName
$forkLogs | Add-Member -NotePropertyName LogType -NotePropertyValue Forks
#Send to log A
SendToLogA -gitHubData $forkLogs -customLogName $RepoLogTable
}
}
else {
Write-Host "$repoName is empty"
Write-Verbose "$repoName is empty"

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

@ -1,3 +1,9 @@
## 1.2
- Fixed issues raised on Sentinel GitHub Repo on AuditLogs
- Updated logic to ingest each AuditLog as an individual record
- Added two environment variables to provide additional support for users to supply their own values for Table names
- Pushing all these latest changes as in-place upgrade, if users dont create environment variables, it will use old tables
## 1.1
- Added CHANGELOG.MD to track future code changes
- Updated "lastrun-Audit.json" to support multiple org's

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

@ -29,7 +29,7 @@
"metadata": {
"description": "Specifies the Log Analytics Workspace Key."
}
},
},
"FunctionSchedule": {
"type": "string",
"defaultValue": "0 */10 * * * *",
@ -193,6 +193,8 @@
"WorkspaceId": "[parameters('WorkspaceId')]",
"WorkspaceKey": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('LogAnalyticsWorkspaceKey')).secretUriWithVersion, ')')]",
"Schedule": "[parameters('FunctionSchedule')]",
"GitHubAuditLogsTableName": "GitHubAuditLogs",
"GitHubRepoLogsTableName": "GitHubRepoLogs",
"WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/githubazurefunctionzip"
}
}

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

@ -193,7 +193,9 @@
"WorkspaceId": "[parameters('WorkspaceId')]",
"WorkspaceKey": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('LogAnalyticsWorkspaceKey')).secretUriWithVersion, ')')]",
"Schedule": "[parameters('FunctionSchedule')]",
"AZURE_TENANT": ".us",
"AZURE_TENANT": ".us",
"GitHubAuditLogsTableName": "GitHubAuditLogs",
"GitHubRepoLogsTableName": "GitHubRepoLogs",
"WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/githubazurefunctionzip"
}
}

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

@ -118,11 +118,29 @@ A GitHub API Token is required. See the documentation to learn more about the [G
```
**Note: Make sure the value in "TMPDIR" doesnt have "\\" at the end.**
10. **For Azure Gov customers only**, You will see additional environment variable "Azure Tenant" under "Configuration" --> "Application Settings" and its default value is ".us"
10. **[Previous Version (prior to 2/9/2021) deployed users only ]**. If you want to ingest GitHub Audit & Repo logs into New custom logs, follow the steps
```
a. Go to `githublogs<<uniqueid>>`
b. Click on "Configuration" under Settings
c. Click on "New Application Setting"
d. Name --> GitHubAuditLogsTableName.
e. Value --> <<Your preferred table name for GitHub Audit Logs, for example GitHubAuditLogs>>
f. Click on "Ok"
g. Click on "New Application Setting"
h. Name --> GitHubRepoLogsTableName.
i. Value --> <<Your preferred table name for GitHub Repo Logs, for example GitHubRepoLogs>>
j. Click on "Ok"
```
**Note**
If you don't create these new environment variable, then it will be ingested to default
Audit Logs --> GitHub_CL
Repo Logs --> GitHubRepoLogs_CL
11. **For Azure Gov customers only**, You will see additional environment variable "Azure Tenant" under "Configuration" --> "Application Settings" and its default value is ".us"
Currently this Function App supports "Azure Gov(.US)" tenants
Ex: https://portal.azure.us
Note: there are two parsers (here)[https://github.com/Azure/Azure-Sentinel/tree/master/Parsers/GitHubFunction] to make the logs useful
Note: there are two parsers (here)[https://github.com/Azure/Azure-Sentinel/blob/master/Parsers/GitHub] to make the logs useful
## Deploy the Function App template
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FDataConnectors%2FGithubFunction%2Fazurecomdeploy_dotcomtenants.json" target="_blank">

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

@ -0,0 +1,160 @@
{
"id": "NGINXHTTPServer",
"title": "NGINX HTTP Server",
"publisher": "Nginx",
"descriptionMarkdown": "NGINX HTTP Server data connector provides the capability to ingest [NGINX HTTP Server](https://nginx.org/en/) events into Azure Sentinel. Refer to [NGINX Logs documentation](https://nginx.org/en/docs/http/ngx_http_log_module.html) for more information.",
"additionalRequirementBanner": "This data connector depends on a parser based on Kusto Function to work as expected. Follow the steps to use this Kusto Function alias **NGINXHTTPServer** in queries and workbooks. [Follow steps to get this Kusto Function>](https://aka.ms/sentinel-NGINXHTTP-parser)",
"graphQueries": [
{
"metricName": "Total data received",
"legend": "NGINX_CL",
"baseQuery": "NGINXHTTPServer"
}
],
"sampleQueries": [
{
"description" : "Top 10 Clients (Source IP)",
"query": "NGINXHTTPServer\n | summarize count() by SrcIpAddr\n | top 10 by count_"
}
],
"dataTypes": [
{
"name": "NGINX_CL",
"lastDataReceivedQuery": "NGINXHTTPServer\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
}
],
"connectivityCriterias": [
{
"type": "IsConnectedQuery",
"value": [
"NGINXHTTPServer\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)"
]
}
],
"availability": {
"status": 1,
"isPreview": true
},
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "read and write permissions are required.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"read": true,
"write": true,
"delete": true
}
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {
"action": true
}
}
]
},
"instructionSteps": [
{
"title": "",
"description": ">**NOTE:** This data connector depends on a parser based on a Kusto Function to work as expected. [Follow these steps](https://aka.ms/sentinel-NGINXHTTP-parser) to create the Kusto Functions alias, **NGINXHTTPServer**",
"instructions": [
]
},
{
"title": "1. Install and onboard the agent for Linux or Windows",
"description": "Install the agent on the NGINX HTTP Server where the logs are generated.\n\n> Logs from NGINX HTTP Server deployed on Linux or Windows servers are collected by **Linux** or **Windows** agents.",
"instructions": [
{
"parameters": {
"title": "Choose where to install the Linux agent:",
"instructionSteps": [
{
"title": "Install agent on Azure Linux Virtual Machine",
"description": "Select the machine to install the agent on and then click **Connect**.",
"instructions": [
{
"parameters": {
"linkType": "InstallAgentOnLinuxVirtualMachine"
},
"type": "InstallAgent"
}
]
},
{
"title": "Install agent on a non-Azure Linux Machine",
"description": "Download the agent on the relevant machine and follow the instructions.",
"instructions": [
{
"parameters": {
"linkType": "InstallAgentOnLinuxNonAzure"
},
"type": "InstallAgent"
}
]
}
]
},
"type": "InstructionStepsGroup"
}
]
},
{
"instructions": [
{
"parameters": {
"title": "Choose where to install the Windows agent:",
"instructionSteps": [
{
"title": "Install agent on Azure Windows Virtual Machine",
"description": "Select the machine to install the agent on and then click **Connect**.",
"instructions": [
{
"parameters": {
"linkType": "InstallAgentOnVirtualMachine"
},
"type": "InstallAgent"
}
]
},
{
"title": "Install agent on a non-Azure Windows Machine",
"description": "Download the agent on the relevant machine and follow the instructions.",
"instructions": [
{
"parameters": {
"linkType": "InstallAgentOnNonAzure"
},
"type": "InstallAgent"
}
]
}
]
},
"type": "InstructionStepsGroup"
}
]
},
{
"title": "2. Configure the logs to be collected",
"description": "Configure the custom log directory to be collected" ,
"instructions": [
{
"parameters": {
"linkType": "OpenAdvancedWorkspaceSettings"
},
"type": "InstallAgent"
}
]
},
{
"title": "",
"description":"1. Select the link above to open your workspace advanced settings \n2. From the left pane, select **Data**, select **Custom Logs** and click **Add+**\n3. Click **Browse** to upload a sample of a NGINX HTTP Server log file (e.g. access.log or error.log). Then, click **Next >**\n4. Select **New line** as the record delimiter and click **Next >**\n5. Select **Windows** or **Linux** and enter the path to NGINX HTTP logs based on your configuration. Example: \n - **Linux** Directory: '/var/log/nginx/*.log' \n6. After entering the path, click the '+' symbol to apply, then click **Next >** \n7. Add **NGINX_CL** as the custom log Name and click **Done**"
}
]
}

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

@ -39,7 +39,7 @@
}
],
"availability": {
"status": 1,
"status": 2,
"isPreview": true
},
"permissions": {
@ -57,7 +57,7 @@
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key)",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {

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

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

@ -52,6 +52,7 @@ $TotalRecordCount = 0
$apiToken = $env:apiToken
$uri = $env:uri
$StartDate = [System.DateTime]::UtcNow.ToString("yyyy-MM-ddT00:00:00.000Z") # set default fallback start time to 0:00 UTC today
$logAnalyticsUri = $env:logAnalyticsUri
# Define the Log Analytics Workspace ID and Key and Custom Table Name
$customerId = $env:workspaceId
@ -59,6 +60,17 @@ $sharedKey = $env:workspaceKey
$LogType = "Okta"
$TimeStampField = "published"
if ([string]::IsNullOrEmpty($logAnalyticsUri))
{
$logAnalyticsUri = "https://" + $customerId + ".ods.opinsights.azure.com"
}
# Returning if the Log Analytics Uri is in incorrect format.
# Sample format supported: https://" + $customerId + ".ods.opinsights.azure.com
if($logAnalyticsUri -notmatch 'https:\/\/([\w\-]+)\.ods\.opinsights\.azure.([a-zA-Z\.]+)$')
{
throw "OKTASSO: Invalid Log Analytics Uri."
}
# Retrieve Timestamp from last records received from Okta
# Check if Tabale has already been created and if not create it to maintain state between executions of Function
@ -144,14 +156,15 @@ do {
-method $method `
-contentType $contentType `
-resource $resource
$LAuri = "https://" + $customerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01"
$logAnalyticsUri = $logAnalyticsUri + $resource + "?api-version=2016-04-01"
$LAheaders = @{
"Authorization" = $signature;
"Log-Type" = $logType;
"x-ms-date" = $rfc1123date;
"time-generated-field" = $TimeStampField
}
$result = Invoke-WebRequest -Uri $LAuri -Method $method -ContentType $contentType -Headers $LAheaders -Body $body -UseBasicParsing
$result = Invoke-WebRequest -Uri $logAnalyticsUri -Method $method -ContentType $contentType -Headers $LAheaders -Body $body -UseBasicParsing
#update State table for next time we execute function
#store details in function storage table to retrieve next time function runs
$result = Add-AzTableRow -table $Table -PartitionKey "part1" -RowKey $apiToken -property @{"uri"=$uri} -UpdateExisting

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

@ -1,6 +1,6 @@
{
"id": "OktaSSO",
"title": "Okta Single Sign-On (Preview)",
"title": "Okta Single Sign-On",
"publisher": "Okta",
"descriptionMarkdown": "The [Okta Single Sign-On (SSO)](https://www.okta.com/products/single-sign-on/) connector provides the capability to ingest audit and event logs from the Okta API into Azure Sentinel. The connector provides visibility into these log types in Azure Sentinel to view dashboards, create custom alerts, and to improve monitoring and investigation capabilities.",
"graphQueries": [
@ -42,7 +42,7 @@
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "read and write permissions are required.",
"permissionsDisplayText": "read and write permissions on the workspace are required.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
@ -53,7 +53,7 @@
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key)",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {
@ -131,7 +131,7 @@
},
{
"title": "",
"description": "**3. Configure the Function App**\n\n1. In the Function App, select the Function App Name and select **Configuration**.\n2. In the **Application settings** tab, select **+ New application setting**.\n3. Add each of the following four (4) application settings individually, with their respective string values (case-sensitive): \n\t\tapiToken\n\t\tworkspaceID\n\t\tworkspaceKey\n\t\turi\n - Use the following schema for the `uri` value: `https://<OktaDomain>/api/v1/logs?since=` Replace `<OktaDomain>` with your domain. [Click here](https://developer.okta.com/docs/reference/api-overview/#url-namespace) for further details on how to identify your Okta domain namespace. There is no need to add a time value to the URI, the Function App will dynamically append the inital start time of logs to UTC 0:00 for the current UTC date as time value to the URI in the proper format.\n - Note: If using Azure Key Vault secrets for any of the values above, use the`@Microsoft.KeyVault(SecretUri={Security Identifier})`schema in place of the string values. Refer to [Key Vault references documentation](https://docs.microsoft.com/azure/app-service/app-service-key-vault-references) for further details. \n4. Once all application settings have been entered, click **Save**."
"description": "**3. Configure the Function App**\n\n1. In the Function App, select the Function App Name and select **Configuration**.\n2. In the **Application settings** tab, select **+ New application setting**.\n3. Add each of the following five (5) application settings individually, with their respective string values (case-sensitive): \n\t\tapiToken\n\t\tworkspaceID\n\t\tworkspaceKey\n\t\turi\n\t\tlogAnalyticsUri (optional)\n - Use the following schema for the `uri` value: `https://<OktaDomain>/api/v1/logs?since=` Replace `<OktaDomain>` with your domain. [Click here](https://developer.okta.com/docs/reference/api-overview/#url-namespace) for further details on how to identify your Okta domain namespace. There is no need to add a time value to the URI, the Function App will dynamically append the inital start time of logs to UTC 0:00 for the current UTC date as time value to the URI in the proper format.\n - Note: If using Azure Key Vault secrets for any of the values above, use the`@Microsoft.KeyVault(SecretUri={Security Identifier})`schema in place of the string values. Refer to [Key Vault references documentation](https://docs.microsoft.com/azure/app-service/app-service-key-vault-references) for further details.\n - Use logAnalyticsUri to override the log analytics API endpoint for delegated cloud. For example, for public cloud, leave the value empty; for Azure GovUS cloud environment, specify the value in the following format: https://<CustomerId>.ods.opinsights.azure.us. \n4. Once all application settings have been entered, click **Save**."
}
]
}

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

@ -4,6 +4,8 @@
"parameters": {
"FunctionName": {
"defaultValue": "OktaSSO",
"minLength": 1,
"maxLength": 11,
"type": "string"
},
"WorkspaceID": {
@ -24,7 +26,9 @@
}
},
"variables": {
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]"
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]",
"StorageSuffix":"[environment().suffixes.storage]",
"LogAnaltyicsUri":"[replace(environment().portal, 'https://portal', concat('https://', toLower(parameters('WorkspaceID')), '.ods.opinsights'))]"
},
"resources": [
{
@ -157,11 +161,11 @@
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=core.windows.net')]"
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=core.windows.net')]"
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]"
},
{
"name": "WEBSITE_CONTENTSHARE",
@ -191,6 +195,10 @@
"name": "uri",
"value": "[parameters('Uri')]"
},
{
"name": "logAnalyticsUri",
"value": "[variables('LogAnaltyicsUri')]"
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "https://aka.ms/sentineloktaazurefunctioncodev2"
@ -204,19 +212,6 @@
"alwaysOn": true
}
},
{
"type": "Microsoft.Web/sites/hostNameBindings",
"apiVersion": "2018-11-01",
"name": "[concat(variables('FunctionName'), '/', variables('FunctionName'), '.azurewebsites.net')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('FunctionName'))]"
],
"properties": {
"siteName": "[variables('FunctionName')]",
"hostNameType": "Verified"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",

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

@ -49,7 +49,7 @@
},
{
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key)",
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
"providerDisplayName": "Keys",
"scope": "Workspace",
"requiredPermissions": {

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

@ -21,14 +21,12 @@ relevantTechniques:
- T1087
query: |
let timeframe = 1d;
AWSCloudTrail
| where TimeGenerated > ago(timeframe)
| where EventName =~ "GetCallerIdentity" and UserIdentityType =~ "AssumedRole"
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by SourceIpAddress, EventName, EventTypeName, UserIdentityType, UserIdentityAccountId, UserIdentityPrincipalid,
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by SourceIpAddress, EventName, EventTypeName, UserIdentityType, UserIdentityAccountId, UserIdentityPrincipalid,
UserAgent, UserIdentityUserName, SessionMfaAuthenticated,AWSRegion, EventSource, AdditionalEventData, ResponseElements
| extend timestamp = StartTimeUtc, AccountCustomEntity = UserIdentityUserName, IPCustomEntity = SourceIpAddress
| sort by EndTimeUtc desc nulls last
| extend timestamp = StartTime, AccountCustomEntity = UserIdentityUserName, IPCustomEntity = SourceIpAddress
| sort by EndTime desc nulls last
entityMappings:
- entityType: Account
fieldMappings:

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

@ -1,7 +1,7 @@
id: 31337365-4b1d-adf5-00da-0000000FF1CE
id: 95dc4ae3-e0f2-48bd-b996-cdd22b90f9af
name: Modified domain federation trust settings
description: |
'This will alert when a user or application modifies the federation settings on the domain or Update domain authentication from Managed to Federated.
'This will alert when a user or application modifies the federation settings on the domain or Update domain authentication from Managed to Federated.
For example, this alert will trigger when a new Active Directory Federated Service (ADFS) TrustedRealm object, such as a signing certificate, is added to the domain.
Modification to domain federation settings should be rare. Confirm the added or modified target domain/URL is legitimate administrator behavior.
To understand why an authorized user may update settings for a federated domain in Office 365, Azure, or Intune, see: https://docs.microsoft.com/office365/troubleshoot/active-directory/update-federated-domain-office-365.
@ -12,8 +12,8 @@ requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 1h
queryPeriod: 1h
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
@ -33,7 +33,7 @@ query: |
| mv-expand modifiedProperties
| extend targetDisplayName = tostring(parse_json(modifiedProperties).displayName)
| mv-expand AdditionalDetails
),
),
(
AuditLogs
| where TimeGenerated > ago(auditLookback)

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

@ -0,0 +1,67 @@
id: 707494a5-8e44-486b-90f8-155d1797a8eb
name: Credential added after admin consented to Application
description: |
'This query will identify instances where Service Principal credentials were added to an application by one user after the application was granted admin consent rights by another user.
If a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.
Additional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow.
For further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities'
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 1d
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1550.001
tags:
- Solorigate
query: |
let auditLookbackStart = 2d;
let auditLookbackEnd = 1d;
AuditLogs
| where TimeGenerated >= ago(auditLookbackStart)
| where OperationName =~ "Consent to application"
| where Result =~ "success"
| mv-expand target = TargetResources
| extend targetResourceName = tostring(target.displayName)
| extend targetResourceID = tostring(target.id)
| extend targetResourceType = tostring(target.type)
| extend targetModifiedProp = TargetResources[0].modifiedProperties
| extend isAdminConsent = targetModifiedProp[0].newValue
| extend Consent_ServicePrincipalNames = targetModifiedProp[5].newValue
| extend Consent_Permissions = targetModifiedProp[4].newValue
| extend Consent_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend Consent_InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))
| join (
AuditLogs
| where TimeGenerated >= ago(auditLookbackEnd)
| where OperationName =~ "Add service principal credentials"
| where Result =~ "success"
| mv-expand target = TargetResources
| extend targetResourceName = tostring(target.displayName)
| extend targetResourceID = tostring(target.id)
| extend targetModifiedProp = TargetResources[0].modifiedProperties
| extend Credential_KeyDescription = targetModifiedProp[0].newValue
| extend UpdatedProperties = targetModifiedProp[1].newValue
| extend Credential_ServicePrincipalNames = targetModifiedProp[2].newValue
| extend Credential_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend Credential_InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))
) on targetResourceName, targetResourceID
| extend TimeConsent = TimeGenerated, TimeCred = TimeGenerated1
| where TimeConsent > TimeCred
| project TimeConsent, TimeCred, Consent_InitiatingUserOrApp, Credential_InitiatingUserOrApp, targetResourceName, targetResourceType, isAdminConsent, Consent_ServicePrincipalNames, Credential_ServicePrincipalNames, Consent_Permissions, Credential_KeyDescription, Consent_InitiatingIpAddress, Credential_InitiatingIpAddress
| extend timestamp = TimeConsent, AccountCustomEntity = Consent_InitiatingUserOrApp, IPCustomEntity = Consent_InitiatingIpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,47 @@
id: acfdee3f-b794-404a-aeba-ef6a1fa08ad1
name: Azure DevOps Agent Pool Created Then Deleted
description: |
'As well as adding build agents to an existing pool to execute malicious activity within a pipeline an attacker could create a complete new agent pool and use this for execution. Azure DevOps allows for the creation of agent pools with Azure hosted infrastructure or self-hosted infrastructure. Given the additional customizability of self-hosted agents this detection focuses on the creation of new self-hosted pools. To further reduce false positive rates the detection looks for pools created and deleted relatively quickly (within 7 days by default), as an attacker is likely to remove a malicious pool once used in order to reduce/remove evidence of their activity.'
severity: High
requiredDataConnectors: []
queryFrequency: 7d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1578.002
query: |
let lookback = 14d;
let timewindow = 7d;
AzureDevOpsAuditing
| where TimeGenerated > ago(lookback)
| where OperationName =~ "Library.AgentPoolCreated"
| extend AgentCloudId = tostring(Data.AgentCloudId)
| extend PoolType = iif(isnotempty(AgentCloudId), "Azure VMs", "Self Hosted")
// Comment this line out to include cloud pools as well
| where PoolType == "Self Hosted"
| extend AgentPoolName = tostring(Data.AgentPoolName)
| extend AgentPoolId = tostring(Data.AgentPoolId)
| extend IsHosted = tostring(Data.IsHosted)
| extend IsLegacy = tostring(Data.IsLegacy)
| extend timekey = bin(TimeGenerated, timewindow)
// Join only with pools deleted in the same window
| join (AzureDevOpsAuditing
| where TimeGenerated > ago(lookback)
| where OperationName =~ "Library.AgentPoolDeleted"
| extend AgentPoolName = tostring(Data.AgentPoolName)
| extend AgentPoolId = tostring(Data.AgentPoolId)
| extend timekey = bin(TimeGenerated, timewindow)) on AgentPoolId, timekey
| project-reorder TimeGenerated, ActorUPN, UserAgent, IpAddress, AuthenticationMechanism, OperationName, AgentPoolName, IsHosted, IsLegacy, Data
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,29 @@
id: 4e8238bd-ff4f-4126-a9f6-09b3b6801b3d
name: Azure DevOps Audit Stream Disabled
description: |
'Azure DevOps allow for audit logs to streamed to external storage solutions such as SIEM solutions. An attacker looking to hide malicious Azure DevOps activity from defenders may look to disable data streams before conducting activity and them re-enabling them after (so as not to raise data threshold-based alarms). Looking for disabled audit streams can identify this activity, and due to the nature of the action its unlikely to have a high false positive rate.'
severity: High
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1562.008
query: |
AzureDevOpsAuditing
| where OperationName =~ "AuditLog.StreamDisabledByUser"
| extend StreamType = tostring(Data.ConsumerType)
| project-reorder TimeGenerated, Details, ActorUPN, IpAddress, UserAgent, StreamType
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,32 @@
id: bf07ca9c-e408-443a-8939-6860a45a929e
name: Azure DevOps - New Extension Added
description: |
'Extensions added additional features to Azure DevOps. An attacker could use a malicious extension to conduct malicious activity. This query looks for new extensions that are not from a configurable list of approved publishers.'
severity: Low
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1505
query: |
let allowed_publishers = dynamic([]);
AzureDevOpsAuditing
| where OperationName =~ "Extension.Installed"
| extend ExtensionName = tostring(Data.ExtensionName)
| extend PublisherName = tostring(Data.PublisherName)
| where PublisherName !in (allowed_publishers)
| project-reorder TimeGenerated, OperationName, ExtensionName, PublisherName, ActorUPN, IpAddress, UserAgent, ScopeDisplayName, Data
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,29 @@
id: 5f0d80db-3415-4265-9d52-8466b7372e3a
name: Azure DevOps - PAT used with Browser.
description: |
'Personal Access Tokens (PATs) are used as an alternate password to authenticate into Azure DevOps. PATs are intended for programmatic access for use in code or applications. Given this they can be prone to attacker theft if not adequately secured. This queries looks for the use of a PAT in authentication but from a User Agent indicating a browser. This should not be normal activity and could be an indicator of an attacker using a stolen PAT.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1564
query: |
AzureDevOpsAuditing
| where AuthenticationMechanism startswith "PAT"
// Look for useragents that include a redenring engine
| where UserAgent has_any ("Gecko", "WebKit", "Presto", "Trident", "EdgeHTML", "Blink")
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,56 @@
id: 155e9134-d5ad-4a6f-88f3-99c220040b66
name: Azure DevOps Pipleine modified by a New User.
description: |
'There are several potential pipeline steps that could be modified by an attacker to inject malicious code into the build cycle. A likely attacker path is the modification to an existing pipeline that they have access to. This detection looks for users modifying a pipeline when they have not previously been observed modifying or creating that pipeline before. This query also joins events with data to Azure AD Identity Protection (AAD IdP) in order to show if the user conducting the action has any associated AAD IdP alerts, you can also chose to filter this detection to only alert when the user also has AAD IdP alerts associated with them.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
- DefenseEvasion
relevantTechniques:
- T1584.006
- T1578
query: |
// Set the lookback to determine if user has created pipelines before
let timeback = 14d;
// Set the period for detections
let timeframe = 1d;
// Get a list of previous Release Pipeline creators to exclude
let releaseusers = AzureDevOpsAuditing
| where TimeGenerated > ago(timeback) and TimeGenerated < ago(timeframe)
| where OperationName in ("Release.ReleasePipelineCreated", "Release.ReleasePipelineModified")
// We want to look for users performing actions in specific projects so we create this userscope object to match on
| extend UserScope = strcat(ActorUserId, "-", ProjectName)
| summarize by UserScope;
// Get Release Pipeline creations by new users
AzureDevOpsAuditing
| where TimeGenerated > ago(timeframe)
| where OperationName =~ "Release.ReleasePipelineModified"
| extend UserScope = strcat(ActorUserId, "-", ProjectName)
| where UserScope !in (releaseusers)
| extend ActorUPN = tolower(ActorUPN)
| project-away Id, ActivityId, ActorCUID, ScopeId, ProjectId, TenantId, SourceSystem, UserScope
// See if any of these users have Azure AD alerts associated with them in the same timeframe
| join kind = leftouter (
SecurityAlert
| where TimeGenerated > ago(timeframe)
| where ProviderName == "IPC"
| extend AadUserId = tostring(parse_json(Entities)[0].AadUserId)
| summarize Alerts=count() by AadUserId) on $left.ActorUserId == $right.AadUserId
| extend Alerts = iif(isnotempty(Alerts), Alerts, 0)
// Uncomment the line below to only show results where the user as AADIdP alerts
//| where Alerts > 0
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,30 @@
id: 71d374e0-1cf8-4e50-aecd-ab6c519795c2
name: Azure DevOps - Retention Reduced to Zero
description: |
'AzureDevOps retains items such as run records and produced artifacts for a configurable amount of time. An attacker looking to reduce the footprint left by their malicious activity may look to reduce the retention time for artifacts and runs to 0.'
severity: Low
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1564
query: |
AzureDevOpsAuditing
| where OperationName =~ "Pipelines.PipelineRetentionSettingChanged"
| where Data.SettingName in ("PurgeArtifacts", "PurgeRuns")
| where Data.NewValue == 0
| project-reorder TimeGenerated, OperationName, ActorUPN, IpAddress, UserAgent, Data
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,35 @@
id: 4ca74dc0-8352-4ac5-893c-73571cc78331
name: Azure DevOps - Variable Secret Not Secured
description: |
'Credentials used in the build process may be stored as Azure DevOps variables. To secure these variables they should be stored in KeyVault or marked as secrets. This detection looks for new variables added with names that suggest they are credentials but where they are not set as Secrets or stored in KeyVault.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1552
query: |
let keywords = dynamic(["secret", "secrets", "password", "PAT", "passwd", "pswd", "pwd", "cred", "creds", "credentials", "credential", "key"]);
AzureDevOpsAuditing
| where OperationName =~ "Library.VariableGroupModified"
| extend Type = tostring(Data.Type)
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend VariableGroupName = tostring(Data.VariableGroupName)
| mv-expand Data.Variables
| where VariableGroupName has_any (keywords) or Data_Variables has_any (keywords)
| where Type != "AzureKeyVault"
| where Data_Variables !has "IsSecret"
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,44 @@
id: 3b9a44d7-c651-45ed-816c-eae583a6f2f1
name: ADO Build Variable Modified by New User.
description: |
'Variables can be configured and used at any stage of the build process in Azure DevOps to inject values. An attacker with the required permissions could modify or add to these variables to conduct malicious activity such as changing paths or remote endpoints called during the build. As variables are often changed by users just detecting these changes would have a high false positive rate. This detection looks for modifications to variable groups where that user has not been observed modifying them before.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1578
query: |
let lookback = 14d;
let timeframe = 1d;
let historical_data =
AzureDevOpsAuditing
| where TimeGenerated > ago(lookback) and TimeGenerated < ago(timeframe)
| where OperationName =~ "Library.VariableGroupModified"
| extend variables = Data.Variables
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend UserKey = strcat(VariableGroupId, "-", ActorUserId)
| project UserKey;
AzureDevOpsAuditing
| where TimeGenerated > ago(timeframe)
| where OperationName =~ "Library.VariableGroupModified"
| extend VariableGroupName = tostring(Data.VariableGroupName)
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend UserKey = strcat(VariableGroupId, "-", ActorUserId)
| where UserKey !in (historical_data)
| project-away UserKey
| project-reorder TimeGenerated, VariableGroupName, ActorUPN, IpAddress, UserAgent
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,58 @@
id: 17f23fbe-bb73-4324-8ecf-a18545a5dc26
name: Azure DevOps Pipeline Created and Deleted on the Same Day
description: |
'An attacker with access to Azure DevOps could create a pipeline to inject artifacts used by other pipelines,
or to create a malicious software build that looks legitimate by using a pipeline that incorporates legitimate elements.
An attacker would also likely want to cover their tracks once conducting such activity. This query looks for Pipelines
created and deleted within the same day, this is unlikely to be legitimate user activity in the majority of cases.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 3d
queryPeriod: 3d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
relevantTechniques:
- T1072
query: |
let timeframe = 3d;
// Get Release Pipeline Creation Events and group by day
AzureDevOpsAuditing
| where TimeGenerated > ago(timeframe)
| where OperationName =~ "Release.ReleasePipelineCreated"
// Group by day
| extend timekey = bin(TimeGenerated, 1d)
| extend PipelineId = tostring(Data.PipelineId)
| extend PipelineName = tostring(Data.PipelineName)
// Rename some columns to make output clearer
| project-rename TimeCreated = TimeGenerated, CreatingUser = ActorUPN, CreatingUserAgent = UserAgent, CreatingIP = IpAddress
// Join with Release Pipeline Deletions where Pipeline ID is the same and deletion occurred on same day as creation
| join (AzureDevOpsAuditing
| where TimeGenerated > ago(timeframe)
| where OperationName =~ "Release.ReleasePipelineDeleted"
// Group by day
| extend timekey = bin(TimeGenerated, 1d)
| extend PipelineId = tostring(Data.PipelineId)
| extend PipelineName = tostring(Data.PipelineName)
// Rename some things to make the output clearer
| project-rename TimeDeleted = TimeGenerated, DeletingUser = ActorUPN, DeletingUserAgent = UserAgent, DeletingIP = IpAddress) on PipelineId, timekey
| project TimeCreated, TimeDeleted, PipelineName, PipelineId, CreatingUser, CreatingIP, CreatingUserAgent, DeletingUser, DeletingIP, DeletingUserAgent, ScopeDisplayName, ProjectName, Data, OperationName, OperationName1
| extend timestamp = TimeCreated, AccountCustomEntity = CreatingUser, IPCustomEntity = CreatingIP
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: DeletingUser
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: DeletingIP

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

@ -0,0 +1,46 @@
id: adc32a33-1cd6-46f5-8801-e3ed8337885f
name: External Upstream Source Added to Azure DevOps Feed
description: |
'The detection looks for new external sources added to an Azure DevOps feed. An allow list can be customized to explicitly allow known good sources. An attacker could look to add a malicious feed in order to inject malicious packages into a build pipeline.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1199
query: |
// Add any known allowed sources and source locations to the filter below (the NuGet Gallery has been added here as an example).
let allowed_sources = dynamic(["NuGet Gallery"]);
let allowed_locations = dynamic(["https://api.nuget.org/v3/index.json"]);
AzureDevOpsAuditing
// Look for feeds created or modified at either the organization or project level
| where OperationName matches regex "Artifacts.Feed.(Org|Project).Modify"
| where Details has "UpstreamSources, added"
| extend FeedName = tostring(Data.FeedName)
| extend FeedId = tostring(Data.FeedId)
| extend UpstreamsAdded = Data.UpstreamsAdded
// As multiple feeds may be added expand these out
| mv-expand UpstreamsAdded
// Only focus on external feeds
| where UpstreamsAdded.UpstreamSourceType !~ "internal"
| extend SourceLocation = tostring(UpstreamsAdded.Location)
| extend SourceName = tostring(UpstreamsAdded.Name)
// Exclude sources and locations in the allow list
| where SourceLocation !in (allowed_locations) and SourceName !in (allowed_sources)
| extend SourceProtocol = tostring(UpstreamsAdded.Protocol)
| extend SourceStatus = tostring(UpstreamsAdded.Status)
| project-reorder TimeGenerated, OperationName, ScopeDisplayName, ProjectName, FeedName, SourceName, SourceLocation, SourceProtocol, ActorUPN, UserAgent, IpAddress
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,63 @@
id: 4ce177b3-56b1-4f0e-b83e-27eed4cb0b16
name: New Agent Added to Pool by New User or of a New OS Type.
description: |
'As seen in attacks such as SolarWinds attackers can look to subvert a build process by controlling build servers. Azure DevOps uses agent pools to execute pipeline tasks. An attacker could insert compromised agents that they control into the pools in order to execute malicious code. This query looks for users adding agents to pools they have not added agents to before, or adding agents to a pool of an OS that has not been added to that pool before. This detection has potential for false positives so has a configurable allow list to allow for certain users to be excluded from the logic.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
relevantTechniques:
- T1053
query: |
let lookback = 14d;
let timeframe = 1d;
// exclude allowed users from query such as the ADO service
let allowed_users = dynamic(["Azure DevOps Service"]);
union
// Look for agents being added to a pool of a OS type not seen with that pool before
(AzureDevOpsAuditing
| where TimeGenerated > ago(lookback) and TimeGenerated < ago(timeframe)
| where OperationName =~ "Library.AgentAdded"
| where ActorUPN !in (allowed_users)
| extend AgentPoolName = tostring(Data.AgentPoolName)
| extend OsDescription = tostring(Data.OsDescription)
| where isnotempty(OsDescription)
| extend OsDescription = tostring(split(OsDescription, "#", 0)[0])
| project AgentPoolName, OsDescription
| join kind=rightanti (AzureDevOpsAuditing
| where TimeGenerated > ago(timeframe)
| where OperationName == "Library.AgentAdded"
| extend AgentPoolName = tostring(Data.AgentPoolName)
| extend OsDescription = tostring(Data.OsDescription)
| where isnotempty(OsDescription)
| extend OsDescription = tostring(split(OsDescription, "#", 0)[0])) on AgentPoolName, OsDescription),
// Look for users addeing agents to a pool that they have not added agents to before.
(AzureDevOpsAuditing
| where TimeGenerated > ago(lookback) and TimeGenerated < ago(timeframe)
| extend AgentPoolName = tostring(Data.AgentPoolName)
| where ActorUPN !in (allowed_users)
| project AgentPoolName, ActorUPN
| join kind=rightanti (AzureDevOpsAuditing
| where TimeGenerated > ago(timeframe)
| where OperationName == "Library.AgentAdded"
| where ActorUPN !in (allowed_users)
| extend AgentPoolName = tostring(Data.AgentPoolName)
) on AgentPoolName, ActorUPN)
| extend AgentName = tostring(Data.AgentName)
| extend OsDescription = tostring(Data.OsDescription)
| extend SystemDetails = Data.SystemCapabilities
| project-reorder TimeGenerated, OperationName, ScopeDisplayName, AgentPoolName, AgentName, ActorUPN, IpAddress, UserAgent, OsDescription, SystemDetails, Data
| extend timestamp = TimeGenerated, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,41 @@
id: 35ce9aff-1708-45b8-a295-5e9a307f5f17
name: New PA, PCA, or PCAS added to Azure DevOps
description: |
'In order for an attacker to be able to conduct many potential attacks against Azure DevOps they will need to gain elevated permissions. This detection looks for users being granted key administrative permissions. If the principal of least privilege is applied the number of users granted these permissions should be small. Note that permissions can also be granted via Azure AD groups and monitoring of these should also be conducted.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1078.004
query: |
AzureDevOpsAuditing
| where OperationName =~ "Group.UpdateGroupMembership.Add"
| where Details has_any ("Project Administrators", "Project Collection Administrators", "Project Collection Service Accounts", "Build Administrator")
| project-reorder TimeGenerated, Details, ActorUPN, IpAddress, UserAgent, AuthenticationMechanism, ScopeDisplayName
| extend timekey = bin(TimeGenerated, 1h)
| extend ActorUserId = tostring(Data.MemberId)
| project timekey, ActorUserId, AddingUser=ActorUPN, TimeAdded=TimeGenerated, PermissionGrantDetails = Details
// Get details of operations conducted by user soon after elevation of permissions
| join (AzureDevOpsAuditing
| extend ActorUserId = tostring(Data.MemberId)
| extend timekey = bin(TimeGenerated, 1h)) on timekey, ActorUserId
| summarize ActionsWhenAdded = make_set(OperationName) by ActorUPN, AddingUser, TimeAdded, PermissionGrantDetails, IpAddress, UserAgent
| extend timestamp = TimeAdded, AccountCustomEntity = ActorUPN, IPCustomEntity = IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AddingUser
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,52 @@
id: c9b6d281-b96b-4763-b728-9a04b9fe1246
name: Cisco Umbrella - Connection to non-corporate private network
description: |
'IP addresses of broadband links that usually indicates users attempting to access their home network, for example for a remote session to a home computer.'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- Exfiltration
query: |
let lbtime = 10m;
Cisco_Umbrella
| where TimeGenerated > ago(lbtime)
| where EventType == 'proxylogs'
| where DvcAction =~ 'Allowed'
| where UrlCategory contains 'Adult Themes' or
UrlCategory contains 'Adware' or
UrlCategory contains 'Alcohol' or
UrlCategory contains 'Illegal Downloads' or
UrlCategory contains 'Drugs' or
UrlCategory contains 'Child Abuse Content' or
UrlCategory contains 'Hate/Discrimination' or
UrlCategory contains 'Nudity' or
UrlCategory contains 'Pornography' or
UrlCategory contains 'Proxy/Anonymizer' or
UrlCategory contains 'Sexuality' or
UrlCategory contains 'Tasteless' or
UrlCategory contains 'Terrorism' or
UrlCategory contains 'Web Spam' or
UrlCategory contains 'German Youth Protection' or
UrlCategory contains 'Illegal Activities' or
UrlCategory contains 'Lingerie/Bikini' or
UrlCategory contains 'Weapons'
| project TimeGenerated, SrcIpAddr, Identities
| extend IPCustomEntity = SrcIpAddr
| extend AccountCustomEntity = Identities
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,42 @@
id: 75297f62-10a8-4fc1-9b2a-12f25c6f05a7
name: Cisco Umbrella - Connection to Unpopular Website Detected
description: |
'Detects first connection to an unpopular website (possible malicious payload delivery).'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
query: |
let domain_lookBack= 14d;
let timeframe = 1d;
let top_million_list = Cisco_Umbrella
| where EventType == "proxylogs"
| where TimeGenerated > ago(domain_lookBack) and TimeGenerated < ago(timeframe)
| extend Hostname = parse_url(UrlOriginal)["Host"]
| summarize count() by tostring(Hostname)
| top 1000000 by count_
| summarize make_list(Hostname);
Cisco_Umbrella
| where EventType == "proxylogs"
| where TimeGenerated > ago(timeframe)
| extend Hostname = parse_url(UrlOriginal)["Host"]
| where Hostname !in (top_million_list)
| extend Message = "Connect to unpopular website (possible malicious payload delivery)"
| project Message, SrcIpAddr, DstIpAddr,UrlOriginal, TimeGenerated
| extend IpCustomEntity = SrcIpAddr, UrlCustomEntity = UrlOriginal
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,33 @@
id: b619d1f1-7f39-4c7e-bf9e-afbb46457997
name: Cisco Umbrella - Crypto Miner User-Agent Detected
description: |
'Detects suspicious user agent strings used by crypto miners in proxy logs.'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
query: |
let timeframe = 15m;
Cisco_Umbrella
| where EventType == "proxylogs"
| where TimeGenerated > ago(timeframe)
| where HttpUserAgentOriginal contains "XMRig" or HttpUserAgentOriginal contains "ccminer"
| extend Message = "Crypto Miner User Agent"
| project Message, SrcIpAddr, DstIpAddr, UrlOriginal, TimeGenerated,HttpUserAgentOriginal
| extend IpCustomEntity = SrcIpAddr, UrlCustomEntity = UrlOriginal
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,33 @@
id: 2b328487-162d-4034-b472-59f1d53684a1
name: Cisco Umbrella - Empty User Agent Detected
description: |
'Rule helps to detect empty and unusual user agent indicating web browsing activity by an unusual process other than a web browser.'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
query: |
let timeframe = 15m;
Cisco_Umbrella
| where EventType == "proxylogs"
| where TimeGenerated > ago(timeframe)
| where HttpUserAgentOriginal == ''
| extend Message = "Empty User Agent"
| project Message, SrcIpAddr, DstIpAddr, UrlOriginal, TimeGenerated
| extend IpCustomEntity = SrcIpAddr, UrlCustomEntity = UrlOriginal
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,81 @@
id: 8d537f3c-094f-430c-a588-8a87da36ee3a
name: Cisco Umbrella - Hack Tool User-Agent Detected
description: |
'Detects suspicious user agent strings used by known hack tools'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
query: |
let timeframe = 15m;
let user_agents=dynamic([
'(hydra)',
' arachni/',
' BFAC ',
' brutus ',
' cgichk ',
'core-project/1.0',
' crimscanner/',
'datacha0s',
'dirbuster',
'domino hunter',
'dotdotpwn',
'FHScan Core',
'floodgate',
'get-minimal',
'gootkit auto-rooter scanner',
'grendel-scan',
' inspath ',
'internet ninja',
'jaascois',
' zmeu ',
'masscan',
' metis ',
'morfeus fucking scanner',
'n-stealth',
'nsauditor',
'pmafind',
'security scan',
'springenwerk',
'teh forest lobster',
'toata dragostea',
' vega/',
'voideye',
'webshag',
'webvulnscan',
' whcc/',
' Havij',
'absinthe',
'bsqlbf',
'mysqloit',
'pangolin',
'sql power injector',
'sqlmap',
'sqlninja',
'uil2pn',
'ruler',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)'
]);
Cisco_Umbrella
| where EventType == "proxylogs"
| where TimeGenerated > ago(timeframe)
| where HttpUserAgentOriginal has_any (user_agents)
| extend Message = "Hack Tool User Agent"
| project Message, SrcIpAddr, DstIpAddr, UrlOriginal, TimeGenerated, HttpUserAgentOriginal
| extend IpCustomEntity = SrcIpAddr, UrlCustomEntity = UrlOriginal
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,34 @@
id: b12b3dab-d973-45af-b07e-e29bb34d8db9
name: Cisco Umbrella - Windows PowerShell User-Agent Detected
description: |
'Rule helps to detect Powershell user-agent activity by an unusual process other than a web browser.'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- DefenseEvasion
query: |
let timeframe = 15m;
Cisco_Umbrella
| where EventType == "proxylogs"
| where TimeGenerated > ago(timeframe)
| where HttpUserAgentOriginal contains "WindowsPowerShell"
| extend Message = "Windows PowerShell User Agent"
| project Message, SrcIpAddr, DstIpAddr, UrlOriginal, TimeGenerated,HttpUserAgentOriginal
| extend IpCustomEntity = SrcIpAddr, UrlCustomEntity = UrlOriginal
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,39 @@
id: 8c8de3fa-6425-4623-9cd9-45de1dd0569a
name: Cisco Umbrella - Rare User Agent Detected
description: |
'Rule helps to detect a rare user-agents indicating web browsing activity by an unusual process other than a web browser.'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
query: |
let lookBack = 14d;
let timeframe = 1d;
let user_agents_list = Cisco_Umbrella
| where EventType == "proxylogs"
| where TimeGenerated > ago(lookBack) and TimeGenerated < ago(timeframe)
| summarize count() by HttpUserAgentOriginal
| summarize make_list(HttpUserAgentOriginal);
Cisco_Umbrella
| where EventType == "proxylogs"
| where TimeGenerated > ago(timeframe)
| where HttpUserAgentOriginal !in (user_agents_list)
| extend Message = "Rare User Agent"
| project Message, SrcIpAddr, DstIpAddr, UrlOriginal, TimeGenerated, HttpUserAgentOriginal
| extend IpCustomEntity = SrcIpAddr, UrlCustomEntity = UrlOriginal
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,52 @@
id: d6bf1931-b1eb-448d-90b2-de118559c7ce
name: Cisco Umbrella - Request Allowed to harmful/malicious URI category
description: |
'It is reccomended that these Categories shoud be blocked by policies because they provide harmful/malicious content..'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
- InitialAccess
query: |
let lbtime = 10m;
Cisco_Umbrella
| where TimeGenerated > ago(lbtime)
| where EventType == 'proxylogs'
| where DvcAction =~ 'Allowed'
| where UrlCategory contains 'Adult Themes' or
UrlCategory contains 'Adware' or
UrlCategory contains 'Alcohol' or
UrlCategory contains 'Illegal Downloads' or
UrlCategory contains 'Drugs' or
UrlCategory contains 'Child Abuse Content' or
UrlCategory contains 'Hate/Discrimination' or
UrlCategory contains 'Nudity' or
UrlCategory contains 'Pornography' or
UrlCategory contains 'Proxy/Anonymizer' or
UrlCategory contains 'Sexuality' or
UrlCategory contains 'Tasteless' or
UrlCategory contains 'Terrorism' or
UrlCategory contains 'Web Spam' or
UrlCategory contains 'German Youth Protection' or
UrlCategory contains 'Illegal Activities' or
UrlCategory contains 'Lingerie/Bikini' or
UrlCategory contains 'Weapons'
| project TimeGenerated, SrcIpAddr, Identities
| extend IPCustomEntity = SrcIpAddr
| extend AccountCustomEntity = Identities
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,37 @@
id: de58ee9e-b229-4252-8537-41a4c2f4045e
name: Cisco Umbrella - Request to blocklisted file type
description: |
'Detects request to potentially harmful file types (.ps1, .bat, .vbs, etc.).'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
query: |
let file_ext_blocklist = dynamic(['.ps1', '.vbs', '.bat', '.scr']);
let lbtime = 10m;
Cisco_Umbrella
| where TimeGenerated > ago(lbtime)
| where EventType == 'proxylogs'
| where DvcAction =~ 'Allowed'
| extend file_ext = extract(@'.*(\.\w+)$', 1, UrlOriginal)
| extend Filename = extract(@'.*\/*\/(.*\.\w+)$', 1, UrlOriginal)
| where file_ext in (file_ext_blocklist)
| project TimeGenerated, SrcIpAddr, Identities, Filename
| extend IPCustomEntity = SrcIpAddr
| extend AccountCustomEntity = Identities
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,34 @@
id: ee1818ec-5f65-4991-b711-bcf2ab7e36c3
name: Cisco Umbrella - URI contains IP address
description: |
'Malware can use IP address to communicate with C2.'
severity: Medium
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandandControl
query: |
let lbtime = 10m;
Cisco_Umbrella
| where TimeGenerated > ago(lbtime)
| where EventType == 'proxylogs'
| where DvcAction =~ 'Allowed'
| where UrlOriginal matches regex @'\Ahttp:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.*'
| project TimeGenerated, SrcIpAddr, Identities
| extend IPCustomEntity = SrcIpAddr
| extend AccountCustomEntity = Identities
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,39 @@
id: 8e0403b1-07f8-4865-b2e9-74d1e83200a4
name: High Urgency Cyberpion Action Items
description: |
'This query creates an alert for active Cyberpion Action Items with high urgency (9-10).
Urgency can be altered using the "min_urgency" variable in the query.'
severity: High
requiredDataConnectors:
- connectorId: CyberpionSecurityLogs
dataTypes:
- CyberpionActionItems_CL
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
- T1195
query: |
let timeframe = 14d;
let time_generated_bucket = 1h;
let min_urgency = 9;
let maxTimeGeneratedBucket = toscalar(
CyberpionActionItems_CL
| where TimeGenerated > ago(timeframe)
| summarize max(bin(TimeGenerated, time_generated_bucket))
);
CyberpionActionItems_CL
| where TimeGenerated > ago(timeframe) and is_open_b == true
| where bin(TimeGenerated, time_generated_bucket) == maxTimeGeneratedBucket
| where urgency_d >= min_urgency
| extend timestamp = opening_datetime_t
| extend DNSCustomEntity = host_s
entityMappings:
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: DNSCustomEntity

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

@ -0,0 +1,90 @@
id: 66276b14-32c5-4226-88e3-080dacc31ce1
name: Audit policy manipulation using auditpol utility
description: |
This detects attempt to manipulate audit policies using auditpol command.
This technique was seen in relation to Solorigate attack but the results can indicate potential malicious activity used in different attacks.
The process name in each data source is commented out as an adversary could rename it. It is advisable to keep process name commented but
if the results show unrelated false positives, users may want to uncomment it.
Refer to auditpol syntax: https://docs.microsoft.com/windows-server/administration/windows-commands/auditpol
Refer to our M365 blog for details on use during the Solorigate attack:
https://www.microsoft.com/security/blog/2021/01/20/deep-dive-into-the-solorigate-second-stage-activation-from-sunburst-to-teardrop-and-raindrop/
severity: Medium
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceProcessEvents
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
relevantTechniques:
- T1204
tags:
- Solorigate
query: |
let timeframe = 1d;
let AccountAllowList = dynamic(['SYSTEM']);
let SubCategoryList = dynamic(["Logoff", "Account Lockout", "User Account Management", "Authorization Policy Change"]); // Add any Category in the list to be allowed or disallowed
let tokens = dynamic(["clear", "remove", "success:disable","failure:disable"]);
(union isfuzzy=true
(
SecurityEvent
| where TimeGenerated >= ago(timeframe)
//| where Process =~ "auditpol.exe"
| where CommandLine has_any (tokens)
| where AccountType !~ "Machine" and Account !in~ (AccountAllowList)
| parse CommandLine with * "/subcategory:" subcategorytoken
| extend SubCategory = tostring(split(subcategorytoken, "\"")[1]) , Toggle = tostring(split(subcategorytoken, "\"")[2])
| where SubCategory in~ (SubCategoryList) //use in~ for inclusion or !in~ for exclusion
| where Toggle !in~ ("/failure:disable", " /success:enable /failure:disable") // use this filter if required to exclude certain toggles
| project TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, Process, ParentProcessName, CommandLine, SubCategory, Toggle
| extend timestamp = TimeGenerated, AccountCustomEntity = Account, HostCustomEntity = Computer
),
(
DeviceProcessEvents
| where TimeGenerated >= ago(timeframe)
// | where InitiatingProcessFileName =~ "auditpol.exe"
| where InitiatingProcessCommandLine has_any (tokens)
| where AccountName !in~ (AccountAllowList)
| parse InitiatingProcessCommandLine with * "/subcategory:" subcategorytoken
| extend SubCategory = tostring(split(subcategorytoken, "\"")[1]) , Toggle = tostring(split(subcategorytoken, "\"")[2])
| where SubCategory in~ (SubCategoryList) //use in~ for inclusion or !in~ for exclusion
| where Toggle !in~ ("/failure:disable", " /success:enable /failure:disable") // use this filter if required to exclude certain toggles
| project TimeGenerated, DeviceName, AccountName, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessParentFileName, InitiatingProcessCommandLine, SubCategory, Toggle
| extend timestamp = TimeGenerated, AccountCustomEntity = AccountName, HostCustomEntity = DeviceName
),
(
Event
| where TimeGenerated > ago(timeframe)
| where Source == "Microsoft-Windows-Sysmon"
| where EventID == 1
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key=tostring(['@Name']), Value=['#text']
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)
// | where OriginalFileName =~ "auditpol.exe"
| where CommandLine has_any (tokens)
| where User !in~ (AccountAllowList)
| parse CommandLine with * "/subcategory:" subcategorytoken
| extend SubCategory = tostring(split(subcategorytoken, "\"")[1]) , Toggle = tostring(split(subcategorytoken, "\"")[2])
| where SubCategory in~ (SubCategoryList) //use in~ for inclusion or !in~ for exclusion
| where Toggle !in~ ("/failure:disable", " /success:enable /failure:disable") // use this filter if required to exclude certain toggles
| project TimeGenerated, Computer, User, Process, ParentImage, CommandLine, SubCategory, Toggle
| extend timestamp = TimeGenerated, AccountCustomEntity = User, HostCustomEntity = Computer
)
)
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity

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

@ -0,0 +1,71 @@
id: 2f561e20-d97b-4b13-b02d-18b34af6e87c
name: Email access via active sync
description: |
This query detects attempts to add attacker devices as allowed IDs for active sync using the Set-CASMailbox command.
This technique was seen in relation to Solorigate attack but the results can indicate potential malicious activity used in different attacks.
- Note that this query can be changed to use the KQL "has_all" operator, which hasn't yet been documented officially, but will be soon.
In short, "has_all" will only match when the referenced field has all strings in the list.
- Refer to Set-CASMailbox syntax: https://docs.microsoft.com/powershell/module/exchange/set-casmailbox?view=exchange-ps
severity: Medium
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceProcessEvents
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
relevantTechniques:
- T1068
- T1078
tags:
- Solorigate
query: |
let timeframe = 1d;
let cmdList = dynamic(["Set-CASMailbox","ActiveSyncAllowedDeviceIDs","add"]);
(union isfuzzy=true
(
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where CommandLine has_all (cmdList)
| project Type, TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, Process, ParentProcessName, CommandLine
| extend timestamp = TimeGenerated, AccountCustomEntity = Account, HostCustomEntity = Computer
),
(
DeviceProcessEvents
| where TimeGenerated >= ago(timeframe)
| where InitiatingProcessCommandLine has_all (cmdList)
| project Type, TimeGenerated, DeviceName, AccountName, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessParentFileName, InitiatingProcessCommandLine
| extend timestamp = TimeGenerated, AccountCustomEntity = AccountName, HostCustomEntity = DeviceName
),
(
Event
| where TimeGenerated > ago(timeframe)
| where Source == "Microsoft-Windows-Sysmon"
| where EventID == 1
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key=tostring(['@Name']), Value=['#text']
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)
| where TimeGenerated >= ago(timeframe)
| where CommandLine has_all (cmdList)
| extend Type = strcat(Type, ": ", Source)
| project Type, TimeGenerated, Computer, User, Process, ParentImage, CommandLine
| extend timestamp = TimeGenerated, AccountCustomEntity = User, HostCustomEntity = Computer
)
)
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity

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

@ -11,6 +11,15 @@ requiredDataConnectors:
- connectorId: Office365
dataTypes:
- OfficeActivity
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
- connectorId: AWS
dataTypes:
- AWSCloudTrail
- connectorId: AzureMonitor(IIS)
dataTypes:
- W3CIISLog
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
@ -30,15 +39,47 @@ query: |
(OfficeActivity | where TimeGenerated >= ago(endtime) | where UserAgent != ""),
(OfficeActivity
| where TimeGenerated >= ago(endtime)
| where RecordType in ("AzureActiveDirectoryAccountLogon", "AzureActiveDirectoryStsLogon")
| extend OperationName = Operation, UserAgent = extractjson("$[0].Value", ExtendedProperties, typeof(string))),
| where RecordType in ("AzureActiveDirectory", "AzureActiveDirectoryStsLogon")
| extend OperationName = Operation
| parse ExtendedProperties with * 'User-Agent\\":\\"' UserAgent2 '\\' *
| parse ExtendedProperties with * 'UserAgent", "Value": "' UserAgent1 '"' *
| where isnotempty(UserAgent1) or isnotempty(UserAgent2)
| extend UserAgent = iff( RecordType == 'AzureActiveDirectoryStsLogon', UserAgent1, UserAgent2)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, RecordType, Operation
),
(AzureDiagnostics
| where TimeGenerated >= ago(endtime)
| where ResourceType =~ "APPLICATIONGATEWAYS"
| where OperationName =~ "ApplicationGatewayAccess"
| extend ClientIP = columnifexists("clientIP_s", "None"), UserAgent = columnifexists("userAgent_s", "None")))
| extend ClientIP = columnifexists("clientIP_s", "None"), UserAgent = columnifexists("userAgent_s", "None")
| where UserAgent != '-'
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, requestUri_s, httpMethod_s, host_s, requestQuery_s, Type
),
(
W3CIISLog
| where TimeGenerated >= ago(endtime)
| where isnotempty(csUserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, csUriStem
),
(
AWSCloudTrail
| where TimeGenerated >= ago(endtime)
| where isnotempty(UserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventSource, EventName
),
(SigninLogs
| where TimeGenerated >= ago(endtime)
| where isnotempty(UserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
),
(AADNonInteractiveUserSignInLogs
| where TimeGenerated >= ago(endtime)
| where isnotempty(UserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
)
)
// Likely artefact of hardcoding
| where UserAgent startswith "User" or UserAgent startswith "\""
| where UserAgent startswith "User" or UserAgent startswith '\"'
// Incorrect casing
or (UserAgent startswith "Mozilla" and not(UserAgent containscs "Mozilla"))
// Incorrect casing
@ -47,9 +88,7 @@ query: |
or UserAgent matches regex @"MSIE\s?;"
// Incorrect spacing around MSIE version
or UserAgent matches regex @"MSIE(?:\d|.{1,5}?\d\s;)"
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), OperationNames = makeset(OperationName), UserAgentCount = dcount(UserAgent),
UserAgentList = makeset(UserAgent), RecordTypes = makeset(RecordType) by UserId, ClientIP
| extend timestamp = StartTimeUtc, IPCustomEntity = ClientIP, AccountCustomEntity = UserId
| extend timestamp = StartTime, IPCustomEntity = SourceIP, AccountCustomEntity = Account
entityMappings:
- entityType: Account

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

@ -0,0 +1,54 @@
id: 1bf6e165-5e32-420e-ab4f-0da8558a8be2
name: Potential Build Process Compromise - MDE
description: |
'The query looks for source code files being modified immediately after a build process is started. The purpose of this is to look for malicious code injection during the build process. This query uses Microsoft Defender for Endpoint telemetry.
More details: https://techcommunity.microsoft.com/t5/azure-sentinel/monitoring-your-software-build-process-with-azure-sentinel/ba-p/2140807'
severity: Medium
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceProcessEvents
- DeviceFileEvents
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1554
tags:
- Solorigate
query: |
// How far back to look for events from
let timeframe = 1d;
// How close together build events and file modifications should occur to alert (make this smaller to reduce FPs)
let time_window = 5m;
// Edit this to include build processes used
let build_processes = dynamic(["MSBuild.exe", "dontnet.exe", "VBCSCompiler.exe"]);
// Include any processes that you want to allow to edit files during/around the build process
let allow_list = dynamic([]);
DeviceProcessEvents
| where TimeGenerated > ago(timeframe)
// Look for build process starts
| where FileName has_any (build_processes)
| summarize by BuildParentProcess=InitiatingProcessFileName, BuildProcess=FileName, BuildAccount = AccountName, DeviceName, BuildCommand=ProcessCommandLine, timekey= bin(TimeGenerated, time_window), BuildProcessTime=TimeGenerated
| join kind=inner(
DeviceFileEvents
| where TimeGenerated > ago(timeframe)
| where InitiatingProcessFileName !in (allow_list)
| where ActionType == "FileCreated" or ActionType == "FileModified"
// Look for code files, edit this to include file extensions used in build.
| where FileName endswith ".cs" or FileName endswith ".cpp"
| summarize by FileEditParentProcess=InitiatingProcessParentFileName, FileEditAccount = InitiatingProcessAccountName, DeviceName, FileEdited=FileName, FileEditProcess=InitiatingProcessFileName, timekey= bin(TimeGenerated, time_window), FileEditTime=TimeGenerated)
// join where build processes and file modifications seen at same time on same host
on timekey, DeviceName
// Limit to only where the file edit happens after the build process starts
| where BuildProcessTime <= FileEditTime
| summarize make_set(FileEdited), make_set(FileEditProcess), make_set(FileEditAccount) by timekey, DeviceName, BuildParentProcess, BuildProcess
| extend HostCustomEntity=DeviceName, timestamp=timekey
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity

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

@ -0,0 +1,36 @@
id: 53e936c6-6c30-4d12-8343-b8a0456e8429
name: SUNSPOT malware hashes
description: |
'This query uses Microsoft Defender for Endpoint data to look for IoCs associated with the SUNSPOT malware shared by Crowdstrike.
More details:
- https://www.crowdstrike.com/blog/sunspot-malware-technical-analysis/
- https://techcommunity.microsoft.com/t5/azure-sentinel/monitoring-your-software-build-process-with-azure-sentinel/ba-p/2140807'
severity: Medium
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceImageLoadEvents
- DeviceEvents
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1554
tags:
- Solorigate
query: |
let SUNSPOT_Hashes = dynamic(["c45c9bda8db1d470f1fd0dcc346dc449839eb5ce9a948c70369230af0b3ef168", "0819db19be479122c1d48743e644070a8dc9a1c852df9a8c0dc2343e904da389"]);
union isfuzzy=true(
DeviceEvents
| where InitiatingProcessSHA256 in (SUNSPOT_Hashes)),
(DeviceImageLoadEvents
| where InitiatingProcessSHA256 in (SUNSPOT_Hashes))
| extend HostCustomEntity = DeviceName, timestamp=TimeGenerated
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity

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

@ -0,0 +1,41 @@
id: c0e84221-f240-4dd7-ab1e-37e034ea2a4e
name: SUNSPOT log file creation
description: |
'This query uses Microsoft Defender for Endpoint data and Windows Event Logs to look for IoCs associated with the SUNSPOT malware shared by Crowdstrike.
More details:
- https://www.crowdstrike.com/blog/sunspot-malware-technical-analysis/
- https://techcommunity.microsoft.com/t5/azure-sentinel/monitoring-your-software-build-process-with-azure-sentinel/ba-p/2140807'
severity: Medium
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceFileEvents
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1554
tags:
- Solorigate
query: |
union isfuzzy=true
(DeviceFileEvents
| where FolderPath endswith "vmware-vmdmp.log"),
(SecurityEvent
| where EventID == 4663
| where ObjectName endswith "vmware-vmdmp.log")
| extend HostCustomEntity = DeviceName, timestamp=TimeGenerated
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity

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

@ -31,7 +31,7 @@ query: |
| where UPN contains ("#EXT#")
| project TimeDeleted=TimeGenerated, Operation, UPN, UserWhoDeleted = UserId, TeamName
) on UPN
| where TimeDeleted < TimeAdded
| where TimeDeleted > TimeAdded
| project TimeAdded, TimeDeleted, UPN, UserWhoAdded, UserWhoDeleted, TeamName
| extend timestamp = TimeAdded, AccountCustomEntity = UPN
entityMappings:

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

@ -46,11 +46,20 @@ query: |
// Join against base logs since specified timeframe to retrive records associated with the hour of anomoly
| join (
OfficeActivity
| where TimeGenerated > ago(2d)
| where OfficeWorkload=~ "Exchange" and Operation =~ "MailItemsAccessed" and ResultStatus =~ "Succeeded"
| where TimeGenerated > ago(2d)
| extend DateHour = bin(TimeGenerated, 1h)
| where OfficeWorkload=~ "Exchange" and Operation =~ "MailItemsAccessed" and ResultStatus =~ "Succeeded"
| summarize HourlyCount=count(), TimeGeneratedMax = arg_max(TimeGenerated, *), IPAdressList = make_set(Client_IPAddress), SourceIPMax= arg_max(Client_IPAddress, *), ClientInfoStringList= make_set(ClientInfoString) by MailboxOwnerUPN, Logon_Type, TenantId, UserType, TimeGenerated = bin(TimeGenerated, 1h)
| where HourlyCount > 25 // Only considering operations with more than 25 hourly count to reduce False Positivies
| order by HourlyCount desc
) on TimeGenerated
| extend PercentofTotal = round(HourlyCount/Total, 2) * 100
| where PercentofTotal > percentthreshold // Filter Users with count of less than 5 percent of TotalEvents per Hour to remove FPs/ users with very low count of MailItemsAccessed events
| order by PercentofTotal desc
| project-reorder TimeGeneratedMax, Type, OfficeWorkload, Operation, UserId,SourceIPMax ,IPAdressList, ClientInfoStringList, HourlyCount, PercentofTotal, Total, baseline, score, anomalies
| extend timestamp = TimeGenerated, AccountCustomEntity = UserId
entityMappings:
- entityType: IP
- entityType: Account
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
- identifier: FullName
columnName: AccountCustomEntity

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

@ -0,0 +1,31 @@
id: eb68b129-5f17-4f56-bf6d-dde48d5e615a
name: ProofpointPOD - Binary file in attachment
description: |
'Detects when email recieved with binary file as attachment.'
severity: Medium
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_message_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
query: |
let lbtime = 10m;
ProofpointPOD
| where TimeGenerated > ago(lbtime)
| where EventType == 'message'
| where NetworkDirection == 'inbound'
| where FilterDisposition !in ('reject', 'discard')
| extend attachedMimeType = todynamic(MsgParts)[0]['detectedMime']
| where attachedMimeType == 'application/zip'
| project SrcUserUpn, DstUserUpn
| extend AccountCustomEntity = DstUserUpn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity

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

@ -0,0 +1,35 @@
id: aedc5b33-2d7c-42cb-a692-f25ef637cbb1
name: ProofpointPOD - Possible data exfiltration to private email
description: |
'Detects when sender sent email to the non-corporate domain and recipient's username is the same as sender's username.'
severity: Medium
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_message_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
query: |
let lbtime = 10m;
ProofpointPOD
| where TimeGenerated > ago(lbtime)
| where EventType == 'message'
| where NetworkDirection == 'outbound'
| where array_length(todynamic(DstUserUpn)) == 1
| extend sender = extract(@'\A(.*?)@', 1, SrcUserUpn)
| extend sender_domain = extract(@'@(.*)$', 1, SrcUserUpn)
| extend recipient = extract(@'\A(.*?)@', 1, tostring(todynamic(DstUserUpn)[0]))
| extend recipient_domain = extract(@'@(.*)$', 1, tostring(todynamic(DstUserUpn)[0]))
| where sender =~ recipient
| where sender_domain != recipient_domain
| project SrcUserUpn, DstUserUpn
| extend AccountCustomEntity = SrcUserUpn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity

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

@ -0,0 +1,40 @@
id: 78979d32-e63f-4740-b206-cfb300c735e0
name: ProofpointPOD - Email sender IP in TI list
description: |
'Email sender IP in TI list.'
severity: Medium
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_maillog_CL
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
- InitialAccess
query: |
let ioc_lookBack = 30d;
let timeframe = 1h;
let TI_IP_List =
ThreatIntelligenceIndicator
| where TimeGenerated > ago(ioc_lookBack)
| where isnotempty(NetworkIP)
| summarize make_list(NetworkIP);
ProofpointPOD
| where TimeGenerated > ago(timeframe)
| where isnotempty(SrcIpAddr)
| where SrcIpAddr in~ (TI_IP_List)
| extend Message = "Email sender IP in TI list"
| project Message, SrcUserUpn, DstUserUpn, SrcIpAddr
| extend AccountCustomEntity = SrcUserUpn, IpCustomEntity = SrcIpAddr
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -0,0 +1,36 @@
id: 35a0792a-1269-431e-ac93-7ae2980d4dde
name: ProofpointPOD - Email sender in TI list
description: |
'Email sender in TI list.'
severity: Medium
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_maillog_CL
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
- InitialAccess
query: |
let ioc_lookBack = 30d;
let timeframe = 1h;
let TI_email_List =
ThreatIntelligenceIndicator
| where TimeGenerated > ago(ioc_lookBack)
| where isnotempty(EmailSenderAddress)
| summarize make_list(EmailSenderAddress);
ProofpointPOD
| where TimeGenerated > ago(timeframe)
| where isnotempty(SrcUserUpn)
| where SrcUserUpn in~ (TI_email_List)
| extend Message = "Email sender in TI list"
| project Message, SrcUserUpn, DstUserUpn
| extend AccountCustomEntity = SrcUserUpn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity

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

@ -0,0 +1,30 @@
id: c7cd6073-6d2c-4284-a5c8-da27605bdfde
name: ProofpointPOD - High risk message not discarded
description: |
'Detects when email with high risk score was not rejected or discarded by filters.'
severity: Low
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_message_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
query: |
let lbtime = 10m;
ProofpointPOD
| where TimeGenerated > ago(lbtime)
| where EventType == 'message'
| where NetworkDirection == 'inbound'
| where FilterDisposition !in ('reject', 'discard')
| where FilterModulesSpamScoresOverall == '100'
| project SrcUserUpn, DstUserUpn
| extend AccountCustomEntity = SrcUserUpn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity

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

@ -0,0 +1,32 @@
id: bda5a2bd-979b-4828-a91f-27c2a5048f7f
name: ProofpointPOD - Multiple archived attachments to the same recipient
description: |
'Detects when multiple emails where sent to the same recipient with large archived attachments.'
severity: Medium
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_message_CL
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
query: |
let lbtime = 30m;
let msgthreshold = 3;
ProofpointPOD
| where TimeGenerated > ago(lbtime)
| where EventType == 'message'
| where NetworkDirection == 'outbound'
| extend attachedMimeType = todynamic(MsgParts)[0]['detectedMime']
| where attachedMimeType == 'application/zip'
| summarize count() by SrcUserUpn, DstUserUpn
| where count_ > msgthreshold
| extend AccountCustomEntity = SrcUserUpn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity

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

@ -0,0 +1,32 @@
id: d1aba9a3-5ab1-45ef-8ed4-da57dc3c0d32
name: ProofpointPOD - Multiple large emails to the same recipient
description: |
'Detects when multiple emails with lage size where sent to the same recipient.'
severity: Medium
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_message_CL
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
query: |
let lbtime = 30m;
let msgthreshold = 3;
let msgszthreshold = 3000000;
ProofpointPOD
| where TimeGenerated > ago(lbtime)
| where EventType == 'message'
| where NetworkDirection == 'outbound'
| where NetworkBytes > msgszthreshold
| summarize count() by SrcUserUpn, DstUserUpn
| where count_ > msgthreshold
| extend AccountCustomEntity = SrcUserUpn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity

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

@ -0,0 +1,44 @@
id: f8127962-7739-4211-a4a9-390a7a00e91f
name: ProofpointPOD - Multiple protected emails to unknown recipient
description: |
'Detects when multiple protected messages where sent to early not seen recipient.'
severity: Medium
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_message_CL
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
query: |
let lbtime = 30m;
let lbperiod = 30d;
let knownrecipients = ProofpointPOD
| where TimeGenerated > ago(lbperiod)
| where EventType == 'message'
| where NetworkDirection == 'outbound'
| where SrcUserUpn != ''
| where array_length(todynamic(DstUserUpn)) == 1
| summarize recipients = make_set(tostring(todynamic(DstUserUpn)[0])) by SrcUserUpn
| extend commcol = SrcUserUpn;
ProofpointPOD
| where TimeGenerated between (ago(lbtime) .. now())
| where EventType == 'message'
| where NetworkDirection == 'outbound'
| extend isProtected = todynamic(MsgParts)[0]['isProtected']
| extend mimePgp = todynamic(MsgParts)[0]['detectedMime']
| where isProtected == 'true' or mimePgp == 'application/pgp-encrypted'
| extend DstUserMail = tostring(todynamic(DstUserUpn)[0])
| extend commcol = tostring(todynamic(DstUserUpn)[0])
| join knownrecipients on commcol
| where recipients !contains DstUserMail
| project SrcUserUpn, DstUserMail
| extend AccountCustomEntity = SrcUserUpn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity

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

@ -0,0 +1,32 @@
id: f6a51e2c-2d6a-4f92-a090-cfb002ca611f
name: ProofpointPOD - Suspicious attachment
description: |
'Detects when email contains suspicious attachment (file type).'
severity: Medium
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_message_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
query: |
let lbtime = 10m;
let disallowed_ext = dynamic(['ps1', 'exe', 'vbs', 'js', 'scr']);
ProofpointPOD
| where TimeGenerated > ago(lbtime)
| where EventType == 'message'
| where NetworkDirection == 'inbound'
| where FilterDisposition !in ('reject', 'discard')
| extend attachedExt = todynamic(MsgParts)[0]['detectedExt']
| where attachedExt in (disallowed_ext)
| project SrcUserUpn, DstUserUpn
| extend AccountCustomEntity = DstUserUpn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity

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

@ -0,0 +1,25 @@
id: 56b0a0cd-894e-4b38-a0a1-c41d9f96649a
name: ProofpointPOD - Weak ciphers
description: |
'Detects when weak TLS ciphers are used.'
severity: Low
requiredDataConnectors:
- connectorId: ProofpointPOD
dataTypes:
- ProofpointPOD_message_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
query: |
let lbtime = 1h;
let tls_ciphers = dynamic(['RC4-SHA', 'DES-CBC3-SHA']);
ProofpointPOD
| where EventType == 'message'
| where TlsCipher in (tls_ciphers)
| extend IpCustomEntity = SrcIpAddr
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -1,48 +0,0 @@
id: a3df4a32-4805-4c6d-8699-f3c888af2f67
name: Correlate Unfamiliar sign-in properties and atypical travel alerts
description: |
'When a user has both an Unfamiliar sign-in properties alert and an Atypical travel alert within 20 minutes, the alert should be handled with a higher severity'
severity: High
requiredDataConnectors:
- connectorId: AzureActiveDirectoryIdentityProtection
dataTypes:
- SecurityAlert (IPC)
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1078
query: |
let TimeFrame = ago(1d);
let Alert1 =
SecurityAlert
| where TimeGenerated > TimeFrame
| where AlertName == "Unfamiliar sign-in properties"
| extend UserPrincipalName = tostring(parse_json(ExtendedProperties).["User Account"])
| extend Alert1Time = TimeGenerated
| extend Alert1 = AlertName
| extend Alert1Severity = AlertSeverity
;
let Alert2 =
SecurityAlert
| where TimeGenerated > TimeFrame
| where AlertName == "Atypical travel"
| extend UserPrincipalName = tostring(parse_json(ExtendedProperties).["User Account"])
| extend Alert2Time = TimeGenerated
| extend Alert2 = AlertName
| extend Alert2Severity = AlertSeverity
| extend CurrentLocation = strcat(tostring(parse_json(tostring(parse_json(Entities)[1].Location)).CountryCode), "|", tostring(parse_json(tostring(parse_json(Entities)[1].Location)).State), "|", tostring(parse_json(tostring(parse_json(Entities)[1].Location)).City))
| extend PreviousLocation = strcat(tostring(parse_json(tostring(parse_json(Entities)[2].Location)).CountryCode), "|", tostring(parse_json(tostring(parse_json(Entities)[2].Location)).State), "|", tostring(parse_json(tostring(parse_json(Entities)[2].Location)).City))
| extend CurrentIPAddress = tostring(parse_json(Entities)[1].Address)
| extend PreviousIPAddress = tostring(parse_json(Entities)[2].Address)
;
Alert1
| join kind=inner Alert2 on UserPrincipalName
| where (Alert1Time - Alert2Time) between (-10min..10min)
| extend TimeDelta = Alert1Time - Alert2Time
| project UserPrincipalName, Alert1, Alert1Time, Alert1Severity, Alert2, Alert2Time, Alert2Severity, TimeDelta, CurrentLocation, PreviousLocation, CurrentIPAddress, PreviousIPAddress
| extend AccountCustomEntity = UserPrincipalName
| extend IPCustomEntity = CurrentIPAddress

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

@ -0,0 +1,57 @@
id: 5ef06767-b37c-4818-b035-47de950d0046
name: Potential Build Process Compromise
description: |
'The query looks for source code files being modified immediately after a build process is started. The purpose of this is to look for malicious code injection during the build process.
More details: https://techcommunity.microsoft.com/t5/azure-sentinel/monitoring-your-software-build-process-with-azure-sentinel/ba-p/2140807'
severity: Medium
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1554
tags:
- Solorigate
query: |
// How far back to look for events from
let timeframe = 1d;
// How close together build events and file modifications should occur to alert (make this smaller to reduce FPs)
let time_window = 5m;
// Edit this to include build processes used
let build_processes = dynamic(["MSBuild.exe", "dontnet.exe", "VBCSCompiler.exe"]);
// Include any processes that you want to allow to edit files during/around the build process
let allow_list = dynamic([""]);
SecurityEvent
| where TimeGenerated > ago(timeframe)
// Look for build process starts
| where EventID == 4688
| where Process has_any (build_processes)
| summarize by BuildParentProcess=ParentProcessName, BuildProcess=Process, BuildAccount = Account, Computer, BuildCommand=CommandLine, timekey= bin(TimeGenerated, time_window), BuildProcessTime=TimeGenerated
| join kind=inner(
SecurityEvent
| where TimeGenerated > ago(timeframe)
// Look for file modifications to code file
| where EventID == 4663
| where Process !in (allow_list)
// Look for code files, edit this to include file extensions used in build.
| where ObjectName endswith ".cs" or ObjectName endswith ".cpp"
// 0x6 and 0x4 for file append, 0x100 for file replacements
| where AccessMask == "0x6" or AccessMask == "0x4" or AccessMask == "0X100"
| summarize by FileEditParentProcess=ParentProcessName, FileEditAccount = Account, Computer, FileEdited=ObjectName, FileEditProcess=ProcessName, timekey= bin(TimeGenerated, time_window), FileEditTime=TimeGenerated)
// join where build processes and file modifications seen at same time on same host
on timekey, Computer
// Limit to only where the file edit happens after the build process starts
| where BuildProcessTime <= FileEditTime
| summarize make_set(FileEdited), make_set(FileEditProcess), make_set(FileEditAccount) by timekey, Computer, BuildParentProcess, BuildProcess
| extend HostCustomEntity=Computer, timestamp=timekey
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity

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

@ -1,16 +1,18 @@
id: 62085097-d113-459f-9ea7-30216f2ee6af
name: AD user created password not set within 24-48 hours
name: AD user enabled and password not set within 48 hours
description: |
'Identifies whenever a new account is created with a default password and password is not changed within 24-48 hours.
Simple version, can be more precise with Windowing, but not necessary if run as an alert on a daily basis.
Effectively, there is an event 4722 indicating a user enabled and no event 4723 indicating a password was changed within in that day or the next day.'
'Identifies when an account is enabled with a default password and the password is not set by the user within 48 hours.
Effectively, there is an event 4722 indicating an account was enabled and within 48 hours, no event 4723 occurs which
indicates there was no attempt by the user to set the password. This will show any attempts (success or fail) that occur
after 48 hours, which can indicate too long of a time period in setting the password to something that only the user knows.
It is recommended that this time period is adjusted per your internal company policy.'
severity: Low
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
queryFrequency: 1d
queryPeriod: 2d
queryPeriod: 3d
triggerOperator: gt
triggerThreshold: 0
tactics:
@ -19,26 +21,27 @@ relevantTechniques:
- T1098
query: |
let starttime = 2d;
let endtime = 1d;
SecurityEvent
// include yesterday and not today, so we can confirm a match occurs within the next day
| where TimeGenerated >= startofday(ago(starttime)) and TimeGenerated <= startofday(ago(endtime))
let starttime = 3d;
let SecEvents = materialize ( SecurityEvent | where TimeGenerated >= ago(starttime)
| where EventID in (4722,4723) | where TargetUserName !endswith "$"
| project TimeGenerated, EventID, Activity, Computer, TargetAccount, TargetSid, SubjectAccount, SubjectUserSid);
let userEnable = SecEvents
| extend EventID4722Time = TimeGenerated
// 4722: User Account Enabled
| where EventID == 4722
// Removing Machine Accounts
| where TargetUserName !endswith "$"
| join kind= leftanti (
SecurityEvent
//verify over the last 2 days
| where TimeGenerated >= startofday(ago(starttime))
// Attempt made to change password
| where EventID == 4723
// Removing Machine Accounts
| where TargetUserName !endswith "$"
) on TargetAccount
| project StartTime = TimeGenerated, EventID, Computer, TargetAccount, TargetSid, SubjectAccount, SubjectUserSid
| extend timestamp = StartTime, AccountCustomEntity = TargetAccount, HostCustomEntity = Computer
| where EventID == 4722
| project Time_Event4722 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4722 = SubjectAccount, SubjectUserSid_Event4722 = SubjectUserSid, Activity_4722 = Activity, Computer_4722 = Computer;
let userPwdSet = SecEvents
// 4723: Attempt made by user to set password
| where EventID == 4723
| project Time_Event4723 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4723 = SubjectAccount, SubjectUserSid_Event4723 = SubjectUserSid, Activity_4723 = Activity, Computer_4723 = Computer;
userEnable | join kind=leftouter userPwdSet on TargetAccount, TargetSid
| extend PasswordSetAttemptDelta_Min = datetime_diff('minute', Time_Event4723, Time_Event4722)
| where PasswordSetAttemptDelta_Min > 2880 or isempty(PasswordSetAttemptDelta_Min)
| project-away TargetAccount1, TargetSid1
| extend Reason = @"User either has not yet attempted to set the initial password after account was enabled or it occurred after 48 hours"
| order by Time_Event4722 asc
| extend timestamp = Time_Event4722, AccountCustomEntity = TargetAccount, HostCustomEntity = Computer_4722
| project-reorder Time_Event4722, Time_Event4723, PasswordSetAttemptDelta_Min, TargetAccount, TargetSid
entityMappings:
- entityType: Account
fieldMappings:

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

@ -0,0 +1,44 @@
Id: 18B7E4E3-5B57-4924-B3CD-7E9A5A143521
DisplayName: "Account's peers with a recent alert"
Description: "Locates the Account's peers with a recent alert"
InputEntityType: Account
InputFields:
- Name
- UPNSuffix
OutputEntityTypes:
- Account
QueryPeriodBefore: 7d
QueryPeriodAfter: 0d
DataSources:
- UserPeerAnalytics
- SecurityAlert
Tactics:
- LateralMovement
query: |
let GetUserPeersWithAlerts = (v_Account_Name:string, v_Account_UPNSuffix:string, v_Account_AadUserId:string) {
let Account_UPN = strcat(v_Account_Name, '@',v_Account_UPNSuffix);
let Peers= UserPeerAnalytics
| where UserPrincipalName =~ Account_UPN or UserId =~ v_Account_AadUserId
| where TimeGenerated == toscalar (UserPeerAnalytics | summarize max(TimeGenerated))
| project PeerUserPrincipalName, PeerUserId, Rank
| extend PeerUserPrincipalName=tolower(PeerUserPrincipalName)
| parse PeerUserPrincipalName with Account_Name '@' Account_UPNSuffix;
let PeerNames= Peers | summarize make_set_if(Account_Name, isnotempty(Account_Name));
let PeerIds = Peers | summarize make_set_if(PeerUserId , isnotempty(PeerUserId));
let PeersWithSecAlert=SecurityAlert
| where Entities has "account"
| where Entities has_any (PeerNames) or Entities has_any (PeerIds)
| mvexpand todynamic(Entities)
| where tostring(Entities ["Type"]) =="account"
| where tostring(Entities ["Name"]) has_any (PeerNames) or tostring(Entities ["AadUserId"]) has_any (PeerIds)
| summarize Account_Aux_AlertCount = count()
by Account_Name=tolower(tostring(Entities["Name"]))
, Account_UPNSuffix=tolower(tostring(Entities["UPNSuffix"]));
PeersWithSecAlert
| join kind=innerunique
Peers
on Account_Name, Account_UPNSuffix
| project Account_Name, Account_UPNSuffix, Account_Aux_AlertCount
};
GetUserPeersWithAlerts("{{Account_Name}}","{{Account_UPNSuffix}}", "{{Account_AadUserId}}")

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

@ -26,3 +26,12 @@ query: |
| project TimeGenerated, EventName, EventTypeName, UserIdentityAccountId, UserIdentityPrincipalid, UserAgent,
UserIdentityUserName, SessionMfaAuthenticated, SourceIpAddress, AWSRegion, EventSource, AdditionalEventData, ResponseElements
| extend timestamp = TimeGenerated, IPCustomEntity = SourceIpAddress, AccountCustomEntity = UserIdentityAccountId
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -41,4 +41,14 @@ query: |
| where TimeAdded > TimeRemoved // Checking if RoleAdd operation was performed after removal
| summarize TotalCount=count() by TimeAdded, TimeRemoved, RoleAdded, RoleRemoved, UserIdentityUserName, UserIdentityAccountId, UserIdentityPrincipalid, UserAgent,
SourceIpAddress, AWSRegion, EventSource, RoleRemovedCount, RoleAddedCount
| extend timestamp = iff(TimeAdded > TimeRemoved,TimeAdded, TimeRemoved), IPCustomEntity = SourceIpAddress, AccountCustomEntity = UserIdentityUserName
| extend timestamp = iff(TimeAdded > TimeRemoved,TimeAdded, TimeRemoved), IPCustomEntity = SourceIpAddress, AccountCustomEntity = UserIdentityUserName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -34,4 +34,13 @@ query: |
| extend InstanceProfileName = tostring(parse_json(RequestParameters).InstanceProfileName), RoleName = tostring(parse_json(RequestParameters).roleName)
| summarize EventCount=count(), StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventSource, EventName, UserIdentityType , UserIdentityArn , UserIdentityUserName, SourceIpAddress, RoleName
) on RoleName
| extend timestamp = StartTimeUtc, IPCustomEntity = SourceIpAddress, AccountCustomEntity = RoleName
| extend timestamp = StartTimeUtc, IPCustomEntity = SourceIpAddress, AccountCustomEntity = RoleName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -34,4 +34,13 @@ query: |
| project TimeGenerated, EventSource, EventName, UserIdentityType, UserIdentityInvokedBy , SourceIpAddress, RoleArn
) on RoleArn, UserIdentityInvokedBy
| summarize EventCount = count(), StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by RoleArn, EventSource, EventName, UserIdentityType, UserIdentityInvokedBy, SourceIpAddress
| extend timestamp = StartTimeUtc, IPCustomEntity = SourceIpAddress, AccountCustomEntity = tostring(split(RoleArn, "/")[1])
| extend timestamp = StartTimeUtc, IPCustomEntity = SourceIpAddress, AccountCustomEntity = tostring(split(RoleArn, "/")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -37,4 +37,13 @@ query: |
| extend UnusedRegion = AWSRegion
| extend UserIdentityUserName = iff(isnotempty(UserIdentityUserName), UserIdentityUserName, tostring(split(UserIdentityArn,'/')[-1]))
| summarize EventCount = count(), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), EventNameList=make_set(EventName), IPList=make_set(SourceIpAddress) by UserIdentityAccountId, UnusedRegion, UserIdentityUserName
| extend timestamp = StartTime , AccountCustomEntity = UserIdentityUserName
| extend timestamp = StartTime , AccountCustomEntity = UserIdentityUserName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -9,11 +9,7 @@ description: |
AWS S3 API GetObject at https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html
S3 LogStash Config: https://github.com/Azure/Azure-Sentinel/blob/master/Parsers/Logstash/input-aws_s3-output-loganalytics.conf
S3 KQL Parser: https://github.com/Azure/Azure-Sentinel/blob/master/Parsers/AwsS3BucketAPILogsParser.txt'
severity: Medium
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
requiredDataConnectors: []
tactics:
- Exfiltration
relevantTechniques:
@ -46,4 +42,17 @@ query: |
| summarize Total = sum(BytesTransferredOut), Files= makeset(Key) , max(EventTime) by bin(EventTime, 1h), EventSource,EventName, SourceIPAddress, UserIdentityType, UserIdentityArn, UserIdentityUserName, BucketName, Host, AuthenticationMethod, SessionMfaAuthenticated, SessionUserName
) on EventTime
| project AnomalyTime = max_EventTime, SourceIPAddress, UserIdentityType,UserIdentityUserName,SessionUserName, BucketName, Host, AuthenticationMethod, Files, Total, baseline, anomalies, score
| extend timestamp = AnomalyTime, AccountCustomEntity = SessionUserName , HostCustomEntity = Host, IPCustomEntity = SourceIPAddress
| extend timestamp = AnomalyTime, AccountCustomEntity = SessionUserName , HostCustomEntity = Host, IPCustomEntity = SourceIPAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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

@ -8,6 +8,7 @@ description: |
and ListBucket at https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html
S3 LogStash Config: https://github.com/Azure/Azure-Sentinel/blob/master/Parsers/Logstash/input-aws_s3-output-loganalytics.conf
S3 KQL Parser: https://github.com/Azure/Azure-Sentinel/blob/master/Parsers/AwsS3BucketAPILogsParser.txt'
requiredDataConnectors: []
tactics:
- Collection
relevantTechniques:
@ -31,3 +32,16 @@ query: |
| summarize EventCount=count(), StartTimeUtc = min(EventTime), EndTimeUtc = max(EventTime), Files= makeset(Key), EventNames = makeset(EventName) by EventSource, SourceIPAddress, UserIdentityType, UserIdentityArn, UserIdentityUserName, BucketName, Host, AuthenticationMethod, SessionMfaAuthenticated, SessionUserName
| project StartTimeUtc, EndTimeUtc, EventSource, Host, SourceIPAddress, UserIdentityType, BucketName, EventNames, Files, AuthenticationMethod, SessionMfaAuthenticated, SessionUserName, EventCount
| extend timestamp = StartTimeUtc, HostCustomEntity = Host, AccountCustomEntity = SessionUserName, IPCustomEntity = SourceIPAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity

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