Advanced hunting for Microsoft Purview Data Loss Prevention - mattnovitsch/M365 GitHub Wiki
Summary
If you are looking to query your Purview data using KQL, good news that data is sent using the Cloud App connector. What I will be covering is the reporting of files with Sensitive Information Types(SIT) being access, printed, and copied to removeable media.
Prerequisites
- Purview Deployed
- Microsoft Defender for Cloud Apps Deployed
Hunting
- This query fill identify all files that have a SIT assigned to them.
Query: let AppEvents = (CloudAppEvents | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "" | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]" | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName) | extend document = tostring(RawEventData.ObjectId) ); AppEvents | extend ObjectId = tostring(RawEventData.ObjectId) | extend DeviceName = tostring(RawEventData.DeviceName) | extend Application = tostring(RawEventData.Application) | summarize count = count() by document,Application,SensitiveInfoTypeName,ActionType,DeviceName
- This query will list all the files that were copied to removable media.
Query:
//Files that were copied to Removable Media with SIT data
let FileswithSITLabel=CloudAppEvents
| where ActionType contains "FileCopiedToRemovableMedia"
| extend RawEventDataObject = parse_json(RawEventData)
| extend SourceFileName = RawEventDataObject.ObjectId
| extend UserName = RawEventDataObject.UserId
| where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != ""
| where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]"
| extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData))
| mv-expand sit
| extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName)
| project Timestamp, ActionType,SourceFileName,SensitiveInfoTypeName;
CloudAppEvents
| where ActionType contains "FileCopiedToRemovableMedia"
| extend RawEventDataObject = parse_json(RawEventData)
| extend SourceFileName = RawEventDataObject.ObjectId
| extend SourceFileName = tostring(SourceFileName)
| extend UserName = RawEventDataObject.UserId
| extend DestinationFilePath = RawEventDataObject.TargetFilePath
| where parse_json(tostring(RawEventData.RemovableMediaDeviceAttributes)) != ""
| where parse_json(tostring(RawEventData.RemovableMediaDeviceAttributes)) != "[]"
| extend RemovableMediaDeviceAttributes = parse_json(tostring(RawEventData.RemovableMediaDeviceAttributes))
| extend RemovableMediaDeviceAttributes = parse_json(RemovableMediaDeviceAttributes)
| extend MediaManufacturer = RemovableMediaDeviceAttributes.Manufacturer
| extend MediaModel = RemovableMediaDeviceAttributes.Model
| extend MediaSerialNumber = RemovableMediaDeviceAttributes.SerialNumber
| join kind=leftouter (FileswithSITLabel
| extend SourceFileName = tostring(SourceFileName)
| project Timestamp, SourceFileName, SensitiveInfoTypeName
) on Timestamp, SourceFileName
| project Timestamp, ActionType,SourceFileName,DestinationFilePath,SensitiveInfoTypeName, MediaManufacturer, MediaModel, MediaSerialNumber,UserName, City, CountryCode, IPAddress
- This query will let you know what files have been printed.
Query:
let FileswithSITLabel=CloudAppEvents
| where ActionType contains "FilePrinted"
| extend RawEventDataObject = parse_json(RawEventData)
| extend SourceFileName = RawEventDataObject.ObjectId
| extend UserName = RawEventDataObject.UserId
| where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != ""
| where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]"
| extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData))
| mv-expand sit
| extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName)
| project Timestamp, ActionType,SourceFileName,SensitiveInfoTypeName;
CloudAppEvents
| where ActionType contains "FilePrinted"
| extend RawEventDataObject = parse_json(RawEventData)
| extend SourceFileName = RawEventDataObject.ObjectId
| extend SourceFileName = tostring(SourceFileName)
| where parse_json(tostring(RawEventData.PolicyMatchInfo)) != ""
| where parse_json(tostring(RawEventData.PolicyMatchInfo)) != "[]"
| extend PolicyMatchInfo = parse_json(tostring(RawEventData.PolicyMatchInfo))
| extend PolicyMatchInfo = parse_json(PolicyMatchInfo)
| extend PolicyName = PolicyMatchInfo.RuleName
| extend UserName = RawEventDataObject.UserId
| extend TargetPrinterName = RawEventData.TargetPrinterName
| join kind=leftouter (FileswithSITLabel
| extend SourceFileName = tostring(SourceFileName)
| project Timestamp, SourceFileName, SensitiveInfoTypeName
) on Timestamp, SourceFileName
| project Timestamp, ActionType,SourceFileName,SensitiveInfoTypeName, PolicyName,TargetPrinterName,UserName, City, CountryCode, IPAddress