1
0
Форкнуть 0

Merge pull request #339 from microsoft/mjmelone-patch-62

Create Hunting in MCAS.csl
This commit is contained in:
tali-ash 2021-05-10 17:50:34 +03:00 коммит произвёл GitHub
Родитель 7ef38096c8 d5a9d097c5
Коммит 95db05467a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 225 добавлений и 0 удалений

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

@ -0,0 +1,225 @@
print Topic = "l33tSpeak: Advanced hunting in Microsoft 365 Defender"
, Presenters = pack_array("Sebastien Molendijk, Michael Melone, Tali Ash")
, Company = "Microsoft"
, Date = todatetime("10 MAY 2021")
///////////////////////
// Working with the dynamic type
// ref:https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/scalar-data-types/dynamic
///////////////////////
// Dynamic is anobject orientedformat for storing structureddata.
// Dynamics are usually converted from JSON strings using eithertodynamic() orparse_json() (same function)
// You can also convert XML into a dynamic by usingparse_xml()
letJsonString= '{"hello": 1337, "world": ["wibble","wobble","wubble"]}';
printtodynamic(JsonString)
// There area number ofways you can interact with elements stored asdynamic() typed objects.
// Interacting with child elements
// -Column.Child
// - Column[“Child”]
letJsonString= '{"hello": 1337, "world": ["wibble","wobble","wubble"]}';
printx=todynamic(JsonString)
|extendhello=x.hello,world=x["world"]
// Interacting with lists \ arrays
// Column[ElementNumber]
letJsonString= '{"hello": 1337, "world": ["wibble","wobble","wubble"]}';
printx=todynamic(JsonString)
|extendhello=x.hello,world=x["world"]
|extendFirstElement=world[0],SecondElement=world[1]
//TheinformationontheactorinitiatingtheactivitiescanbefoundinAccountObjectIdandAccountDisplayNamecolumns.
// Togetthetargetaccount and the activities were performedwecanextractinformationfromRawEventData
CloudAppEvents
|whereActionType=="AddedToGroup"
|take50
| project-reorder AccountObjectId, AccountDisplayName, RawEventData
CloudAppEvents
|whereActionType=="AddedToGroup"
|projectTimestamp,Application,IPAddress,Actor=AccountDisplayName,AddedUser=RawEventData.TargetUserOrGroupName
CloudAppEvents
|whereActionType=="AddedToGroup"
|projectTimestamp,Application,IPAddress,Actor=AccountDisplayName,AddedUser=RawEventData["TargetUserOrGroupName"]
//////////////////////////////
//pack_array()
// ref:https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/packarrayfunction
// Creates a dynamic array
//////////////////////////////
// Lists, sets, and arrays in KQL are stored as dynamics and can be created
// with functionssuch aspack_array()
printpack_array('foo','bar','baz')
// Note that you cannot simply compare dynamic elements in KQL. To do this,
// convert them back to another type using functions such astostring() ortoint()
letJsonDynamic= todynamic('{"hello": 1337, "world": ["wibble","wobble","wubble"]}');
printtostring(JsonDynamic.hello)==tostring(JsonDynamic['hello'])
////////////////////////
//bag_unpack()
// ref:https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/bag-unpackplugin
// Automatically unpacks the first level of a dynamic to a table
////////////////////////
// Another option is to usebag_unpack() to turn JSON data directly into a table.
// Note thatbag_unpack() only processes the firstlevel of JSON. If you have
// multiple nested JSON elements you may needmultiple calls to the function.
letJsonDynamic= todynamic('{"hello": 1337, "world": ["wibble","wobble","wubble"]}');
printx =JsonDynamic
| evaluatebag_unpack(x)
/////////////////////////////
// mv-expand
//ref:https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/mvexpandoperator
// Multiplies elements in a dynamic array across a tabular dataset
/////////////////////////////
//You can alsouse functions such as mv-expand to parse elements in a dynamic
// across a table.This isvery handy for efficiently analyzing lists of
//elementsat scale
//Lets putbag_unpack() and mv-expandtogether.
letJsonDynamic= todynamic('{"hello": 1337, "world": ["wibble","wobble","wubble"]}');
printx=JsonDynamic
|evaluatebag_unpack(x)
|mv-expandworld
//Withmv-expandwecanextracttheGrouptheuserwasaddedto.
//TheeasiestistoextractitfromActivityObjectscolumn
CloudAppEvents
|whereActionType=="AddedToGroup"
|mv-expandActivityObjects
|whereActivityObjects['Type'] == ('Group')
|projectTimestamp,Application,IPAddress,Actor=AccountDisplayName,AddedUser=RawEventData.TargetUserOrGroupName,Group=ActivityObjects.Name
////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////
//startofday()function
//ref:https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/startofdayfunction
// Returns the time at the start of a day, with an optional time offset
//////////////////////////////
//KQLtimefiltersandfunctionsareUTC
//Returnsthestartofthedaycontainingthedate,shiftedbyanoffset of days,ifprovided.
printstartofday(datetime(2021-01-0110:10:17))
IdentityInfo|whereAccountUpn=='meganb@seccxp.ninja'
lettimeToSearch=startofday(datetime('2021-05-04'));
AADSignInEventsBeta
|whereAccountObjectId=='eababd92-9dc7-40e3-9359-6c106522db19'andTimestamp>=timeToSearch
|distinctApplication,ResourceDisplayName,Country,City,IPAddress,DeviceName,DeviceTrustType,OSPlatform,IsManaged,IsCompliant,AuthenticationRequirement,RiskState,UserAgent,ClientAppUsed
//Step1:understandtheperformedactions
letaccountId='eababd92-9dc7-40e3-9359-6c106522db19';
letlocations=pack_array('SG', 'DE', 'IE', 'AL', 'UK');
lettimeToSearch=startofday(datetime('2021-05-04'));
CloudAppEvents
|whereAccountObjectId==accountIdandCountryCodein(locations)andTimestamp>=timeToSearch
|summarizebyActionType,CountryCode,AccountObjectId
|sortbyActionTypeasc
//Step2:reviewtheaccessedemails
letaccountId='eababd92-9dc7-40e3-9359-6c106522db19';
letlocations=pack_array('SG', 'DE', 'IE', 'AL', 'UK');
lettimeToSearch=startofday(datetime('2021-05-04'));
CloudAppEvents
|whereActionType=='MailItemsAccessed'andCountryCodein(locations)andAccountObjectId==accountIdandTimestamp>=timeToSearch
|mv-expandtodynamic(RawEventData.Folders)
|extendPath=todynamic(RawEventData_Folders.Path),SessionId=tostring(RawEventData.SessionId)
|mv-expandtodynamic(RawEventData_Folders.FolderItems)
|projectSessionId,Timestamp,AccountObjectId,DeviceType,CountryCode,City,IPAddress,UserAgent,Path,Message=tostring(RawEventData_Folders_FolderItems.InternetMessageId)
|joinkind=leftouter(
EmailEvents
|whereRecipientObjectId==accountId
|projectSubject,RecipientEmailAddress,SenderMailFromAddress,DeliveryLocation,ThreatTypes,AttachmentCount,UrlCount,InternetMessageId
)
on$left.Message==$right.InternetMessageId
|sortbyTimestampdesc
// BONUS: get message details using Graph:
// https://graph.microsoft.com/v1.0/users/meganb@seccxp.ninja/messages?filter=internetMessageId eq '<b4acafd9-d086-4de0-8deb-c83118dae907@az.centralus.production.microsoft.com>'&select=subject,from,hasAttachments
//Step3:reviewtheaccessedFolderItems
let accountId='eababd92-9dc7-40e3-9359-6c106522db19';
let locations=pack_array('SG', 'DE', 'IE', 'AL', 'UK');
let timeToSearch = startofday(datetime('2021-05-04'));
CloudAppEvents
| where ActionType == 'FilePreviewed' or ActionType == 'FileDownloaded' and CountryCode in(locations) and AccountObjectId == accountId and Timestamp >= timeToSearch
| project Timestamp, CountryCode, IPAddress, ISP, UserAgent, Application, ActivityObjects, AccountObjectId
| mv-expand ActivityObjects
| where ActivityObjects['Type']in('File', 'Folder') and ActivityObjects['Role'] == 'Target object'
| evaluate bag_unpack(ActivityObjects)
//Step4:reviewdeletedemails
letaccountId='eababd92-9dc7-40e3-9359-6c106522db19';
letlocations=pack_array('SG', 'DE', 'IE', 'AL', 'UK');
lettimeToSearch=startofday(datetime('2021-05-04'));
CloudAppEvents
|whereActionTypein~('MoveToDeletedItems','SoftDelete', 'HardDelete')andCountryCodein(locations)andAccountObjectId==accountIdandTimestamp>=timeToSearch
|mv-expandActivityObjects
|whereActivityObjects['Type']in('Email','Folder')
|evaluatebag_unpack(ActivityObjects)
|distinctTimestamp,AccountObjectId,ActionType,CountryCode,IPAddress,Type,Name,Id
|sortbyTimestampdesc
//Step5:reviewthecreatedinboxrules
letaccountId='eababd92-9dc7-40e3-9359-6c106522db19';
letlocations=pack_array('SG', 'DE', 'IE', 'AL', 'UK');
lettimeToSearch=startofday(datetime('2021-05-04'));
CloudAppEvents
|whereActionTypecontains_cs'InboxRule'andCountryCodein(locations)
|extendRuleParameters=RawEventData.Parameters
|projectTimestamp,CountryCode,IPAddress,ISP,ActionType,ObjectName,RuleParameters
|sortbyTimestampdesc
//Step6:identifypotentialothervictims
letaccountId='eababd92-9dc7-40e3-9359-6c106522db19';
letlocations=pack_array('SG', 'DE', 'IE', 'AL', 'UK');
lettimeToSearch=startofday(datetime('2021-05-04'));
letips=(
CloudAppEvents
|whereCountryCodein(locations)
|distinctIPAddress,AccountObjectId
);
ips
|join(CloudAppEvents|projectActivityIP=IPAddress,UserId=AccountObjectId)on$left.IPAddress==$right.ActivityIP
|distinctUserId
|joinIdentityInfoon$left.UserId==$right.AccountObjectId
|distinctAccountDisplayName,AccountUpn,Department,Country,City,AccountObjectId
//Bonus:identifydetailssentbythemaliciousactorIdentityInfo
letaccountId='eababd92-9dc7-40e3-9359-6c106522db19';
lettimeToSearch=startofday(datetime('2021-05-04'));
CloudAppEvents
|whereActionType=~'send'andAccountObjectId==accountId//applytherightfilter
|extendrawData=todynamic(RawEventData)
|extendUserKey=rawData.UserKey,MessageId=tostring(rawData.Item.InternetMessageId),Subject=rawData.Item.Subject,Attachments=rawData.Item.Attachments
|join(
EmailEvents
)
on$left.MessageId==$right.InternetMessageId
|sortbyTimestampdesc
|projectUserKey,Timestamp,AccountObjectId,AccountDisplayName,DeviceType,CountryCode,City,ISP,IPAddress,SenderIPv4,SenderIPv6,UserAgent,Subject,InternetMessageId,Attachments,RecipientEmailAddress,SenderMailFromAddress,DeliveryLocation, ThreatTypes, ConfidenceLevel
,AttachmentCount,UrlCount,MessageId