Merge branch 'master' into Infoblox-CDC-dataconnector
This commit is contained in:
Коммит
fe9d1b4b00
|
@ -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>
|
Двоичный файл не отображается.
Двоичные данные
.script/tests/KqlvalidationsTests/Microsoft.Azure.Sentinel.KustoServices.1.0.9.nupkg
Normal file
Двоичные данные
.script/tests/KqlvalidationsTests/Microsoft.Azure.Sentinel.KustoServices.1.0.9.nupkg
Normal file
Двоичный файл не отображается.
|
@ -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. You’ll 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 don’t 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 pair’s 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 don’t 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, you’ll 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**
|
||||
It’s 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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 57 KiB |
Двоичные данные
DataConnectors/DocuSign-SecurityEvents/images/AppAzSentinelIntegration.png
Normal file
Двоичные данные
DataConnectors/DocuSign-SecurityEvents/images/AppAzSentinelIntegration.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 30 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 31 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче